summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore72
-rw-r--r--.mailmap2
-rw-r--r--.shippable.yml9
-rw-r--r--.travis.yml176
-rw-r--r--MAINTAINERS150
-rw-r--r--Makefile228
-rw-r--r--Makefile.objs82
-rw-r--r--Makefile.target8
-rw-r--r--VERSION2
-rw-r--r--accel/accel.c25
-rw-r--r--accel/kvm/kvm-all.c4
-rw-r--r--accel/tcg/translate-all.c4
-rw-r--r--accel/tcg/user-exec.c75
-rw-r--r--audio/alsaaudio.c2
-rw-r--r--audio/audio_int.h4
-rw-r--r--backends/hostmem-file.c22
-rw-r--r--backends/hostmem-memfd.c2
-rw-r--r--backends/hostmem-ram.c9
-rw-r--r--backends/hostmem.c53
-rw-r--r--block.c89
-rw-r--r--block/Makefile.objs2
-rw-r--r--block/backup.c43
-rw-r--r--block/bochs.c22
-rw-r--r--block/commit.c23
-rw-r--r--block/crypto.c1
-rw-r--r--block/dirty-bitmap.c69
-rw-r--r--block/dmg-lzfse.c49
-rw-r--r--block/dmg.c88
-rw-r--r--block/dmg.h3
-rw-r--r--block/file-posix.c384
-rw-r--r--block/file-win32.c8
-rw-r--r--block/gluster.c2
-rw-r--r--block/iscsi.c49
-rw-r--r--block/linux-aio.c4
-rw-r--r--block/mirror.c57
-rw-r--r--block/nbd-client.c32
-rw-r--r--block/nvme.c16
-rw-r--r--block/qcow.c2
-rw-r--r--block/qcow2-bitmap.c4
-rw-r--r--block/qcow2-cluster.c72
-rw-r--r--block/qcow2.c174
-rw-r--r--block/qcow2.h3
-rw-r--r--block/replication.c67
-rw-r--r--block/sheepdog.c8
-rw-r--r--block/stream.c20
-rw-r--r--block/trace-events4
-rw-r--r--block/vhdx.h2
-rw-r--r--block/vpc.c2
-rw-r--r--blockdev-nbd.c40
-rw-r--r--blockdev.c124
-rw-r--r--bsd-user/elfload.c2
-rw-r--r--bsd-user/x86_64/target_syscall.h2
-rw-r--r--chardev/char.c11
-rw-r--r--chardev/spice.c10
-rwxr-xr-xconfigure214
-rw-r--r--contrib/elf2dmp/main.c2
-rw-r--r--contrib/elf2dmp/pdb.h2
-rw-r--r--contrib/elf2dmp/pe.h1
-rw-r--r--contrib/elf2dmp/qemu_elf.h1
-rw-r--r--contrib/gitdm/aliases27
-rw-r--r--contrib/gitdm/domain-map21
-rw-r--r--contrib/gitdm/filetypes.txt146
-rw-r--r--contrib/gitdm/group-map-academics14
-rw-r--r--contrib/gitdm/group-map-cadence3
-rw-r--r--contrib/gitdm/group-map-codeweavers1
-rw-r--r--contrib/gitdm/group-map-ibm13
-rw-r--r--contrib/gitdm/group-map-individuals10
-rw-r--r--contrib/gitdm/group-map-redhat7
-rw-r--r--contrib/gitdm/group-map-wavecomp19
-rw-r--r--contrib/ivshmem-client/ivshmem-client.h4
-rw-r--r--contrib/ivshmem-server/ivshmem-server.h5
-rw-r--r--contrib/rdmacm-mux/Makefile.objs3
-rw-r--r--contrib/rdmacm-mux/main.c800
-rw-r--r--contrib/rdmacm-mux/rdmacm-mux.h61
-rw-r--r--contrib/vhost-user-blk/vhost-user-blk.c1
-rw-r--r--contrib/vhost-user-scsi/vhost-user-scsi.c1
-rw-r--r--cpus-common.c2
-rw-r--r--cpus.c3
-rw-r--r--crypto/aes.c28
-rw-r--r--crypto/block-luks.c57
-rw-r--r--crypto/block-qcow.c26
-rw-r--r--crypto/block.c225
-rw-r--r--crypto/blockpriv.h42
-rw-r--r--default-configs/ppc64-softmmu.mak2
-rw-r--r--default-configs/riscv32-softmmu.mak9
-rw-r--r--default-configs/riscv64-softmmu.mak9
-rw-r--r--default-configs/virtio.mak3
-rw-r--r--device_tree.c2
-rw-r--r--disas.c15
-rw-r--r--disas/alpha.c8
-rw-r--r--disas/arm.c2
-rw-r--r--disas/i386.c4
-rw-r--r--disas/m68k.c4
-rw-r--r--disas/microblaze.c1
-rw-r--r--disas/nanomips.cpp2155
-rw-r--r--disas/nanomips.h125
-rw-r--r--disas/ppc.c2
-rw-r--r--docs/cpu-hotplug.rst142
-rw-r--r--docs/devel/build-system.txt2
-rw-r--r--docs/devel/loads-stores.rst35
-rw-r--r--docs/devel/migration.rst9
-rw-r--r--docs/devel/qapi-code-gen.txt21
-rw-r--r--docs/interop/nbd.txt19
-rw-r--r--docs/interop/qmp-spec.txt7
-rw-r--r--docs/pvrdma.txt128
-rw-r--r--docs/specs/ivshmem-spec.txt8
-rw-r--r--docs/specs/tpm.txt104
-rw-r--r--dump.c2
-rw-r--r--exec.c35
-rw-r--r--fpu/softfloat.c865
-rw-r--r--fsdev/qemu-fsdev.c5
-rw-r--r--gdbstub.c664
-rw-r--r--gitdm.config50
-rw-r--r--hmp-commands.hx6
-rw-r--r--hmp.c12
-rw-r--r--hw/9pfs/9p-handle.c710
-rw-r--r--hw/9pfs/9p.c4
-rw-r--r--hw/9pfs/Makefile.objs1
-rw-r--r--hw/9pfs/xen-9p-backend.c22
-rw-r--r--hw/acpi/Makefile.objs1
-rw-r--r--hw/acpi/aml-build.c68
-rw-r--r--hw/acpi/core.c21
-rw-r--r--hw/acpi/memory_hotplug.c10
-rw-r--r--hw/acpi/pcihp.c47
-rw-r--r--hw/acpi/piix4.c40
-rw-r--r--hw/acpi/tpm.c459
-rw-r--r--hw/alpha/typhoon.c59
-rw-r--r--hw/arm/allwinner-a10.c6
-rw-r--r--hw/arm/armv7m.c5
-rw-r--r--hw/arm/boot.c43
-rw-r--r--hw/arm/mps2-tz.c1
-rw-r--r--hw/arm/musicpal.c11
-rw-r--r--hw/arm/nrf51_soc.c117
-rw-r--r--hw/arm/stellaris.c2
-rw-r--r--hw/arm/virt-acpi-build.c41
-rw-r--r--hw/arm/virt.c128
-rw-r--r--hw/arm/xlnx-versal-virt.c9
-rw-r--r--hw/arm/xlnx-zynqmp.c23
-rw-r--r--hw/audio/marvell_88w8618.c1
-rw-r--r--hw/block/Makefile.objs2
-rw-r--r--hw/block/dataplane/Makefile.objs1
-rw-r--r--hw/block/dataplane/xen-block.c827
-rw-r--r--hw/block/dataplane/xen-block.h29
-rw-r--r--hw/block/nvme.h8
-rw-r--r--hw/block/onenand.c16
-rw-r--r--hw/block/tc58128.c3
-rw-r--r--hw/block/trace-events14
-rw-r--r--hw/block/vhost-user-blk.c7
-rw-r--r--hw/block/virtio-blk.c10
-rw-r--r--hw/block/xen-block.c963
-rw-r--r--hw/block/xen_disk.c1011
-rw-r--r--hw/char/grlib_apbuart.c12
-rw-r--r--hw/char/serial.c2
-rw-r--r--hw/char/sh_serial.c18
-rw-r--r--hw/char/stm32f2xx_usart.c3
-rw-r--r--hw/char/virtio-serial-bus.c2
-rw-r--r--hw/char/xen_console.c70
-rw-r--r--hw/core/empty_slot.c9
-rw-r--r--hw/core/loader.c76
-rw-r--r--hw/core/machine.c157
-rw-r--r--hw/core/qdev-properties-system.c4
-rw-r--r--hw/core/qdev-properties.c249
-rw-r--r--hw/core/qdev.c22
-rw-r--r--hw/core/reset.c2
-rw-r--r--hw/core/sysbus.c15
-rw-r--r--hw/core/uboot_image.h1
-rw-r--r--hw/cpu/Makefile.objs2
-rw-r--r--hw/cpu/cluster.c50
-rw-r--r--hw/display/g364fb.c9
-rw-r--r--hw/display/qxl.c2
-rw-r--r--hw/display/ramfb-standalone.c1
-rw-r--r--hw/display/tc6393xb.c6
-rw-r--r--hw/display/vga.c8
-rw-r--r--hw/display/virtio-gpu-3d.c6
-rw-r--r--hw/display/virtio-gpu-pci.c21
-rw-r--r--hw/display/virtio-vga.c8
-rw-r--r--hw/display/xenfb.c25
-rw-r--r--hw/dma/puv3_dma.c10
-rw-r--r--hw/dma/pxa2xx_dma.c4
-rw-r--r--hw/dma/soc_dma.c2
-rw-r--r--hw/gpio/Makefile.objs1
-rw-r--r--hw/gpio/max7310.c2
-rw-r--r--hw/gpio/nrf51_gpio.c300
-rw-r--r--hw/gpio/puv3_gpio.c29
-rw-r--r--hw/gpio/trace-events7
-rw-r--r--hw/i2c/bitbang_i2c.h2
-rw-r--r--hw/i2c/i2c-ddc.c2
-rw-r--r--hw/i386/acpi-build.c81
-rw-r--r--hw/i386/amd_iommu.c2
-rw-r--r--hw/i386/intel_iommu.c72
-rw-r--r--hw/i386/intel_iommu_internal.h3
-rw-r--r--hw/i386/kvm/ioapic.c2
-rw-r--r--hw/i386/multiboot.c6
-rw-r--r--hw/i386/pc.c274
-rw-r--r--hw/i386/pc_piix.c479
-rw-r--r--hw/i386/pc_q35.c110
-rw-r--r--hw/i386/trace-events6
-rw-r--r--hw/i386/x86-iommu.c18
-rw-r--r--hw/i386/xen/xen-hvm.c14
-rw-r--r--hw/i386/xen/xen-mapcache.c4
-rw-r--r--hw/i386/xen/xen_platform.c2
-rw-r--r--hw/ide/core.c94
-rw-r--r--hw/ide/pci.c1
-rw-r--r--hw/ide/piix.c1
-rw-r--r--hw/ide/via.c1
-rw-r--r--hw/input/lm832x.c2
-rw-r--r--hw/input/milkymist-softusb.c16
-rw-r--r--hw/input/pckbd.c2
-rw-r--r--hw/input/pl050.c11
-rw-r--r--hw/input/ps2.c6
-rw-r--r--hw/input/tsc210x.c2
-rw-r--r--hw/intc/Makefile.objs2
-rw-r--r--hw/intc/apic.c9
-rw-r--r--hw/intc/arm_gicv3_cpuif.c21
-rw-r--r--hw/intc/ioapic.c2
-rw-r--r--hw/intc/puv3_intc.c11
-rw-r--r--hw/intc/spapr_xive.c1481
-rw-r--r--hw/intc/xics.c4
-rw-r--r--hw/intc/xics_kvm.c4
-rw-r--r--hw/intc/xics_spapr.c14
-rw-r--r--hw/intc/xive.c1596
-rw-r--r--hw/mem/memory-device.c58
-rw-r--r--hw/microblaze/boot.c2
-rw-r--r--hw/microblaze/petalogix_s3adsp1800_mmu.c4
-rw-r--r--hw/mips/cps.c8
-rw-r--r--hw/mips/gt64xxx_pci.c6
-rw-r--r--hw/mips/mips_r4k.c4
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/edu.c1
-rw-r--r--hw/misc/ivshmem.c210
-rw-r--r--hw/misc/macio/mac_dbdma.c1
-rw-r--r--hw/misc/max111x.c6
-rw-r--r--hw/misc/milkymist-hpdmc.c9
-rw-r--r--hw/misc/milkymist-pfpu.c12
-rw-r--r--hw/misc/mips_itu.c73
-rw-r--r--hw/misc/nrf51_rng.c262
-rw-r--r--hw/misc/omap_l4.c4
-rw-r--r--hw/misc/puv3_pm.c10
-rw-r--r--hw/misc/tmp105.c2
-rw-r--r--hw/misc/tmp421.c2
-rw-r--r--hw/misc/tz-mpc.c4
-rw-r--r--hw/moxie/moxiesim.c1
-rw-r--r--hw/net/ftgmac100.c80
-rw-r--r--hw/net/mipsnet.c16
-rw-r--r--hw/net/ne2000.c44
-rw-r--r--hw/net/rocker/rocker.c2
-rw-r--r--hw/net/virtio-net.c671
-rw-r--r--hw/net/vmxnet3.c122
-rw-r--r--hw/net/vmxnet3_defs.h133
-rw-r--r--hw/net/xen_nic.c14
-rw-r--r--hw/nios2/boot.c2
-rw-r--r--hw/nvram/ds1225y.c12
-rw-r--r--hw/nvram/fw_cfg.c71
-rw-r--r--hw/pci-bridge/dec.c12
-rw-r--r--hw/pci-bridge/gen_pcie_root_port.c4
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c31
-rw-r--r--hw/pci-bridge/pcie_pci_bridge.c32
-rw-r--r--hw/pci-bridge/pcie_root_port.c14
-rw-r--r--hw/pci-host/pam.c2
-rw-r--r--hw/pci/msix.c4
-rw-r--r--hw/pci/pci.c87
-rw-r--r--hw/pci/pci_bridge.c4
-rw-r--r--hw/pci/pci_host.c26
-rw-r--r--hw/pci/pcie.c178
-rw-r--r--hw/pci/pcie_port.c6
-rw-r--r--hw/pci/shpc.c25
-rw-r--r--hw/ppc/e500.c19
-rw-r--r--hw/ppc/mac_newworld.c40
-rw-r--r--hw/ppc/mac_oldworld.c10
-rw-r--r--hw/ppc/pnv.c27
-rw-r--r--hw/ppc/pnv_core.c4
-rw-r--r--hw/ppc/pnv_psi.c7
-rw-r--r--hw/ppc/ppc405_boards.c16
-rw-r--r--hw/ppc/ppc405_uc.c6
-rw-r--r--hw/ppc/ppc440_bamboo.c7
-rw-r--r--hw/ppc/ppc4xx_devs.c3
-rw-r--r--hw/ppc/prep.c4
-rw-r--r--hw/ppc/sam460ex.c4
-rw-r--r--hw/ppc/spapr.c448
-rw-r--r--hw/ppc/spapr_cpu_core.c11
-rw-r--r--hw/ppc/spapr_hcall.c93
-rw-r--r--hw/ppc/spapr_iommu.c4
-rw-r--r--hw/ppc/spapr_irq.c439
-rw-r--r--hw/ppc/spapr_pci.c44
-rw-r--r--hw/ppc/spapr_rtas_ddw.c19
-rw-r--r--hw/ppc/spapr_vio.c2
-rw-r--r--hw/ppc/trace-events3
-rw-r--r--hw/ppc/virtex_ml507.c2
-rw-r--r--hw/rdma/rdma_backend.c559
-rw-r--r--hw/rdma/rdma_backend.h40
-rw-r--r--hw/rdma/rdma_backend_defs.h20
-rw-r--r--hw/rdma/rdma_rm.c127
-rw-r--r--hw/rdma/rdma_rm.h17
-rw-r--r--hw/rdma/rdma_rm_defs.h21
-rw-r--r--hw/rdma/rdma_utils.c1
-rw-r--r--hw/rdma/rdma_utils.h26
-rw-r--r--hw/rdma/vmw/pvrdma.h10
-rw-r--r--hw/rdma/vmw/pvrdma_cmd.c273
-rw-r--r--hw/rdma/vmw/pvrdma_dev_ring.c29
-rw-r--r--hw/rdma/vmw/pvrdma_dev_ring.h1
-rw-r--r--hw/rdma/vmw/pvrdma_main.c80
-rw-r--r--hw/rdma/vmw/pvrdma_qp_ops.c102
-rw-r--r--hw/rdma/vmw/pvrdma_qp_ops.h4
-rw-r--r--hw/riscv/sifive_clint.c8
-rw-r--r--hw/riscv/sifive_e.c5
-rw-r--r--hw/riscv/sifive_plic.c2
-rw-r--r--hw/riscv/sifive_u.c25
-rw-r--r--hw/riscv/sifive_uart.c24
-rw-r--r--hw/riscv/virt.c147
-rw-r--r--hw/s390x/css.c32
-rw-r--r--hw/s390x/s390-pci-bus.c80
-rw-r--r--hw/s390x/s390-pci-bus.h30
-rw-r--r--hw/s390x/s390-pci-inst.c133
-rw-r--r--hw/s390x/s390-pci-inst.h1
-rw-r--r--hw/s390x/s390-virtio-ccw.c156
-rw-r--r--hw/s390x/tod-kvm.c102
-rw-r--r--hw/s390x/virtio-ccw.c42
-rw-r--r--hw/scsi/esp-pci.c10
-rw-r--r--hw/scsi/esp.c33
-rw-r--r--hw/scsi/lsi53c895a.c6
-rw-r--r--hw/scsi/scsi-bus.c2
-rw-r--r--hw/scsi/trace-events1
-rw-r--r--hw/scsi/vhost-scsi.c3
-rw-r--r--hw/scsi/vhost-user-scsi.c3
-rw-r--r--hw/sd/sdhci.c5
-rw-r--r--hw/sh4/r2d.c16
-rw-r--r--hw/smbios/smbios-stub.c2
-rw-r--r--hw/smbios/smbios.c5
-rw-r--r--hw/smbios/smbios_build.h4
-rw-r--r--hw/smbios/smbios_type_38-stub.c2
-rw-r--r--hw/smbios/smbios_type_38.c3
-rw-r--r--hw/sparc/sun4m.c6
-rw-r--r--hw/timer/Makefile.objs1
-rw-r--r--hw/timer/etraxfs_timer.c14
-rw-r--r--hw/timer/grlib_gptimer.c11
-rw-r--r--hw/timer/i8254.c1
-rw-r--r--hw/timer/mc146818rtc.c2
-rw-r--r--hw/timer/nrf51_timer.c393
-rw-r--r--hw/timer/puv3_ost.c13
-rw-r--r--hw/timer/sun4v-rtc.c2
-rw-r--r--hw/timer/trace-events5
-rw-r--r--hw/tpm/Makefile.objs1
-rw-r--r--hw/tpm/tpm_crb.c13
-rw-r--r--hw/tpm/tpm_ppi.c53
-rw-r--r--hw/tpm/tpm_ppi.h46
-rw-r--r--hw/tpm/tpm_tis.c25
-rw-r--r--hw/tpm/trace-events3
-rw-r--r--hw/usb/bus.c6
-rw-r--r--hw/usb/ccid-card-emulated.c6
-rw-r--r--hw/usb/combined-packet.c2
-rw-r--r--hw/usb/dev-audio.c3
-rw-r--r--hw/usb/dev-bluetooth.c2
-rw-r--r--hw/usb/dev-hid.c6
-rw-r--r--hw/usb/dev-hub.c14
-rw-r--r--hw/usb/dev-mtp.c27
-rw-r--r--hw/usb/dev-network.c2
-rw-r--r--hw/usb/hcd-ehci-pci.c53
-rw-r--r--hw/usb/hcd-ehci-sysbus.c17
-rw-r--r--hw/usb/hcd-ehci.c14
-rw-r--r--hw/usb/hcd-ehci.h3
-rw-r--r--hw/usb/hcd-uhci.c8
-rw-r--r--hw/usb/host-libusb.c2
-rw-r--r--hw/usb/tusb6010.c8
-rw-r--r--hw/usb/xen-usb.c43
-rw-r--r--hw/vfio/ap.c10
-rw-r--r--hw/vfio/common.c4
-rw-r--r--hw/vfio/pci.c9
-rw-r--r--hw/virtio/Makefile.objs15
-rw-r--r--hw/virtio/vhost-scsi-pci.c97
-rw-r--r--hw/virtio/vhost-user-blk-pci.c103
-rw-r--r--hw/virtio/vhost-user-scsi-pci.c103
-rw-r--r--hw/virtio/vhost-user.c2
-rw-r--r--hw/virtio/vhost-vsock-pci.c86
-rw-r--r--hw/virtio/virtio-9p-pci.c88
-rw-r--r--hw/virtio/virtio-balloon-pci.c95
-rw-r--r--hw/virtio/virtio-balloon.c2
-rw-r--r--hw/virtio/virtio-blk-pci.c100
-rw-r--r--hw/virtio/virtio-crypto-pci.c21
-rw-r--r--hw/virtio/virtio-input-host-pci.c48
-rw-r--r--hw/virtio/virtio-input-pci.c157
-rw-r--r--hw/virtio/virtio-net-pci.c98
-rw-r--r--hw/virtio/virtio-pci.c852
-rw-r--r--hw/virtio/virtio-pci.h288
-rw-r--r--hw/virtio/virtio-rng-pci.c88
-rw-r--r--hw/virtio/virtio-rng.c2
-rw-r--r--hw/virtio/virtio-scsi-pci.c107
-rw-r--r--hw/virtio/virtio-serial-pci.c115
-rw-r--r--hw/virtio/virtio.c8
-rw-r--r--hw/watchdog/watchdog.c2
-rw-r--r--hw/watchdog/wdt_i6300esb.c1
-rw-r--r--hw/xen/Makefile.objs2
-rw-r--r--hw/xen/trace-events26
-rw-r--r--hw/xen/xen-backend.c165
-rw-r--r--hw/xen/xen-bus-helper.c184
-rw-r--r--hw/xen/xen-bus.c1199
-rw-r--r--hw/xen/xen-common.c31
-rw-r--r--hw/xen/xen-legacy-backend.c (renamed from hw/xen/xen_backend.c)87
-rw-r--r--hw/xen/xen_devconfig.c4
-rw-r--r--hw/xen/xen_pt.c8
-rw-r--r--hw/xen/xen_pt_config_init.c6
-rw-r--r--hw/xen/xen_pt_graphics.c18
-rw-r--r--hw/xen/xen_pt_msi.c2
-rw-r--r--hw/xen/xen_pvdev.c22
-rw-r--r--hw/xenpv/Makefile.objs2
-rw-r--r--hw/xenpv/xen_domainbuild.c299
-rw-r--r--hw/xenpv/xen_domainbuild.h13
-rw-r--r--hw/xenpv/xen_machine_pv.c21
-rw-r--r--include/block/block.h6
-rw-r--r--include/block/block_backup.h13
-rw-r--r--include/block/dirty-bitmap.h7
-rw-r--r--include/block/nbd.h46
-rw-r--r--include/chardev/char.h3
-rw-r--r--include/crypto/block.h2
-rw-r--r--include/elf.h65
-rw-r--r--include/exec/cpu-common.h2
-rw-r--r--include/exec/helper-head.h13
-rw-r--r--include/exec/helper-tcg.h21
-rw-r--r--include/exec/memory.h32
-rw-r--r--include/exec/poison.h1
-rw-r--r--include/exec/tb-hash.h4
-rw-r--r--include/fpu/softfloat.h30
-rw-r--r--include/glib-compat.h56
-rw-r--r--include/hw/acpi/acpi-defs.h30
-rw-r--r--include/hw/acpi/acpi.h14
-rw-r--r--include/hw/acpi/acpi_dev_interface.h6
-rw-r--r--include/hw/acpi/aml-build.h2
-rw-r--r--include/hw/acpi/pcihp.h5
-rw-r--r--include/hw/acpi/tpm.h21
-rw-r--r--include/hw/arm/allwinner-a10.h1
-rw-r--r--include/hw/arm/linux-boot-if.h5
-rw-r--r--include/hw/arm/nrf51.h45
-rw-r--r--include/hw/arm/nrf51_soc.h9
-rw-r--r--include/hw/arm/pxa.h1
-rw-r--r--include/hw/arm/xlnx-versal.h8
-rw-r--r--include/hw/arm/xlnx-zynqmp.h3
-rw-r--r--include/hw/boards.h60
-rw-r--r--include/hw/char/nrf51_uart.h1
-rw-r--r--include/hw/char/serial.h4
-rw-r--r--include/hw/compat.h288
-rw-r--r--include/hw/cpu/cluster.h58
-rw-r--r--include/hw/devices.h1
-rw-r--r--include/hw/elf_ops.h6
-rw-r--r--include/hw/firmware/smbios.h (renamed from include/hw/smbios/smbios.h)0
-rw-r--r--include/hw/fw-path-provider.h4
-rw-r--r--include/hw/gpio/nrf51_gpio.h69
-rw-r--r--include/hw/hotplug.h6
-rw-r--r--include/hw/i2c/i2c.h2
-rw-r--r--include/hw/i2c/ppc4xx_i2c.h3
-rw-r--r--include/hw/i2c/smbus.h2
-rw-r--r--include/hw/i386/intel_iommu.h1
-rw-r--r--include/hw/i386/ioapic.h3
-rw-r--r--include/hw/i386/pc.h727
-rw-r--r--include/hw/i386/x86-iommu.h4
-rw-r--r--include/hw/ide/ahci.h4
-rw-r--r--include/hw/ide/internal.h2
-rw-r--r--include/hw/input/ps2.h2
-rw-r--r--include/hw/intc/intc.h4
-rw-r--r--include/hw/ipmi/ipmi.h4
-rw-r--r--include/hw/isa/isa.h4
-rw-r--r--include/hw/loader.h24
-rw-r--r--include/hw/mem/memory-device.h4
-rw-r--r--include/hw/misc/mips_itu.h8
-rw-r--r--include/hw/misc/nrf51_rng.h83
-rw-r--r--include/hw/nmi.h4
-rw-r--r--include/hw/pci-host/spapr.h9
-rw-r--r--include/hw/pci/pci.h16
-rw-r--r--include/hw/pci/pci_bridge.h6
-rw-r--r--include/hw/pci/pcie.h13
-rw-r--r--include/hw/pci/pcie_port.h4
-rw-r--r--include/hw/pci/pcie_regs.h23
-rw-r--r--include/hw/pci/shpc.h10
-rw-r--r--include/hw/pcmcia.h4
-rw-r--r--include/hw/ppc/openpic.h2
-rw-r--r--include/hw/ppc/pnv.h2
-rw-r--r--include/hw/ppc/pnv_psi.h1
-rw-r--r--include/hw/ppc/spapr.h37
-rw-r--r--include/hw/ppc/spapr_irq.h14
-rw-r--r--include/hw/ppc/spapr_xive.h50
-rw-r--r--include/hw/ppc/xics.h13
-rw-r--r--include/hw/ppc/xics_spapr.h37
-rw-r--r--include/hw/ppc/xive.h424
-rw-r--r--include/hw/ppc/xive_regs.h235
-rw-r--r--include/hw/qdev-core.h30
-rw-r--r--include/hw/qdev-properties.h38
-rw-r--r--include/hw/riscv/sifive_u.h3
-rw-r--r--include/hw/riscv/sifive_uart.h3
-rw-r--r--include/hw/riscv/virt.h15
-rw-r--r--include/hw/s390x/tod.h10
-rw-r--r--include/hw/scsi/esp.h2
-rw-r--r--include/hw/sh4/sh_intc.h20
-rw-r--r--include/hw/smbios/ipmi.h15
-rw-r--r--include/hw/stream.h4
-rw-r--r--include/hw/sysbus.h3
-rw-r--r--include/hw/timer/m48t59.h4
-rw-r--r--include/hw/timer/nrf51_timer.h80
-rw-r--r--include/hw/usb.h4
-rw-r--r--include/hw/vfio/vfio-common.h4
-rw-r--r--include/hw/vfio/vfio-platform.h2
-rw-r--r--include/hw/virtio/virtio-net.h86
-rw-r--r--include/hw/xen/io/ring.h4
-rw-r--r--include/hw/xen/xen-backend.h39
-rw-r--r--include/hw/xen/xen-block.h94
-rw-r--r--include/hw/xen/xen-bus-helper.h45
-rw-r--r--include/hw/xen/xen-bus.h137
-rw-r--r--include/hw/xen/xen-legacy-backend.h (renamed from include/hw/xen/xen_backend.h)43
-rw-r--r--include/hw/xen/xen.h3
-rw-r--r--include/hw/xen/xen_common.h19
-rw-r--r--include/hw/xen/xen_pvdev.h38
-rw-r--r--include/migration/vmstate.h1
-rw-r--r--include/monitor/monitor.h3
-rw-r--r--include/net/eth.h2
-rw-r--r--include/net/net.h2
-rw-r--r--include/qapi/string-input-visitor.h4
-rw-r--r--include/qemu/acl.h14
-rw-r--r--include/qemu/atomic.h5
-rw-r--r--include/qemu/compiler.h27
-rw-r--r--include/qemu/cutils.h8
-rw-r--r--include/qemu/hbitmap.h31
-rw-r--r--include/qemu/host-utils.h4
-rw-r--r--include/qemu/iov.h2
-rw-r--r--include/qemu/module.h3
-rw-r--r--include/qemu/option_int.h2
-rw-r--r--include/qemu/osdep.h17
-rw-r--r--include/qemu/queue.h153
-rw-r--r--include/qemu/range.h68
-rw-r--r--include/qemu/rcu_queue.h45
-rw-r--r--include/qemu/typedefs.h26
-rw-r--r--include/qemu/vfio-helpers.h1
-rw-r--r--include/qemu/xxhash.h (renamed from include/exec/tb-hash-xx.h)47
-rw-r--r--include/qom/cpu.h10
-rw-r--r--include/qom/object.h11
-rw-r--r--include/qom/object_interfaces.h10
-rw-r--r--include/scsi/constants.h2
-rw-r--r--include/scsi/pr-manager.h8
-rw-r--r--include/sysemu/accel.h6
-rw-r--r--include/sysemu/balloon.h2
-rw-r--r--include/sysemu/bt.h4
-rw-r--r--include/sysemu/hostmem.h3
-rw-r--r--include/sysemu/kvm.h2
-rw-r--r--include/sysemu/memory_mapping.h2
-rw-r--r--include/sysemu/numa.h2
-rw-r--r--include/sysemu/rng.h2
-rw-r--r--include/sysemu/sysemu.h26
-rw-r--r--include/sysemu/tpm.h4
-rw-r--r--include/sysemu/whpx.h1
-rw-r--r--include/ui/console.h28
-rw-r--r--include/ui/egl-helpers.h2
-rw-r--r--include/ui/input.h3
-rw-r--r--include/ui/qemu-pixman.h10
-rw-r--r--include/ui/qemu-spice.h6
-rw-r--r--include/ui/sdl2.h3
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/host/riscv32/hostdep.h11
-rw-r--r--linux-user/host/riscv64/hostdep.h34
-rw-r--r--linux-user/host/riscv64/safe-syscall.inc.S77
-rw-r--r--linux-user/linuxload.c14
-rw-r--r--linux-user/main.c4
-rw-r--r--linux-user/mmap.c10
-rw-r--r--linux-user/ppc/signal.c28
-rw-r--r--linux-user/qemu.h10
-rw-r--r--linux-user/signal.c16
-rw-r--r--linux-user/strace.c4
-rw-r--r--linux-user/syscall.c63
-rw-r--r--linux-user/syscall_defs.h4
-rw-r--r--linux-user/uaccess.c2
-rw-r--r--linux-user/vm86.c2
-rw-r--r--linux-user/x86_64/target_syscall.h2
-rw-r--r--memory.c97
-rw-r--r--memory_mapping.c2
-rw-r--r--migration/block-dirty-bitmap.c2
-rw-r--r--migration/block.c4
-rw-r--r--migration/colo.c16
-rw-r--r--migration/global_state.c15
-rw-r--r--migration/migration.c4
-rw-r--r--migration/ram.c2
-rw-r--r--migration/vmstate.c13
-rw-r--r--monitor.c158
-rw-r--r--nbd/client.c816
-rw-r--r--nbd/nbd-internal.h8
-rw-r--r--nbd/server.c156
-rw-r--r--nbd/trace-events18
-rw-r--r--net/checksum.c2
-rw-r--r--net/colo-compare.c17
-rw-r--r--net/colo.c1
-rw-r--r--net/colo.h7
-rw-r--r--net/filter-rewriter.c9
-rw-r--r--net/filter.c2
-rw-r--r--net/net.c2
-rw-r--r--net/queue.c2
-rw-r--r--net/slirp.c63
-rw-r--r--net/util.h55
-rw-r--r--pc-bios/efi-e1000.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-e1000e.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-eepro100.rombin240128 -> 240128 bytes
-rw-r--r--pc-bios/efi-ne2k_pci.rombin238080 -> 238592 bytes
-rw-r--r--pc-bios/efi-pcnet.rombin238080 -> 238592 bytes
-rw-r--r--pc-bios/efi-rtl8139.rombin241664 -> 242688 bytes
-rw-r--r--pc-bios/efi-virtio.rombin242176 -> 242688 bytes
-rw-r--r--pc-bios/efi-vmxnet3.rombin236032 -> 236032 bytes
-rw-r--r--pc-bios/keymaps/common157
-rw-r--r--pc-bios/keymaps/modifiers18
-rw-r--r--pc-bios/keymaps/nl-be3
-rw-r--r--pc-bios/keymaps/sl177
-rw-r--r--pc-bios/keymaps/sv176
-rw-r--r--pc-bios/palcode-clipperbin152680 -> 155968 bytes
-rw-r--r--pc-bios/qemu-icon.bmpbin630 -> 0 bytes
-rw-r--r--pc-bios/s390-ccw/start.S14
-rw-r--r--qapi/block-core.json82
-rw-r--r--qapi/block.json30
-rw-r--r--qapi/char.json150
-rw-r--r--qapi/common.json42
-rw-r--r--qapi/crypto.json6
-rw-r--r--qapi/migration.json15
-rw-r--r--qapi/misc.json87
-rw-r--r--qapi/net.json3
-rw-r--r--qapi/qapi-schema.json1
-rw-r--r--qapi/qobject-input-visitor.c9
-rw-r--r--qapi/rdma.json38
-rw-r--r--qapi/run-state.json44
-rw-r--r--qapi/string-input-visitor.c413
-rw-r--r--qapi/tpm.json5
-rw-r--r--qapi/transaction.json12
-rw-r--r--qapi/ui.json3
-rw-r--r--qemu-deprecated.texi26
-rw-r--r--qemu-doc.texi13
-rw-r--r--qemu-io-cmds.c29
-rw-r--r--qemu-nbd.c270
-rw-r--r--qemu-nbd.texi123
-rw-r--r--qemu-options.hx24
-rw-r--r--qemu-seccomp.c3
-rw-r--r--qga/commands-posix.c9
-rw-r--r--qga/commands-win32.c70
-rw-r--r--qga/qapi-schema.json16
-rw-r--r--qmp.c12
-rw-r--r--qobject/json-parser.c5
-rw-r--r--qom/cpu.c1
-rw-r--r--qom/object.c52
-rw-r--r--qom/object_interfaces.c14
-rw-r--r--qtest.c47
-rw-r--r--roms/Makefile4
m---------roms/ipxe0
m---------roms/qemu-palcode0
-rw-r--r--rules.mak4
-rwxr-xr-xscripts/analyse-locks-simpletrace.py1
-rwxr-xr-xscripts/analyze-migration.py1
-rwxr-xr-xscripts/checkpatch.pl144
-rw-r--r--scripts/cocci-macro-file.h25
-rwxr-xr-xscripts/device-crash-test17
-rwxr-xr-xscripts/fix-multiline-comments.sh62
-rwxr-xr-xscripts/gtester-cat26
-rw-r--r--scripts/qapi/common.py208
-rwxr-xr-xscripts/qapi/doc.py31
-rw-r--r--scripts/qapi/events.py13
-rw-r--r--scripts/qapi/introspect.py17
-rw-r--r--scripts/qapi/types.py10
-rw-r--r--scripts/qapi/visit.py8
-rw-r--r--scripts/qemu.py2
-rwxr-xr-xscripts/replay-dump.py2
-rwxr-xr-xscripts/simpletrace.py1
-rwxr-xr-xscripts/tap-driver.pl378
-rwxr-xr-xscripts/tap-merge.pl110
-rwxr-xr-xscripts/texi2pod.pl2
-rwxr-xr-xscripts/tracetool.py2
-rw-r--r--scripts/tracetool/backend/log.py2
-rw-r--r--scripts/tracetool/format/simpletrace_stap.py2
-rw-r--r--scsi/pr-manager.c21
-rw-r--r--scsi/trace-events2
-rw-r--r--slirp/Makefile.objs37
-rw-r--r--slirp/arp_table.c12
-rw-r--r--slirp/bootp.c10
-rw-r--r--slirp/cksum.c8
-rw-r--r--slirp/debug.h47
-rw-r--r--slirp/dhcpv6.c17
-rw-r--r--slirp/if.c4
-rw-r--r--slirp/ip.h10
-rw-r--r--slirp/ip6.h3
-rw-r--r--slirp/ip6_icmp.c27
-rw-r--r--slirp/ip6_icmp.h6
-rw-r--r--slirp/ip6_input.c2
-rw-r--r--slirp/ip6_output.c4
-rw-r--r--slirp/ip_icmp.c31
-rw-r--r--slirp/ip_input.c202
-rw-r--r--slirp/libslirp.h27
-rw-r--r--slirp/main.h33
-rw-r--r--slirp/mbuf.c2
-rw-r--r--slirp/mbuf.h1
-rw-r--r--slirp/misc.c286
-rw-r--r--slirp/misc.h13
-rw-r--r--slirp/ncsi.c4
-rw-r--r--slirp/ndp_table.c32
-rw-r--r--slirp/sbuf.h1
-rw-r--r--slirp/slirp.c179
-rw-r--r--slirp/slirp.h45
-rw-r--r--slirp/slirp_config.h86
-rw-r--r--slirp/socket.c53
-rw-r--r--slirp/socket.h2
-rw-r--r--slirp/tcp.h4
-rw-r--r--slirp/tcp_input.c92
-rw-r--r--slirp/tcp_output.c6
-rw-r--r--slirp/tcp_subr.c22
-rw-r--r--slirp/tcp_timer.c4
-rw-r--r--slirp/tftp.c7
-rw-r--r--slirp/trace-events5
-rw-r--r--slirp/udp.c7
-rw-r--r--slirp/udp6.c11
-rw-r--r--stubs/slirp.c2
-rw-r--r--stubs/tpm.c5
-rw-r--r--target/alpha/cpu.c6
-rw-r--r--target/alpha/translate.c2
-rw-r--r--target/arm/Makefile.objs1
-rw-r--r--target/arm/cpu-qom.h3
-rw-r--r--target/arm/cpu.c86
-rw-r--r--target/arm/cpu.h485
-rw-r--r--target/arm/cpu64.c103
-rw-r--r--target/arm/helper-a64.c155
-rw-r--r--target/arm/helper-a64.h14
-rw-r--r--target/arm/helper.c1447
-rw-r--r--target/arm/helper.h1
-rw-r--r--target/arm/idau.h4
-rw-r--r--target/arm/internals.h80
-rw-r--r--target/arm/kvm.c2
-rw-r--r--target/arm/kvm64.c4
-rw-r--r--target/arm/machine.c24
-rw-r--r--target/arm/op_helper.c186
-rw-r--r--target/arm/pauth_helper.c497
-rw-r--r--target/arm/sve.decode5
-rw-r--r--target/arm/translate-a64.c571
-rw-r--r--target/arm/translate.c73
-rw-r--r--target/arm/translate.h5
-rw-r--r--target/cris/helper.c2
-rw-r--r--target/cris/mmu.h10
-rw-r--r--target/cris/translate_v10.inc.c2
-rw-r--r--target/i386/Makefile.objs6
-rw-r--r--target/i386/cpu.c76
-rw-r--r--target/i386/cpu.h7
-rw-r--r--target/i386/hax-all.c17
-rw-r--r--target/i386/hax-i386.h6
-rw-r--r--target/i386/hax-mem.c2
-rw-r--r--target/i386/hax-posix.c (renamed from target/i386/hax-darwin.c)0
-rw-r--r--target/i386/hax-posix.h (renamed from target/i386/hax-darwin.h)0
-rw-r--r--target/i386/hvf/x86_decode.c2
-rw-r--r--target/i386/kvm.c95
-rw-r--r--target/i386/sev.c3
-rw-r--r--target/i386/translate.c12
-rw-r--r--target/i386/whp-dispatch.h1
-rw-r--r--target/microblaze/cpu.c14
-rw-r--r--target/microblaze/cpu.h9
-rw-r--r--target/microblaze/op_helper.c22
-rw-r--r--target/mips/cpu.h331
-rw-r--r--target/mips/helper.h6
-rw-r--r--target/mips/internal.h1
-rw-r--r--target/mips/machine.c7
-rw-r--r--target/mips/op_helper.c64
-rw-r--r--target/mips/translate.c2201
-rw-r--r--target/ppc/arch_dump.c15
-rw-r--r--target/ppc/cpu.h66
-rw-r--r--target/ppc/gdbstub.c8
-rw-r--r--target/ppc/int_helper.c86
-rw-r--r--target/ppc/internal.h39
-rw-r--r--target/ppc/kvm.c24
-rw-r--r--target/ppc/machine.c72
-rw-r--r--target/ppc/monitor.c4
-rw-r--r--target/ppc/translate.c133
-rw-r--r--target/ppc/translate/dfp-impl.inc.c2
-rw-r--r--target/ppc/translate/fp-impl.inc.c486
-rw-r--r--target/ppc/translate/vmx-impl.inc.c154
-rw-r--r--target/ppc/translate/vmx-ops.inc.c2
-rw-r--r--target/ppc/translate/vsx-impl.inc.c862
-rw-r--r--target/ppc/translate_init.inc.c32
-rw-r--r--target/riscv/Makefile.objs2
-rw-r--r--target/riscv/cpu.c10
-rw-r--r--target/riscv/cpu.h41
-rw-r--r--target/riscv/cpu_helper.c25
-rw-r--r--target/riscv/csr.c863
-rw-r--r--target/riscv/fpu_helper.c1
-rw-r--r--target/riscv/gdbstub.c10
-rw-r--r--target/riscv/op_helper.c613
-rw-r--r--target/riscv/pmp.c2
-rw-r--r--target/s390x/diag.c2
-rw-r--r--target/sparc/cpu.c1
-rw-r--r--target/tilegx/translate.c2
-rw-r--r--target/tricore/fpu_helper.c9
-rw-r--r--tcg/aarch64/tcg-target.h1
-rw-r--r--tcg/aarch64/tcg-target.inc.c71
-rw-r--r--tcg/arm/tcg-target.h1
-rw-r--r--tcg/arm/tcg-target.inc.c55
-rw-r--r--tcg/i386/tcg-target.h17
-rw-r--r--tcg/i386/tcg-target.inc.c212
-rw-r--r--tcg/mips/tcg-target.h1
-rw-r--r--tcg/mips/tcg-target.inc.c12
-rw-r--r--tcg/optimize.c16
-rw-r--r--tcg/ppc/tcg-target.h1
-rw-r--r--tcg/ppc/tcg-target.inc.c60
-rw-r--r--tcg/riscv/tcg-target.h177
-rw-r--r--tcg/riscv/tcg-target.inc.c1949
-rw-r--r--tcg/s390/tcg-target.h1
-rw-r--r--tcg/s390/tcg-target.inc.c45
-rw-r--r--tcg/sparc/tcg-target.h1
-rw-r--r--tcg/sparc/tcg-target.inc.c58
-rw-r--r--tcg/tcg-op.c221
-rw-r--r--tcg/tcg-op.h1
-rw-r--r--tcg/tcg-opc.h7
-rw-r--r--tcg/tcg.c640
-rw-r--r--tcg/tcg.h45
-rw-r--r--tcg/tci/tcg-target.h2
-rw-r--r--tcg/tci/tcg-target.inc.c3
-rw-r--r--tests/Makefile.include148
-rw-r--r--tests/acceptance/linux_initrd.py48
-rw-r--r--tests/acceptance/virtio_version.py176
-rw-r--r--tests/acpi-utils.c72
-rw-r--r--tests/acpi-utils.h56
-rw-r--r--tests/atomic64-bench.c6
-rw-r--r--tests/atomic_add-bench.c6
-rw-r--r--tests/bios-tables-test.c310
-rw-r--r--tests/boot-order-test.c59
-rw-r--r--tests/boot-serial-test.c33
-rw-r--r--tests/cdrom-test.c2
-rw-r--r--tests/check-qom-interface.c4
-rw-r--r--tests/cpu-plug-test.c4
-rw-r--r--tests/data/acpi/pc/DSDT.dimmpxmbin6790 -> 6784 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.memhpbin6496 -> 6490 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.dimmpxmbin9474 -> 9468 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.memhpbin9180 -> 9174 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.mmio64bin8947 -> 8945 bytes
-rw-r--r--tests/display-vga-test.c10
-rw-r--r--tests/docker/Makefile.include13
-rw-r--r--tests/docker/dockerfiles/centos7.docker1
-rw-r--r--tests/docker/dockerfiles/debian-amd64.docker5
-rw-r--r--tests/docker/dockerfiles/debian-sid.docker11
-rw-r--r--tests/docker/dockerfiles/debian.docker13
-rw-r--r--tests/docker/dockerfiles/fedora-i386-cross.docker2
-rw-r--r--tests/docker/dockerfiles/fedora.docker5
-rw-r--r--tests/docker/dockerfiles/travis.docker4
-rw-r--r--tests/endianness-test.c329
-rw-r--r--tests/fp/.gitignore1
-rw-r--r--tests/fp/Makefile8
-rw-r--r--tests/fp/fp-bench.c630
-rw-r--r--tests/fp/platform.h1
-rw-r--r--tests/hexloader-test.c2
-rw-r--r--tests/ivshmem-test.c90
-rw-r--r--tests/libqos/malloc.c2
-rw-r--r--tests/libqos/pci-pc.c47
-rw-r--r--tests/libqos/pci-spapr.c20
-rw-r--r--tests/libqtest.c91
-rw-r--r--tests/libqtest.h25
-rw-r--r--tests/machine-none-test.c7
-rw-r--r--tests/microbit-test.c255
-rw-r--r--tests/migration-test.c8
-rw-r--r--tests/pnv-xscom-test.c29
-rw-r--r--tests/prom-env-test.c17
-rw-r--r--tests/pvpanic-test.c14
-rw-r--r--tests/pxe-test.c7
-rw-r--r--tests/qapi-schema/alternate-base.err1
-rw-r--r--tests/qapi-schema/alternate-invalid-dict.err1
-rw-r--r--tests/qapi-schema/alternate-invalid-dict.exit (renamed from tests/qapi-schema/enum-dict-member.exit)0
-rw-r--r--tests/qapi-schema/alternate-invalid-dict.json4
-rw-r--r--tests/qapi-schema/alternate-invalid-dict.out (renamed from tests/qapi-schema/enum-dict-member.out)0
-rw-r--r--tests/qapi-schema/comments.out14
-rw-r--r--tests/qapi-schema/doc-bad-section.out13
-rw-r--r--tests/qapi-schema/doc-good.json11
-rw-r--r--tests/qapi-schema/doc-good.out22
-rw-r--r--tests/qapi-schema/doc-good.texi7
-rw-r--r--tests/qapi-schema/double-type.err1
-rw-r--r--tests/qapi-schema/empty.out9
-rw-r--r--tests/qapi-schema/enum-bad-member.err1
-rw-r--r--tests/qapi-schema/enum-bad-member.exit1
-rw-r--r--tests/qapi-schema/enum-bad-member.json2
-rw-r--r--tests/qapi-schema/enum-bad-member.out0
-rw-r--r--tests/qapi-schema/enum-dict-member-unknown.err2
-rw-r--r--tests/qapi-schema/enum-dict-member-unknown.exit1
-rw-r--r--tests/qapi-schema/enum-dict-member-unknown.json2
-rw-r--r--tests/qapi-schema/enum-dict-member-unknown.out0
-rw-r--r--tests/qapi-schema/enum-dict-member.err1
-rw-r--r--tests/qapi-schema/enum-dict-member.json2
-rw-r--r--tests/qapi-schema/enum-if-invalid.err1
-rw-r--r--tests/qapi-schema/enum-if-invalid.exit1
-rw-r--r--tests/qapi-schema/enum-if-invalid.json3
-rw-r--r--tests/qapi-schema/enum-if-invalid.out0
-rw-r--r--tests/qapi-schema/event-case.out9
-rw-r--r--tests/qapi-schema/event-member-invalid-dict.err1
-rw-r--r--tests/qapi-schema/event-member-invalid-dict.exit1
-rw-r--r--tests/qapi-schema/event-member-invalid-dict.json2
-rw-r--r--tests/qapi-schema/event-member-invalid-dict.out0
-rw-r--r--tests/qapi-schema/event-nest-struct.json2
-rw-r--r--tests/qapi-schema/flat-union-inline-invalid-dict.err1
-rw-r--r--tests/qapi-schema/flat-union-inline-invalid-dict.exit1
-rw-r--r--tests/qapi-schema/flat-union-inline-invalid-dict.json11
-rw-r--r--tests/qapi-schema/flat-union-inline-invalid-dict.out0
-rw-r--r--tests/qapi-schema/flat-union-inline.json2
-rw-r--r--tests/qapi-schema/flat-union-invalid-if-discriminator.err1
-rw-r--r--tests/qapi-schema/flat-union-invalid-if-discriminator.exit1
-rw-r--r--tests/qapi-schema/flat-union-invalid-if-discriminator.json17
-rw-r--r--tests/qapi-schema/flat-union-invalid-if-discriminator.out0
-rw-r--r--tests/qapi-schema/ident-with-escape.out9
-rw-r--r--tests/qapi-schema/include-relpath.out14
-rw-r--r--tests/qapi-schema/include-repetition.out14
-rw-r--r--tests/qapi-schema/include-simple.out14
-rw-r--r--tests/qapi-schema/indented-expr.out9
-rw-r--r--tests/qapi-schema/nested-struct-data-invalid-dict.err1
-rw-r--r--tests/qapi-schema/nested-struct-data-invalid-dict.exit1
-rw-r--r--tests/qapi-schema/nested-struct-data-invalid-dict.json3
-rw-r--r--tests/qapi-schema/nested-struct-data-invalid-dict.out0
-rw-r--r--tests/qapi-schema/nested-struct-data.json2
-rw-r--r--tests/qapi-schema/qapi-schema-test.json39
-rw-r--r--tests/qapi-schema/qapi-schema-test.out74
-rw-r--r--tests/qapi-schema/struct-member-invalid-dict.err1
-rw-r--r--tests/qapi-schema/struct-member-invalid-dict.exit1
-rw-r--r--tests/qapi-schema/struct-member-invalid-dict.json3
-rw-r--r--tests/qapi-schema/struct-member-invalid-dict.out0
-rw-r--r--tests/qapi-schema/test-qapi.py9
-rw-r--r--tests/qapi-schema/union-branch-invalid-dict.err1
-rw-r--r--tests/qapi-schema/union-branch-invalid-dict.exit1
-rw-r--r--tests/qapi-schema/union-branch-invalid-dict.json4
-rw-r--r--tests/qapi-schema/union-branch-invalid-dict.out0
-rw-r--r--tests/qapi-schema/unknown-expr-key.err3
-rw-r--r--tests/qapi-schema/unknown-expr-key.json2
-rw-r--r--tests/qemu-iotests/060.out4
-rw-r--r--tests/qemu-iotests/071.out4
-rw-r--r--tests/qemu-iotests/081.out14
-rw-r--r--tests/qemu-iotests/083.out28
-rw-r--r--tests/qemu-iotests/087.out12
-rw-r--r--tests/qemu-iotests/094.out2
-rw-r--r--tests/qemu-iotests/109.out44
-rw-r--r--tests/qemu-iotests/117.out2
-rw-r--r--tests/qemu-iotests/119.out2
-rw-r--r--tests/qemu-iotests/120.out2
-rw-r--r--tests/qemu-iotests/127.out2
-rwxr-xr-xtests/qemu-iotests/13318
-rw-r--r--tests/qemu-iotests/133.out15
-rw-r--r--tests/qemu-iotests/140.out2
-rw-r--r--tests/qemu-iotests/143.out2
-rw-r--r--tests/qemu-iotests/156.out2
-rw-r--r--tests/qemu-iotests/176.out16
-rw-r--r--tests/qemu-iotests/183.out4
-rw-r--r--tests/qemu-iotests/184.out12
-rw-r--r--tests/qemu-iotests/185.out10
-rw-r--r--tests/qemu-iotests/191.out6
-rw-r--r--tests/qemu-iotests/195.out6
-rwxr-xr-xtests/qemu-iotests/2068
-rwxr-xr-xtests/qemu-iotests/22354
-rw-r--r--tests/qemu-iotests/223.out51
-rw-r--r--tests/qemu-iotests/227.out12
-rwxr-xr-xtests/qemu-iotests/2291
-rwxr-xr-xtests/qemu-iotests/23330
-rw-r--r--tests/qemu-iotests/233.out19
-rwxr-xr-xtests/qemu-iotests/2354
-rwxr-xr-xtests/qemu-iotests/236161
-rw-r--r--tests/qemu-iotests/236.out351
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/qemu-iotests/iotests.py64
-rw-r--r--tests/qht-bench.c11
-rw-r--r--tests/qmp-test.c6
-rw-r--r--tests/tcg/alpha/test-cond.c4
-rw-r--r--tests/tcg/arm/hello-arm.c20
-rw-r--r--tests/tcg/cris/check_glibc_kernelversion.c8
-rw-r--r--tests/tcg/cris/check_mmap3.c2
-rw-r--r--tests/tcg/cris/check_openpf1.c2
-rw-r--r--tests/tcg/cris/check_settls1.c2
-rw-r--r--tests/tcg/i386/hello-i386.c14
-rw-r--r--tests/tcg/i386/test-i386.c2
-rw-r--r--tests/tcg/mips/hello-mips.c10
-rw-r--r--tests/tcg/mips/mipsr5900/Makefile2
-rw-r--r--tests/tcg/mips/mipsr5900/madd.c78
-rw-r--r--tests/tcg/mips/mipsr5900/maddu.c70
-rw-r--r--tests/tcg/multiarch/sha1.c12
-rw-r--r--tests/test-arm-mptimer.c153
-rw-r--r--tests/test-crypto-block.c3
-rw-r--r--tests/test-crypto-pbkdf.c3
-rw-r--r--tests/test-cutils.c24
-rw-r--r--tests/test-filter-mirror.c9
-rw-r--r--tests/test-filter-redirector.c16
-rw-r--r--tests/test-hbitmap.c177
-rw-r--r--tests/test-qdev-global-props.c79
-rw-r--r--tests/test-qmp-cmds.c16
-rw-r--r--tests/test-rcu-list.c2
-rw-r--r--tests/test-string-input-visitor.c223
-rw-r--r--tests/test-vmstate.c8
-rw-r--r--tests/tpm-util.h1
-rw-r--r--tests/vhost-user-bridge.c2
-rw-r--r--tests/vhost-user-test.c6
-rw-r--r--tests/vmgenid-test.c101
-rw-r--r--trace/simple.c4
-rw-r--r--ui/cocoa.m3
-rw-r--r--ui/console.c40
-rw-r--r--ui/egl-headless.c10
-rw-r--r--ui/egl-helpers.c4
-rw-r--r--ui/gtk-egl.c3
-rw-r--r--ui/gtk.c18
-rw-r--r--ui/icons/Makefile13
-rw-r--r--ui/icons/qemu.svg (renamed from pc-bios/qemu_logo_no_text.svg)0
-rw-r--r--ui/icons/qemu_128x128.pngbin0 -> 8286 bytes
-rw-r--r--ui/icons/qemu_16x16.pngbin0 -> 765 bytes
-rw-r--r--ui/icons/qemu_24x24.pngbin0 -> 1201 bytes
-rw-r--r--ui/icons/qemu_256x256.pngbin0 -> 17572 bytes
-rw-r--r--ui/icons/qemu_32x32.bmpbin0 -> 4234 bytes
-rw-r--r--ui/icons/qemu_32x32.pngbin0 -> 1696 bytes
-rw-r--r--ui/icons/qemu_48x48.pngbin0 -> 2694 bytes
-rw-r--r--ui/icons/qemu_512x512.pngbin0 -> 38007 bytes
-rw-r--r--ui/icons/qemu_64x64.pngbin0 -> 3807 bytes
-rw-r--r--ui/input.c82
-rw-r--r--ui/keymaps.c7
-rw-r--r--ui/keymaps.h4
-rw-r--r--ui/qemu-pixman.c2
-rw-r--r--ui/qemu.desktop8
-rw-r--r--ui/sdl2.c22
-rw-r--r--ui/spice-core.c9
-rw-r--r--ui/vnc-enc-zywrle-template.c4
-rw-r--r--ui/vnc.c29
-rw-r--r--util/aio-posix.c90
-rw-r--r--util/aio-win32.c67
-rw-r--r--util/bitops.c4
-rw-r--r--util/cutils.c91
-rw-r--r--util/hbitmap.c76
-rw-r--r--util/osdep.c4
-rw-r--r--util/oslib-posix.c8
-rw-r--r--util/qemu-option.c4
-rw-r--r--util/qemu-sockets.c4
-rw-r--r--util/qemu-thread-common.h1
-rw-r--r--util/qemu-thread-posix.c11
-rw-r--r--util/qemu-thread-win32.c4
-rw-r--r--util/qsp.c14
-rw-r--r--util/vfio-helpers.c2
-rw-r--r--vl.c74
1023 files changed, 42180 insertions, 17686 deletions
diff --git a/.gitignore b/.gitignore
index 64efdfd929..0430257313 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,78 +30,14 @@
/qapi-gen-timestamp
/qapi/qapi-builtin-types.[ch]
/qapi/qapi-builtin-visit.[ch]
-/qapi/qapi-commands-block-core.[ch]
-/qapi/qapi-commands-block.[ch]
-/qapi/qapi-commands-char.[ch]
-/qapi/qapi-commands-common.[ch]
-/qapi/qapi-commands-crypto.[ch]
-/qapi/qapi-commands-introspect.[ch]
-/qapi/qapi-commands-job.[ch]
-/qapi/qapi-commands-migration.[ch]
-/qapi/qapi-commands-misc.[ch]
-/qapi/qapi-commands-net.[ch]
-/qapi/qapi-commands-rocker.[ch]
-/qapi/qapi-commands-run-state.[ch]
-/qapi/qapi-commands-sockets.[ch]
-/qapi/qapi-commands-tpm.[ch]
-/qapi/qapi-commands-trace.[ch]
-/qapi/qapi-commands-transaction.[ch]
-/qapi/qapi-commands-ui.[ch]
+/qapi/qapi-commands-*.[ch]
/qapi/qapi-commands.[ch]
-/qapi/qapi-events-block-core.[ch]
-/qapi/qapi-events-block.[ch]
-/qapi/qapi-events-char.[ch]
-/qapi/qapi-events-common.[ch]
-/qapi/qapi-events-crypto.[ch]
-/qapi/qapi-events-introspect.[ch]
-/qapi/qapi-events-job.[ch]
-/qapi/qapi-events-migration.[ch]
-/qapi/qapi-events-misc.[ch]
-/qapi/qapi-events-net.[ch]
-/qapi/qapi-events-rocker.[ch]
-/qapi/qapi-events-run-state.[ch]
-/qapi/qapi-events-sockets.[ch]
-/qapi/qapi-events-tpm.[ch]
-/qapi/qapi-events-trace.[ch]
-/qapi/qapi-events-transaction.[ch]
-/qapi/qapi-events-ui.[ch]
+/qapi/qapi-events-*.[ch]
/qapi/qapi-events.[ch]
/qapi/qapi-introspect.[ch]
-/qapi/qapi-types-block-core.[ch]
-/qapi/qapi-types-block.[ch]
-/qapi/qapi-types-char.[ch]
-/qapi/qapi-types-common.[ch]
-/qapi/qapi-types-crypto.[ch]
-/qapi/qapi-types-introspect.[ch]
-/qapi/qapi-types-job.[ch]
-/qapi/qapi-types-migration.[ch]
-/qapi/qapi-types-misc.[ch]
-/qapi/qapi-types-net.[ch]
-/qapi/qapi-types-rocker.[ch]
-/qapi/qapi-types-run-state.[ch]
-/qapi/qapi-types-sockets.[ch]
-/qapi/qapi-types-tpm.[ch]
-/qapi/qapi-types-trace.[ch]
-/qapi/qapi-types-transaction.[ch]
-/qapi/qapi-types-ui.[ch]
+/qapi/qapi-types-*.[ch]
/qapi/qapi-types.[ch]
-/qapi/qapi-visit-block-core.[ch]
-/qapi/qapi-visit-block.[ch]
-/qapi/qapi-visit-char.[ch]
-/qapi/qapi-visit-common.[ch]
-/qapi/qapi-visit-crypto.[ch]
-/qapi/qapi-visit-introspect.[ch]
-/qapi/qapi-visit-job.[ch]
-/qapi/qapi-visit-migration.[ch]
-/qapi/qapi-visit-misc.[ch]
-/qapi/qapi-visit-net.[ch]
-/qapi/qapi-visit-rocker.[ch]
-/qapi/qapi-visit-run-state.[ch]
-/qapi/qapi-visit-sockets.[ch]
-/qapi/qapi-visit-tpm.[ch]
-/qapi/qapi-visit-trace.[ch]
-/qapi/qapi-visit-transaction.[ch]
-/qapi/qapi-visit-ui.[ch]
+/qapi/qapi-visit-*.[ch]
/qapi/qapi-visit.[ch]
/qapi/qapi-doc.texi
/qemu-doc.html
diff --git a/.mailmap b/.mailmap
index ed8faa5719..b8e08297c9 100644
--- a/.mailmap
+++ b/.mailmap
@@ -34,6 +34,6 @@ Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu
# Also list preferred name forms where people have changed their
-# git author config, or having utf8/latin1 encoding issues.
+# git author config, or had utf8/latin1 encoding issues.
Daniel P. Berrangé <berrange@redhat.com>
Reimar Döffinger <Reimar.Doeffinger@gmx.de>
diff --git a/.shippable.yml b/.shippable.yml
index f74a3de3ff..f2ffef21d1 100644
--- a/.shippable.yml
+++ b/.shippable.yml
@@ -7,10 +7,11 @@ env:
matrix:
- IMAGE=debian-amd64
TARGET_LIST=x86_64-softmmu,x86_64-linux-user
- - IMAGE=debian-win32-cross
- TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu
- - IMAGE=debian-win64-cross
- TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu
+ # currently disabled as the mxe.cc repos are down
+ # - IMAGE=debian-win32-cross
+ # TARGET_LIST=arm-softmmu,i386-softmmu,lm32-softmmu
+ # - IMAGE=debian-win64-cross
+ # TARGET_LIST=aarch64-softmmu,sparc64-softmmu,x86_64-softmmu
- IMAGE=debian-armel-cross
TARGET_LIST=arm-softmmu,arm-linux-user,armeb-linux-user
- IMAGE=debian-armhf-cross
diff --git a/.travis.yml b/.travis.yml
index d472fd650b..87d9fa971c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,13 @@
-# The current Travis default is a container based 14.04 Trust on EC2
+# The current Travis default is a VM based 16.04 Xenial on GCE
# Additional builds with specific requirements for a full VM need to
# be added as additional matrix: entries later on
-sudo: false
-dist: trusty
+dist: xenial
language: c
-python:
- - "2.6"
compiler:
- gcc
cache: ccache
+
+
addons:
apt:
packages:
@@ -35,10 +34,17 @@ addons:
- libssh2-1-dev
- liburcu-dev
- libusb-1.0-0-dev
- - libvte-2.90-dev
+ - libvte-2.91-dev
- sparse
- uuid-dev
- gcovr
+ homebrew:
+ packages:
+ - libffi
+ - gettext
+ - glib
+ - pixman
+
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
# to prevent IRC notifications from forks. This was created using:
@@ -49,88 +55,147 @@ notifications:
- secure: "F7GDRgjuOo5IUyRLqSkmDL7kvdU4UcH3Lm/W2db2JnDHTGCqgEdaYEYKciyCLZ57vOTsTsOgesN8iUT7hNHBd1KWKjZe9KDTZWppWRYVwAwQMzVeSOsbbU4tRoJ6Pp+3qhH1Z0eGYR9ZgKYAoTumDFgSAYRp4IscKS8jkoedOqM="
on_success: change
on_failure: always
+
+
env:
global:
- SRC_DIR="."
- BUILD_DIR="."
- - TEST_CMD="make check"
- - MAKEFLAGS="-j3"
- matrix:
- - CONFIG="--disable-system"
- - CONFIG="--disable-user"
- - CONFIG="--enable-debug --enable-debug-tcg"
- - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb --disable-user"
- - CONFIG="--enable-modules --disable-linux-user"
- - CONFIG="--with-coroutine=ucontext --disable-linux-user"
- - CONFIG="--with-coroutine=sigaltstack --disable-linux-user"
+ - TEST_CMD="make check -j3 V=1"
+
+
git:
# we want to do this ourselves
submodules: false
-before_install:
- - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update ; fi
- - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install libffi gettext glib pixman ; fi
- - git submodule update --init --recursive capstone dtc ui/keycodemapdb
+
+
before_script:
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${CONFIG} || { cat config.log && exit 1; }
script:
- - make ${MAKEFLAGS} && ${TEST_CMD}
+ - make -j3 && ${TEST_CMD}
+
+
matrix:
include:
+ - env:
+ - CONFIG="--disable-system"
+
+
+ - env:
+ - CONFIG="--disable-user"
+
+
+ - env:
+ - CONFIG="--enable-debug --enable-debug-tcg"
+
+
+ - env:
+ - CONFIG="--disable-linux-aio --disable-cap-ng --disable-attr --disable-brlapi --disable-uuid --disable-libusb --disable-user"
+
+
+ - env:
+ - CONFIG="--enable-modules --disable-linux-user"
+
+
+ - env:
+ - CONFIG="--with-coroutine=ucontext --disable-linux-user"
+
+
+ - env:
+ - CONFIG="--with-coroutine=sigaltstack --disable-linux-user"
+
+
# Test out-of-tree builds
- - env: CONFIG="--enable-debug --enable-debug-tcg"
- BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
+ - env:
+ - CONFIG="--enable-debug --enable-debug-tcg"
+ - BUILD_DIR="out-of-tree/build/dir" SRC_DIR="../../.."
+
+
# Test with Clang for compile portability (Travis uses clang-5.0)
- - env: CONFIG="--disable-system"
+ - env:
+ - CONFIG="--disable-system"
compiler: clang
- - env: CONFIG="--disable-user"
+
+
+ - env:
+ - CONFIG="--disable-user"
compiler: clang
+
+
# gprof/gcov are GCC features
- - env: CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
+ - env:
+ - CONFIG="--enable-gprof --enable-gcov --disable-pie --target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
after_success:
- ${SRC_DIR}/scripts/travis/coverage-summary.sh
- compiler: gcc
+
+
# We manually include builds which we disable "make check" for
- - env: CONFIG="--enable-debug --enable-tcg-interpreter"
- TEST_CMD=""
- compiler: gcc
+ - env:
+ - CONFIG="--enable-debug --enable-tcg-interpreter"
+ - TEST_CMD=""
+
+
# We don't need to exercise every backend with every front-end
- - env: CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
- TEST_CMD=""
- compiler: gcc
- - env: CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
- TEST_CMD=""
- compiler: gcc
- - env: CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
- TEST_CMD=""
- compiler: gcc
- - env: CONFIG="--disable-tcg"
- TEST_CMD=""
- compiler: gcc
+ - env:
+ - CONFIG="--enable-trace-backends=log,simple,syslog --disable-system"
+ - TEST_CMD=""
+
+
+ - env:
+ - CONFIG="--enable-trace-backends=ftrace --target-list=x86_64-softmmu"
+ - TEST_CMD=""
+
+
+ - env:
+ - CONFIG="--enable-trace-backends=ust --target-list=x86_64-softmmu"
+ - TEST_CMD=""
+
+
+ - env:
+ - CONFIG="--disable-tcg"
+ - TEST_CMD=""
+
+
# MacOSX builds
- - env: CONFIG="--target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
+ - env:
+ - CONFIG="--target-list=aarch64-softmmu,arm-softmmu,i386-softmmu,mips-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
os: osx
osx_image: xcode9.4
compiler: clang
- - env: CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
+
+
+ - env:
+ - CONFIG="--target-list=i386-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,x86_64-softmmu"
os: osx
osx_image: xcode10
compiler: clang
+
+
# Python builds
- - env: CONFIG="--target-list=x86_64-softmmu"
+ - env:
+ - CONFIG="--target-list=x86_64-softmmu"
+ language: python
python:
- - "3.0"
- - env: CONFIG="--target-list=x86_64-softmmu"
+ - "3.4"
+
+
+ - env:
+ - CONFIG="--target-list=x86_64-softmmu"
+ language: python
python:
- "3.6"
+
+
# Acceptance (Functional) tests
- - env: CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu"
- TEST_CMD="make AVOCADO_SHOW=app check-acceptance"
+ - env:
+ - CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu"
+ - TEST_CMD="make AVOCADO_SHOW=app check-acceptance"
addons:
apt:
packages:
- python3-pip
- - python3.4-venv
+ - python3.5-venv
# Using newer GCC with sanitizers
- addons:
apt:
@@ -164,7 +229,7 @@ matrix:
- libssh2-1-dev
- liburcu-dev
- libusb-1.0-0-dev
- - libvte-2.90-dev
+ - libvte-2.91-dev
- sparse
- uuid-dev
language: generic
@@ -175,11 +240,8 @@ matrix:
- TEST_CMD=""
before_script:
- ./configure ${CONFIG} --extra-cflags="-g3 -O0 -fsanitize=thread -fuse-ld=gold" || { cat config.log && exit 1; }
+
+
- env:
- CONFIG="--disable-system --disable-docs"
- - TEST_CMD="make check-tcg"
- script:
- - make ${MAKEFLAGS} && ${TEST_CMD} ${MAKEFLAGS}
- sudo: required
- dist: trusty
- compiler: gcc
+ - TEST_CMD="make -j3 check-tcg V=1"
diff --git a/MAINTAINERS b/MAINTAINERS
index 63effdc473..af339b86db 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -127,9 +127,11 @@ F: include/sysemu/cpus.h
FPU emulation
M: Aurelien Jarno <aurelien@aurel32.net>
M: Peter Maydell <peter.maydell@linaro.org>
-S: Odd Fixes
+M: Alex Bennée <alex.bennee@linaro.org>
+S: Maintained
F: fpu/
F: include/fpu/
+F: tests/fp/
Alpha
M: Richard Henderson <rth@twiddle.net>
@@ -203,21 +205,24 @@ F: disas/microblaze.c
MIPS
M: Aurelien Jarno <aurelien@aurel32.net>
M: Aleksandar Markovic <amarkovic@wavecomp.com>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: target/mips/
+F: default-configs/*mips*
+F: disas/mips.c
+F: disas/nanomips.cpp
+F: disas/nanomips.h
+F: hw/intc/mips_gic.c
F: hw/mips/
F: hw/misc/mips_*
-F: hw/intc/mips_gic.c
F: hw/timer/mips_gictimer.c
+F: include/hw/intc/mips_gic.h
F: include/hw/mips/
F: include/hw/misc/mips_*
-F: include/hw/intc/mips_gic.h
F: include/hw/timer/mips_gictimer.h
F: tests/tcg/mips/
-F: disas/mips.c
-F: disas/nanomips.h
-F: disas/nanomips.cpp
+K: ^Subject:.*(?i)mips
Moxie
M: Anthony Green <green@moxielogic.com>
@@ -233,7 +238,9 @@ M: Marek Vasut <marex@denx.de>
S: Maintained
F: target/nios2/
F: hw/nios2/
+F: hw/intc/nios2_iic.c
F: disas/nios2.c
+F: default-configs/nios2-softmmu.mak
OpenRISC
M: Stafford Horne <shorne@gmail.com>
@@ -258,11 +265,12 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
M: Sagar Karandikar <sagark@eecs.berkeley.edu>
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
L: qemu-riscv@nongnu.org
-S: Maintained
+S: Supported
F: target/riscv/
F: hw/riscv/
F: include/hw/riscv/
-F: disas/riscv.c
+F: linux-user/host/riscv32/
+F: linux-user/host/riscv64/
S390
M: Richard Henderson <rth@twiddle.net>
@@ -289,6 +297,7 @@ S: Maintained
F: target/sparc/
F: hw/sparc/
F: hw/sparc64/
+F: include/hw/sparc/sparc64.h
F: disas/sparc.c
UniCore32
@@ -355,6 +364,7 @@ F: target/arm/kvm.c
MIPS
M: James Hogan <jhogan@kernel.org>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: target/mips/kvm.c
@@ -365,8 +375,9 @@ S: Maintained
F: target/ppc/kvm.c
S390
-M: Christian Borntraeger <borntraeger@de.ibm.com>
+M: Halil Pasic <pasic@linux.ibm.com>
M: Cornelia Huck <cohuck@redhat.com>
+M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Maintained
F: target/s390x/kvm.c
F: target/s390x/kvm_s390x.h
@@ -396,6 +407,7 @@ Guest CPU Cores (Xen):
X86
M: Stefano Stabellini <sstabellini@kernel.org>
M: Anthony Perard <anthony.perard@citrix.com>
+M: Paul Durrant <paul.durrant@citrix.com>
L: xen-devel@lists.xenproject.org
S: Supported
F: */xen*
@@ -403,10 +415,12 @@ F: hw/9pfs/xen-9p-backend.c
F: hw/char/xen_console.c
F: hw/display/xenfb.c
F: hw/net/xen_nic.c
-F: hw/block/xen_*
+F: hw/block/xen*
+F: hw/block/dataplane/xen*
F: hw/xen/
F: hw/xenpv/
F: hw/i386/xen/
+F: include/hw/block/dataplane/xen*
F: include/hw/xen/
F: include/sysemu/xen-mapcache.h
@@ -504,6 +518,7 @@ F: hw/intc/arm*
F: hw/intc/gic_internal.h
F: hw/misc/a9scu.c
F: hw/misc/arm11scu.c
+F: hw/misc/arm_l2x0.c
F: hw/timer/a9gtimer*
F: hw/timer/arm*
F: include/hw/arm/arm*.h
@@ -538,6 +553,7 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: include/hw/arm/digic.h
F: hw/*/digic*
+F: include/hw/*/digic*
Gumstix
M: Peter Maydell <peter.maydell@linaro.org>
@@ -575,6 +591,7 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/integratorcp.c
F: hw/misc/arm_integrator_debug.c
+F: include/hw/misc/arm_integrator_debug.h
MCIMX6UL EVK / i.MX6ul
M: Peter Maydell <peter.maydell@linaro.org>
@@ -594,7 +611,9 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/mcimx7d-sabre.c
F: hw/arm/fsl-imx7.c
+F: hw/misc/imx7_*.c
F: include/hw/arm/fsl-imx7.h
+F: include/hw/misc/imx7_*.h
F: hw/pci-host/designware.c
F: include/hw/pci-host/designware.h
@@ -608,6 +627,8 @@ F: hw/misc/mps2-*.c
F: include/hw/misc/mps2-*.h
F: hw/arm/iotkit.c
F: include/hw/arm/iotkit.h
+F: hw/misc/iotkit-secctl.c
+F: include/hw/misc/iotkit-secctl.h
F: hw/misc/iotkit-sysctl.c
F: include/hw/misc/iotkit-sysctl.h
F: hw/misc/iotkit-sysinfo.c
@@ -626,6 +647,10 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/nseries.c
+F: hw/input/lm832x.c
+F: hw/input/tsc2005.c
+F: hw/misc/cbus.c
+F: hw/timer/twl92230.c
Palm
M: Andrzej Zaborowski <balrogg@gmail.com>
@@ -633,6 +658,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/palm.c
+F: hw/input/tsc210x.c
Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org>
@@ -669,6 +695,7 @@ F: hw/display/tc6393xb.c
F: hw/gpio/max7310.c
F: hw/gpio/zaurus.c
F: hw/misc/mst_fpga.c
+F: hw/misc/max111x.c
F: include/hw/arm/pxa.h
F: include/hw/arm/sharpsl.h
@@ -679,10 +706,10 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/sabrelite.c
F: hw/arm/fsl-imx6.c
-F: hw/misc/imx6_src.c
+F: hw/misc/imx6_*.c
F: hw/ssi/imx_spi.c
F: include/hw/arm/fsl-imx6.h
-F: include/hw/misc/imx6_src.h
+F: include/hw/misc/imx6_*.h
F: include/hw/ssi/imx_spi.h
Sharp SL-5500 (Collie) PDA
@@ -738,6 +765,9 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/xlnx*.c
F: include/hw/*/xlnx*.h
+F: include/hw/ssi/xilinx_spips.h
+F: hw/display/dpcd.c
+F: include/hw/display/dpcd.h
ARM ACPI Subsystem
M: Shannon Zhao <shannon.zhaosl@gmail.com>
@@ -790,7 +820,9 @@ R: Joel Stanley <joel@jms.id.au>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/*/*aspeed*
+F: hw/misc/pca9552.c
F: include/hw/*/*aspeed*
+F: include/hw/misc/pca9552*.h
F: hw/net/ftgmac100.c
F: include/hw/net/ftgmac100.h
@@ -846,6 +878,7 @@ petalogix_s3adsp1800
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
+F: include/hw/char/xilinx_uartlite.h
petalogix_ml605
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@@ -856,18 +889,23 @@ MIPS Machines
-------------
Jazz
M: Hervé Poussineau <hpoussin@reactos.org>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: hw/mips/mips_jazz.c
+F: hw/display/jazz_led.c
+F: hw/dma/rc4030.c
Malta
M: Aurelien Jarno <aurelien@aurel32.net>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: hw/mips/mips_malta.c
Mipssim
M: Aleksandar Markovic <amarkovic@wavecomp.com>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Odd Fixes
F: hw/mips/mips_mipssim.c
@@ -875,26 +913,30 @@ F: hw/net/mipsnet.c
R4000
M: Aurelien Jarno <aurelien@aurel32.net>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: hw/mips/mips_r4k.c
Fulong 2E
M: Aleksandar Markovic <amarkovic@wavecomp.com>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Odd Fixes
F: hw/mips/mips_fulong2e.c
F: hw/isa/vt82c686.c
-
+F: hw/pci-host/bonito.c
F: include/hw/isa/vt82c686.h
Boston
M: Paul Burton <pburton@wavecomp.com>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: hw/core/loader-fit.c
F: hw/mips/boston.c
F: hw/pci-host/xilinx-pcie.c
+F: include/hw/pci-host/xilinx-pcie.h
OpenRISC Machines
-----------------
@@ -923,6 +965,7 @@ L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/e500.[hc]
F: hw/ppc/e500plat.c
+F: hw/gpio/mpc8xxx.c
F: include/hw/ppc/ppc_e500.h
F: include/hw/pci-host/ppce500.h
F: pc-bios/u-boot.e500
@@ -934,7 +977,7 @@ S: Odd Fixes
F: hw/ppc/mpc8544ds.c
F: hw/ppc/mpc8544_guts.c
-New World
+New World (mac99)
M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org
S: Odd Fixes
@@ -944,11 +987,15 @@ F: hw/pci-bridge/dec.[hc]
F: hw/misc/macio/
F: hw/misc/mos6522.c
F: hw/nvram/mac_nvram.c
+F: hw/input/adb*
F: include/hw/misc/macio/
F: include/hw/misc/mos6522.h
F: include/hw/ppc/mac_dbdma.h
+F: include/hw/pci-host/uninorth.h
+F: include/hw/input/adb*
+F: pc-bios/qemu_vga.ndrv
-Old World
+Old World (g3beige)
M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org
S: Odd Fixes
@@ -956,6 +1003,10 @@ F: hw/ppc/mac_oldworld.c
F: hw/pci-host/grackle.c
F: hw/misc/macio/
F: hw/intc/heathrow_pic.c
+F: hw/input/adb*
+F: include/hw/intc/heathrow_pic.h
+F: include/hw/input/adb*
+F: pc-bios/qemu_vga.ndrv
PReP
M: Hervé Poussineau <hpoussin@reactos.org>
@@ -993,6 +1044,14 @@ F: tests/libqos/*spapr*
F: tests/rtas*
F: tests/libqos/rtas*
+XIVE
+M: David Gibson <david@gibson.dropbear.id.au>
+M: Cédric Le Goater <clg@kaod.org>
+L: qemu-ppc@nongnu.org
+S: Supported
+F: hw/*/*xive*
+F: include/hw/*/*xive*
+
virtex_ml507
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org
@@ -1003,8 +1062,14 @@ sam460ex
M: BALATON Zoltan <balaton@eik.bme.hu>
L: qemu-ppc@nongnu.org
S: Maintained
+F: hw/ppc/sam460ex.c
+F: hw/ppc/ppc440_pcix.c
+F: hw/display/sm501*
F: hw/ide/sii3112.c
F: hw/timer/m41t80.c
+F: pc-bios/canyonlands.dt[sb]
+F: pc-bios/u-boot-sam460ex-20100605.bin
+F: roms/u-boot-sam460ex
SH4 Machines
------------
@@ -1032,12 +1097,15 @@ F: hw/misc/eccmemctl.c
F: hw/misc/slavio_misc.c
F: include/hw/sparc/sparc32_dma.h
F: pc-bios/openbios-sparc32
+F: include/hw/sparc/sun4m_iommu.h
Sun4u
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained
F: hw/sparc64/sun4u.c
F: pc-bios/openbios-sparc64
+F: hw/pci-host/sabre.c
+F: include/hw/pci-host/sabre.h
Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com>
@@ -1057,6 +1125,7 @@ S390 Machines
-------------
S390 Virtio-ccw
M: Cornelia Huck <cohuck@redhat.com>
+M: Halil Pasic <pasic@linux.ibm.com>
M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Supported
F: hw/char/sclp*.[hc]
@@ -1136,11 +1205,13 @@ F: hw/timer/hpet*
F: hw/timer/i8254*
F: hw/timer/mc146818rtc*
F: hw/watchdog/wdt_ib700.c
+F: hw/watchdog/wdt_i6300esb.c
F: include/hw/display/vga.h
F: include/hw/char/parallel.h
F: include/hw/dma/i8257.h
F: include/hw/i2c/pm_smbus.h
F: include/hw/input/i8042.h
+F: include/hw/isa/i8259_internal.h
F: include/hw/isa/superio.h
F: include/hw/timer/hpet.h
F: include/hw/timer/i8254*
@@ -1152,7 +1223,9 @@ M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Supported
F: hw/core/machine.c
F: hw/core/null-machine.c
+F: hw/cpu/cluster.c
F: include/hw/boards.h
+F: include/hw/cpu/cluster.h
T: git https://github.com/ehabkost/qemu.git machine-next
Xtensa Machines
@@ -1238,7 +1311,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
M: Igor Mammedov <imammedo@redhat.com>
S: Supported
F: include/hw/acpi/*
-F: include/hw/smbios/*
+F: include/hw/firmware/smbios.h
F: hw/mem/*
F: hw/acpi/*
F: hw/smbios/*
@@ -1246,8 +1319,7 @@ F: hw/i386/acpi-build.[hc]
F: hw/arm/virt-acpi-build.c
F: tests/bios-tables-test.c
F: tests/acpi-utils.[hc]
-F: tests/acpi-test-data/*
-F: tests/acpi-test-data/*/*
+F: tests/data/acpi/
ppc4xx
M: David Gibson <david@gibson.dropbear.id.au>
@@ -1282,7 +1354,7 @@ T: git https://github.com/jasowang/qemu.git net
SCSI
M: Paolo Bonzini <pbonzini@redhat.com>
-R: Fam Zheng <famz@redhat.com>
+R: Fam Zheng <fam@euphon.net>
S: Supported
F: include/hw/scsi/*
F: hw/scsi/*
@@ -1366,6 +1438,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
F: hw/*/*vhost*
F: docs/interop/vhost-user.txt
+F: contrib/vhost-user-*/
virtio
M: Michael S. Tsirkin <mst@redhat.com>
@@ -1478,6 +1551,7 @@ S: Maintained
F: hw/acpi/nvdimm.c
F: hw/mem/nvdimm.c
F: include/hw/mem/nvdimm.h
+F: docs/nvdimm.txt
e1000x
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
@@ -1608,7 +1682,7 @@ T: git https://repo.or.cz/qemu/kevin.git block
Block I/O path
M: Stefan Hajnoczi <stefanha@redhat.com>
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
L: qemu-block@nongnu.org
S: Supported
F: util/async.c
@@ -1622,7 +1696,7 @@ T: git https://github.com/stefanha/qemu.git block
Block SCSI subsystem
M: Paolo Bonzini <pbonzini@redhat.com>
-R: Fam Zheng <famz@redhat.com>
+R: Fam Zheng <fam@euphon.net>
L: qemu-block@nongnu.org
S: Supported
F: include/scsi/*
@@ -1654,7 +1728,7 @@ F: qapi/transaction.json
T: git https://repo.or.cz/qemu/armbru.git block-next
Dirty Bitmaps
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
M: John Snow <jsnow@redhat.com>
L: qemu-block@nongnu.org
S: Supported
@@ -1752,6 +1826,7 @@ F: ui/spice-*.c
F: audio/spiceaudio.c
F: hw/display/qxl*
F: qapi/ui.json
+F: docs/spice-port-fqdn.txt
Graphics
M: Gerd Hoffmann <kraxel@redhat.com>
@@ -1896,6 +1971,7 @@ S: Supported
F: qmp.c
F: monitor.c
F: docs/devel/*qmp-*
+F: docs/interop/*qmp-*
F: scripts/qmp/
F: tests/qmp-test.c
F: tests/qmp-cmd-test.c
@@ -2028,7 +2104,7 @@ F: tests/test-throttle.c
L: qemu-block@nongnu.org
UUID
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
S: Supported
F: util/uuid.c
F: include/qemu/uuid.h
@@ -2126,6 +2202,7 @@ F: disas/i386.c
MIPS target
M: Aurelien Jarno <aurelien@aurel32.net>
+R: Aleksandar Rikalo <arikalo@wavecomp.com>
R: Stefan Markovic <smarkovic@wavecomp.com>
S: Maintained
F: tcg/mips/
@@ -2137,6 +2214,15 @@ S: Odd Fixes
F: tcg/ppc/
F: disas/ppc.c
+RISC-V
+M: Michael Clark <mjc@sifive.com>
+M: Palmer Dabbelt <palmer@sifive.com>
+M: Alistair Francis <Alistair.Francis@wdc.com>
+L: qemu-riscv@nongnu.org
+S: Maintained
+F: tcg/riscv/
+F: disas/riscv.c
+
S390 target
M: Richard Henderson <rth@twiddle.net>
S: Maintained
@@ -2159,7 +2245,7 @@ F: disas/tci.c
Block drivers
-------------
VMDK
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
L: qemu-block@nongnu.org
S: Supported
F: block/vmdk.c
@@ -2245,13 +2331,13 @@ F: block/gluster.c
T: git https://github.com/codyprime/qemu-kvm-jtc.git block
Null Block Driver
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
L: qemu-block@nongnu.org
S: Supported
F: block/null.c
NVMe Block Driver
-M: Fam Zheng <famz@redhat.com>
+M: Fam Zheng <fam@euphon.net>
L: qemu-block@nongnu.org
S: Supported
F: block/nvme*
@@ -2377,13 +2463,15 @@ S: Maintained
F: hw/rdma/*
F: hw/rdma/vmw/*
F: docs/pvrdma.txt
+F: contrib/rdmacm-mux/*
+F: qapi/rdma.json
Build and test automation
-------------------------
Build and test automation
M: Alex Bennée <alex.bennee@linaro.org>
-M: Fam Zheng <famz@redhat.com>
-R: Philippe Mathieu-Daudé <f4bug@amsat.org>
+M: Fam Zheng <fam@euphon.net>
+R: Philippe Mathieu-Daudé <philmd@redhat.com>
L: qemu-devel@nongnu.org
S: Maintained
F: .travis.yml
@@ -2409,6 +2497,12 @@ M: Daniel P. Berrange <berrange@redhat.com>
S: Odd Fixes
F: docs/devel/build-system.txt
+GIT Data Mining Config
+M: Alex Bennée <alex.bennee@linaro.org>
+S: Odd Fixes
+F: gitdm.config
+F: contrib/gitdm/*
+
Incompatible changes
R: libvir-list@redhat.com
F: qemu-deprecated.texi
diff --git a/Makefile b/Makefile
index f2947186a4..de898eab62 100644
--- a/Makefile
+++ b/Makefile
@@ -67,7 +67,7 @@ CONFIG_ALL=y
-include config-all-devices.mak
-include config-all-disas.mak
-config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios
+config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo $@ is out-of-date, running configure
@# TODO: The next lines include code which supports a smooth
@# transition from old configurations without config.status.
@@ -88,82 +88,26 @@ endif
include $(SRC_PATH)/rules.mak
GENERATED_FILES = qemu-version.h config-host.h qemu-options.def
-GENERATED_FILES += qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
-GENERATED_FILES += qapi/qapi-types.h qapi/qapi-types.c
-GENERATED_FILES += qapi/qapi-types-block-core.h qapi/qapi-types-block-core.c
-GENERATED_FILES += qapi/qapi-types-block.h qapi/qapi-types-block.c
-GENERATED_FILES += qapi/qapi-types-char.h qapi/qapi-types-char.c
-GENERATED_FILES += qapi/qapi-types-common.h qapi/qapi-types-common.c
-GENERATED_FILES += qapi/qapi-types-crypto.h qapi/qapi-types-crypto.c
-GENERATED_FILES += qapi/qapi-types-introspect.h qapi/qapi-types-introspect.c
-GENERATED_FILES += qapi/qapi-types-job.h qapi/qapi-types-job.c
-GENERATED_FILES += qapi/qapi-types-migration.h qapi/qapi-types-migration.c
-GENERATED_FILES += qapi/qapi-types-misc.h qapi/qapi-types-misc.c
-GENERATED_FILES += qapi/qapi-types-net.h qapi/qapi-types-net.c
-GENERATED_FILES += qapi/qapi-types-rocker.h qapi/qapi-types-rocker.c
-GENERATED_FILES += qapi/qapi-types-run-state.h qapi/qapi-types-run-state.c
-GENERATED_FILES += qapi/qapi-types-sockets.h qapi/qapi-types-sockets.c
-GENERATED_FILES += qapi/qapi-types-tpm.h qapi/qapi-types-tpm.c
-GENERATED_FILES += qapi/qapi-types-trace.h qapi/qapi-types-trace.c
-GENERATED_FILES += qapi/qapi-types-transaction.h qapi/qapi-types-transaction.c
-GENERATED_FILES += qapi/qapi-types-ui.h qapi/qapi-types-ui.c
-GENERATED_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
-GENERATED_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
-GENERATED_FILES += qapi/qapi-visit-block-core.h qapi/qapi-visit-block-core.c
-GENERATED_FILES += qapi/qapi-visit-block.h qapi/qapi-visit-block.c
-GENERATED_FILES += qapi/qapi-visit-char.h qapi/qapi-visit-char.c
-GENERATED_FILES += qapi/qapi-visit-common.h qapi/qapi-visit-common.c
-GENERATED_FILES += qapi/qapi-visit-crypto.h qapi/qapi-visit-crypto.c
-GENERATED_FILES += qapi/qapi-visit-introspect.h qapi/qapi-visit-introspect.c
-GENERATED_FILES += qapi/qapi-visit-job.h qapi/qapi-visit-job.c
-GENERATED_FILES += qapi/qapi-visit-migration.h qapi/qapi-visit-migration.c
-GENERATED_FILES += qapi/qapi-visit-misc.h qapi/qapi-visit-misc.c
-GENERATED_FILES += qapi/qapi-visit-net.h qapi/qapi-visit-net.c
-GENERATED_FILES += qapi/qapi-visit-rocker.h qapi/qapi-visit-rocker.c
-GENERATED_FILES += qapi/qapi-visit-run-state.h qapi/qapi-visit-run-state.c
-GENERATED_FILES += qapi/qapi-visit-sockets.h qapi/qapi-visit-sockets.c
-GENERATED_FILES += qapi/qapi-visit-tpm.h qapi/qapi-visit-tpm.c
-GENERATED_FILES += qapi/qapi-visit-trace.h qapi/qapi-visit-trace.c
-GENERATED_FILES += qapi/qapi-visit-transaction.h qapi/qapi-visit-transaction.c
-GENERATED_FILES += qapi/qapi-visit-ui.h qapi/qapi-visit-ui.c
-GENERATED_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
-GENERATED_FILES += qapi/qapi-commands-block-core.h qapi/qapi-commands-block-core.c
-GENERATED_FILES += qapi/qapi-commands-block.h qapi/qapi-commands-block.c
-GENERATED_FILES += qapi/qapi-commands-char.h qapi/qapi-commands-char.c
-GENERATED_FILES += qapi/qapi-commands-common.h qapi/qapi-commands-common.c
-GENERATED_FILES += qapi/qapi-commands-crypto.h qapi/qapi-commands-crypto.c
-GENERATED_FILES += qapi/qapi-commands-introspect.h qapi/qapi-commands-introspect.c
-GENERATED_FILES += qapi/qapi-commands-job.h qapi/qapi-commands-job.c
-GENERATED_FILES += qapi/qapi-commands-migration.h qapi/qapi-commands-migration.c
-GENERATED_FILES += qapi/qapi-commands-misc.h qapi/qapi-commands-misc.c
-GENERATED_FILES += qapi/qapi-commands-net.h qapi/qapi-commands-net.c
-GENERATED_FILES += qapi/qapi-commands-rocker.h qapi/qapi-commands-rocker.c
-GENERATED_FILES += qapi/qapi-commands-run-state.h qapi/qapi-commands-run-state.c
-GENERATED_FILES += qapi/qapi-commands-sockets.h qapi/qapi-commands-sockets.c
-GENERATED_FILES += qapi/qapi-commands-tpm.h qapi/qapi-commands-tpm.c
-GENERATED_FILES += qapi/qapi-commands-trace.h qapi/qapi-commands-trace.c
-GENERATED_FILES += qapi/qapi-commands-transaction.h qapi/qapi-commands-transaction.c
-GENERATED_FILES += qapi/qapi-commands-ui.h qapi/qapi-commands-ui.c
-GENERATED_FILES += qapi/qapi-events.h qapi/qapi-events.c
-GENERATED_FILES += qapi/qapi-events-block-core.h qapi/qapi-events-block-core.c
-GENERATED_FILES += qapi/qapi-events-block.h qapi/qapi-events-block.c
-GENERATED_FILES += qapi/qapi-events-char.h qapi/qapi-events-char.c
-GENERATED_FILES += qapi/qapi-events-common.h qapi/qapi-events-common.c
-GENERATED_FILES += qapi/qapi-events-crypto.h qapi/qapi-events-crypto.c
-GENERATED_FILES += qapi/qapi-events-introspect.h qapi/qapi-events-introspect.c
-GENERATED_FILES += qapi/qapi-events-job.h qapi/qapi-events-job.c
-GENERATED_FILES += qapi/qapi-events-migration.h qapi/qapi-events-migration.c
-GENERATED_FILES += qapi/qapi-events-misc.h qapi/qapi-events-misc.c
-GENERATED_FILES += qapi/qapi-events-net.h qapi/qapi-events-net.c
-GENERATED_FILES += qapi/qapi-events-rocker.h qapi/qapi-events-rocker.c
-GENERATED_FILES += qapi/qapi-events-run-state.h qapi/qapi-events-run-state.c
-GENERATED_FILES += qapi/qapi-events-sockets.h qapi/qapi-events-sockets.c
-GENERATED_FILES += qapi/qapi-events-tpm.h qapi/qapi-events-tpm.c
-GENERATED_FILES += qapi/qapi-events-trace.h qapi/qapi-events-trace.c
-GENERATED_FILES += qapi/qapi-events-transaction.h qapi/qapi-events-transaction.c
-GENERATED_FILES += qapi/qapi-events-ui.h qapi/qapi-events-ui.c
-GENERATED_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
-GENERATED_FILES += qapi/qapi-doc.texi
+
+#see Makefile.objs for the definition of QAPI_MODULES
+GENERATED_QAPI_FILES = qapi/qapi-builtin-types.h qapi/qapi-builtin-types.c
+GENERATED_QAPI_FILES += qapi/qapi-types.h qapi/qapi-types.c
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-types-%.h)
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-types-%.c)
+GENERATED_QAPI_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
+GENERATED_QAPI_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.h)
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-visit-%.c)
+GENERATED_QAPI_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.h)
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-commands-%.c)
+GENERATED_QAPI_FILES += qapi/qapi-events.h qapi/qapi-events.c
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.h)
+GENERATED_QAPI_FILES += $(QAPI_MODULES:%=qapi/qapi-events-%.c)
+GENERATED_QAPI_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
+GENERATED_QAPI_FILES += qapi/qapi-doc.texi
+
+GENERATED_FILES += $(GENERATED_QAPI_FILES)
GENERATED_FILES += trace/generated-tcg-tracers.h
@@ -418,6 +362,7 @@ dummy := $(call unnest-vars,, \
elf2dmp-obj-y \
ivshmem-client-obj-y \
ivshmem-server-obj-y \
+ rdmacm-mux-obj-y \
libvhost-user-obj-y \
vhost-user-scsi-obj-y \
vhost-user-blk-obj-y \
@@ -434,7 +379,8 @@ dummy := $(call unnest-vars,, \
ui-obj-m \
audio-obj-y \
audio-obj-m \
- trace-obj-y)
+ trace-obj-y \
+ slirp-obj-y)
include $(SRC_PATH)/tests/Makefile.include
@@ -507,7 +453,7 @@ CAP_CFLAGS += -DCAPSTONE_HAS_X86
subdir-capstone: .git-submodule-status
$(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE))
-$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \
+$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) $(slirp-obj-y) \
$(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY))
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
@@ -583,100 +529,10 @@ qga/qapi-generated/qapi-gen-timestamp: $(SRC_PATH)/qga/qapi-schema.json $(qapi-p
"GEN","$(@:%-timestamp=%)")
@>$@
-qapi-modules = $(SRC_PATH)/qapi/qapi-schema.json $(SRC_PATH)/qapi/common.json \
- $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
- $(SRC_PATH)/qapi/char.json \
- $(SRC_PATH)/qapi/crypto.json \
- $(SRC_PATH)/qapi/introspect.json \
- $(SRC_PATH)/qapi/job.json \
- $(SRC_PATH)/qapi/migration.json \
- $(SRC_PATH)/qapi/misc.json \
- $(SRC_PATH)/qapi/net.json \
- $(SRC_PATH)/qapi/rocker.json \
- $(SRC_PATH)/qapi/run-state.json \
- $(SRC_PATH)/qapi/sockets.json \
- $(SRC_PATH)/qapi/tpm.json \
- $(SRC_PATH)/qapi/trace.json \
- $(SRC_PATH)/qapi/transaction.json \
- $(SRC_PATH)/qapi/ui.json
-
-qapi/qapi-builtin-types.c qapi/qapi-builtin-types.h \
-qapi/qapi-types.c qapi/qapi-types.h \
-qapi/qapi-types-block-core.c qapi/qapi-types-block-core.h \
-qapi/qapi-types-block.c qapi/qapi-types-block.h \
-qapi/qapi-types-char.c qapi/qapi-types-char.h \
-qapi/qapi-types-common.c qapi/qapi-types-common.h \
-qapi/qapi-types-crypto.c qapi/qapi-types-crypto.h \
-qapi/qapi-types-introspect.c qapi/qapi-types-introspect.h \
-qapi/qapi-types-job.c qapi/qapi-types-job.h \
-qapi/qapi-types-migration.c qapi/qapi-types-migration.h \
-qapi/qapi-types-misc.c qapi/qapi-types-misc.h \
-qapi/qapi-types-net.c qapi/qapi-types-net.h \
-qapi/qapi-types-rocker.c qapi/qapi-types-rocker.h \
-qapi/qapi-types-run-state.c qapi/qapi-types-run-state.h \
-qapi/qapi-types-sockets.c qapi/qapi-types-sockets.h \
-qapi/qapi-types-tpm.c qapi/qapi-types-tpm.h \
-qapi/qapi-types-trace.c qapi/qapi-types-trace.h \
-qapi/qapi-types-transaction.c qapi/qapi-types-transaction.h \
-qapi/qapi-types-ui.c qapi/qapi-types-ui.h \
-qapi/qapi-builtin-visit.c qapi/qapi-builtin-visit.h \
-qapi/qapi-visit.c qapi/qapi-visit.h \
-qapi/qapi-visit-block-core.c qapi/qapi-visit-block-core.h \
-qapi/qapi-visit-block.c qapi/qapi-visit-block.h \
-qapi/qapi-visit-char.c qapi/qapi-visit-char.h \
-qapi/qapi-visit-common.c qapi/qapi-visit-common.h \
-qapi/qapi-visit-crypto.c qapi/qapi-visit-crypto.h \
-qapi/qapi-visit-introspect.c qapi/qapi-visit-introspect.h \
-qapi/qapi-visit-job.c qapi/qapi-visit-job.h \
-qapi/qapi-visit-migration.c qapi/qapi-visit-migration.h \
-qapi/qapi-visit-misc.c qapi/qapi-visit-misc.h \
-qapi/qapi-visit-net.c qapi/qapi-visit-net.h \
-qapi/qapi-visit-rocker.c qapi/qapi-visit-rocker.h \
-qapi/qapi-visit-run-state.c qapi/qapi-visit-run-state.h \
-qapi/qapi-visit-sockets.c qapi/qapi-visit-sockets.h \
-qapi/qapi-visit-tpm.c qapi/qapi-visit-tpm.h \
-qapi/qapi-visit-trace.c qapi/qapi-visit-trace.h \
-qapi/qapi-visit-transaction.c qapi/qapi-visit-transaction.h \
-qapi/qapi-visit-ui.c qapi/qapi-visit-ui.h \
-qapi/qapi-commands.h qapi/qapi-commands.c \
-qapi/qapi-commands-block-core.c qapi/qapi-commands-block-core.h \
-qapi/qapi-commands-block.c qapi/qapi-commands-block.h \
-qapi/qapi-commands-char.c qapi/qapi-commands-char.h \
-qapi/qapi-commands-common.c qapi/qapi-commands-common.h \
-qapi/qapi-commands-crypto.c qapi/qapi-commands-crypto.h \
-qapi/qapi-commands-introspect.c qapi/qapi-commands-introspect.h \
-qapi/qapi-commands-job.c qapi/qapi-commands-job.h \
-qapi/qapi-commands-migration.c qapi/qapi-commands-migration.h \
-qapi/qapi-commands-misc.c qapi/qapi-commands-misc.h \
-qapi/qapi-commands-net.c qapi/qapi-commands-net.h \
-qapi/qapi-commands-rocker.c qapi/qapi-commands-rocker.h \
-qapi/qapi-commands-run-state.c qapi/qapi-commands-run-state.h \
-qapi/qapi-commands-sockets.c qapi/qapi-commands-sockets.h \
-qapi/qapi-commands-tpm.c qapi/qapi-commands-tpm.h \
-qapi/qapi-commands-trace.c qapi/qapi-commands-trace.h \
-qapi/qapi-commands-transaction.c qapi/qapi-commands-transaction.h \
-qapi/qapi-commands-ui.c qapi/qapi-commands-ui.h \
-qapi/qapi-events.c qapi/qapi-events.h \
-qapi/qapi-events-block-core.c qapi/qapi-events-block-core.h \
-qapi/qapi-events-block.c qapi/qapi-events-block.h \
-qapi/qapi-events-char.c qapi/qapi-events-char.h \
-qapi/qapi-events-common.c qapi/qapi-events-common.h \
-qapi/qapi-events-crypto.c qapi/qapi-events-crypto.h \
-qapi/qapi-events-introspect.c qapi/qapi-events-introspect.h \
-qapi/qapi-events-job.c qapi/qapi-events-job.h \
-qapi/qapi-events-migration.c qapi/qapi-events-migration.h \
-qapi/qapi-events-misc.c qapi/qapi-events-misc.h \
-qapi/qapi-events-net.c qapi/qapi-events-net.h \
-qapi/qapi-events-rocker.c qapi/qapi-events-rocker.h \
-qapi/qapi-events-run-state.c qapi/qapi-events-run-state.h \
-qapi/qapi-events-sockets.c qapi/qapi-events-sockets.h \
-qapi/qapi-events-tpm.c qapi/qapi-events-tpm.h \
-qapi/qapi-events-trace.c qapi/qapi-events-trace.h \
-qapi/qapi-events-transaction.c qapi/qapi-events-transaction.h \
-qapi/qapi-events-ui.c qapi/qapi-events-ui.h \
-qapi/qapi-introspect.h qapi/qapi-introspect.c \
-qapi/qapi-doc.texi: \
-qapi-gen-timestamp ;
+qapi-modules = $(SRC_PATH)/qapi/qapi-schema.json \
+ $(QAPI_MODULES:%=$(SRC_PATH)/qapi/%.json)
+
+$(GENERATED_QAPI_FILES): qapi-gen-timestamp ;
qapi-gen-timestamp: $(qapi-modules) $(qapi-py)
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-gen.py \
-o "qapi" -b $<, \
@@ -726,6 +582,10 @@ vhost-user-scsi$(EXESUF): $(vhost-user-scsi-obj-y) libvhost-user.a
vhost-user-blk$(EXESUF): $(vhost-user-blk-obj-y) libvhost-user.a
$(call LINK, $^)
+rdmacm-mux$(EXESUF): LIBS += "-libumad"
+rdmacm-mux$(EXESUF): $(rdmacm-mux-obj-y) $(COMMON_LDADDS)
+ $(call LINK, $^)
+
module_block.h: $(SRC_PATH)/scripts/modules/module_block.py config-host.mak
$(call quiet-command,$(PYTHON) $< $@ \
$(addprefix $(SRC_PATH)/,$(patsubst %.mo,%.c,$(block-obj-m))), \
@@ -794,9 +654,9 @@ distclean: clean
rm -Rf .sdk
if test -f dtc/version_gen.h; then $(MAKE) $(DTC_MAKE_ARGS) clean; fi
-KEYMAPS=da en-gb et fr fr-ch is lt modifiers no pt-br sv \
+KEYMAPS=da en-gb et fr fr-ch is lt no pt-br sv \
ar de en-us fi fr-be hr it lv nl pl ru th \
-common de-ch es fo fr-ca hu ja mk nl-be pt sl tr \
+de-ch es fo fr-ca hu ja mk pt sl tr \
bepo cz
ifdef INSTALL_BLOBS
@@ -809,7 +669,6 @@ pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
efi-e1000.rom efi-eepro100.rom efi-ne2k_pci.rom \
efi-pcnet.rom efi-rtl8139.rom efi-virtio.rom \
efi-e1000e.rom efi-vmxnet3.rom \
-qemu-icon.bmp qemu_logo_no_text.svg \
bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin \
s390-ccw.img s390-netboot.img \
@@ -862,6 +721,7 @@ ifneq (,$(findstring qemu-ga,$(TOOLS)))
endif
endif
+ICON_SIZES=16x16 24x24 32x32 48x48 64x64 128x128 256x256 512x512
install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir
ifneq ($(TOOLS),)
@@ -883,6 +743,20 @@ ifneq ($(BLOBS),)
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
+ for s in $(ICON_SIZES); do \
+ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \
+ "$(DESTDIR)/$(qemu_icondir)/hicolor/$${s}/apps/qemu.png"; \
+ done; \
+ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_32x32.bmp \
+ "$(DESTDIR)/$(qemu_icondir)/hicolor/32x32/apps/qemu.bmp"; \
+ mkdir -p "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu.svg \
+ "$(DESTDIR)/$(qemu_icondir)/hicolor/scalable/apps/qemu.svg"
+ mkdir -p "$(DESTDIR)/$(qemu_desktopdir)"
+ $(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \
+ "$(DESTDIR)/$(qemu_desktopdir)/qemu.desktop"
ifdef CONFIG_GTK
$(MAKE) -C po $@
endif
@@ -1000,6 +874,8 @@ docs/interop/qemu-qmp-ref.dvi docs/interop/qemu-qmp-ref.html \
docs/interop/qemu-qmp-ref.txt docs/interop/qemu-qmp-ref.7: \
docs/interop/qemu-qmp-ref.texi docs/interop/qemu-qmp-qapi.texi
+$(filter %.1 %.7 %.8,$(DOCS)): scripts/texi2pod.pl
+
# Reports/Analysis
%/coverage-report.html:
diff --git a/Makefile.objs b/Makefile.objs
index 1e1ff387d7..67a054b08a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,66 +1,23 @@
+QAPI_MODULES = block-core block char common crypto introspect job migration
+QAPI_MODULES += misc net rdma rocker run-state sockets tpm trace transaction
+QAPI_MODULES += ui
+
#######################################################################
# Common libraries for tools and emulators
stub-obj-y = stubs/ crypto/
util-obj-y = util/ qobject/ qapi/
util-obj-y += qapi/qapi-builtin-types.o
util-obj-y += qapi/qapi-types.o
-util-obj-y += qapi/qapi-types-block-core.o
-util-obj-y += qapi/qapi-types-block.o
-util-obj-y += qapi/qapi-types-char.o
-util-obj-y += qapi/qapi-types-common.o
-util-obj-y += qapi/qapi-types-crypto.o
-util-obj-y += qapi/qapi-types-introspect.o
-util-obj-y += qapi/qapi-types-job.o
-util-obj-y += qapi/qapi-types-migration.o
-util-obj-y += qapi/qapi-types-misc.o
-util-obj-y += qapi/qapi-types-net.o
-util-obj-y += qapi/qapi-types-rocker.o
-util-obj-y += qapi/qapi-types-run-state.o
-util-obj-y += qapi/qapi-types-sockets.o
-util-obj-y += qapi/qapi-types-tpm.o
-util-obj-y += qapi/qapi-types-trace.o
-util-obj-y += qapi/qapi-types-transaction.o
-util-obj-y += qapi/qapi-types-ui.o
+util-obj-y += $(QAPI_MODULES:%=qapi/qapi-types-%.o)
util-obj-y += qapi/qapi-builtin-visit.o
util-obj-y += qapi/qapi-visit.o
-util-obj-y += qapi/qapi-visit-block-core.o
-util-obj-y += qapi/qapi-visit-block.o
-util-obj-y += qapi/qapi-visit-char.o
-util-obj-y += qapi/qapi-visit-common.o
-util-obj-y += qapi/qapi-visit-crypto.o
-util-obj-y += qapi/qapi-visit-introspect.o
-util-obj-y += qapi/qapi-visit-job.o
-util-obj-y += qapi/qapi-visit-migration.o
-util-obj-y += qapi/qapi-visit-misc.o
-util-obj-y += qapi/qapi-visit-net.o
-util-obj-y += qapi/qapi-visit-rocker.o
-util-obj-y += qapi/qapi-visit-run-state.o
-util-obj-y += qapi/qapi-visit-sockets.o
-util-obj-y += qapi/qapi-visit-tpm.o
-util-obj-y += qapi/qapi-visit-trace.o
-util-obj-y += qapi/qapi-visit-transaction.o
-util-obj-y += qapi/qapi-visit-ui.o
+util-obj-y += $(QAPI_MODULES:%=qapi/qapi-visit-%.o)
util-obj-y += qapi/qapi-events.o
-util-obj-y += qapi/qapi-events-block-core.o
-util-obj-y += qapi/qapi-events-block.o
-util-obj-y += qapi/qapi-events-char.o
-util-obj-y += qapi/qapi-events-common.o
-util-obj-y += qapi/qapi-events-crypto.o
-util-obj-y += qapi/qapi-events-introspect.o
-util-obj-y += qapi/qapi-events-job.o
-util-obj-y += qapi/qapi-events-migration.o
-util-obj-y += qapi/qapi-events-misc.o
-util-obj-y += qapi/qapi-events-net.o
-util-obj-y += qapi/qapi-events-rocker.o
-util-obj-y += qapi/qapi-events-run-state.o
-util-obj-y += qapi/qapi-events-sockets.o
-util-obj-y += qapi/qapi-events-tpm.o
-util-obj-y += qapi/qapi-events-trace.o
-util-obj-y += qapi/qapi-events-transaction.o
-util-obj-y += qapi/qapi-events-ui.o
+util-obj-y += $(QAPI_MODULES:%=qapi/qapi-events-%.o)
util-obj-y += qapi/qapi-introspect.o
chardev-obj-y = chardev/
+slirp-obj-$(CONFIG_SLIRP) = slirp/
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
@@ -123,8 +80,6 @@ common-obj-y += vl.o
vl.o-cflags := $(GPROF_CFLAGS) $(SDL_CFLAGS)
common-obj-$(CONFIG_TPM) += tpm.o
-common-obj-$(CONFIG_SLIRP) += slirp/
-
common-obj-y += backends/
common-obj-y += chardev/
@@ -138,23 +93,7 @@ common-obj-$(CONFIG_FDT) += device_tree.o
# qapi
common-obj-y += qapi/qapi-commands.o
-common-obj-y += qapi/qapi-commands-block-core.o
-common-obj-y += qapi/qapi-commands-block.o
-common-obj-y += qapi/qapi-commands-char.o
-common-obj-y += qapi/qapi-commands-common.o
-common-obj-y += qapi/qapi-commands-crypto.o
-common-obj-y += qapi/qapi-commands-introspect.o
-common-obj-y += qapi/qapi-commands-job.o
-common-obj-y += qapi/qapi-commands-migration.o
-common-obj-y += qapi/qapi-commands-misc.o
-common-obj-y += qapi/qapi-commands-net.o
-common-obj-y += qapi/qapi-commands-rocker.o
-common-obj-y += qapi/qapi-commands-run-state.o
-common-obj-y += qapi/qapi-commands-sockets.o
-common-obj-y += qapi/qapi-commands-tpm.o
-common-obj-y += qapi/qapi-commands-trace.o
-common-obj-y += qapi/qapi-commands-transaction.o
-common-obj-y += qapi/qapi-commands-ui.o
+common-obj-y += $(QAPI_MODULES:%=qapi/qapi-commands-%.o)
common-obj-y += qapi/qapi-introspect.o
common-obj-y += qmp.o hmp.o
endif
@@ -194,6 +133,7 @@ vhost-user-scsi.o-cflags := $(LIBISCSI_CFLAGS)
vhost-user-scsi.o-libs := $(LIBISCSI_LIBS)
vhost-user-scsi-obj-y = contrib/vhost-user-scsi/
vhost-user-blk-obj-y = contrib/vhost-user-blk/
+rdmacm-mux-obj-y = contrib/rdmacm-mux/
######################################################################
trace-events-subdirs =
@@ -243,6 +183,7 @@ trace-events-subdirs += hw/vfio
trace-events-subdirs += hw/virtio
trace-events-subdirs += hw/watchdog
trace-events-subdirs += hw/xen
+trace-events-subdirs += hw/gpio
trace-events-subdirs += io
trace-events-subdirs += linux-user
trace-events-subdirs += migration
@@ -251,6 +192,7 @@ trace-events-subdirs += net
trace-events-subdirs += qapi
trace-events-subdirs += qom
trace-events-subdirs += scsi
+trace-events-subdirs += slirp
trace-events-subdirs += target/arm
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
diff --git a/Makefile.target b/Makefile.target
index 4d56298bbf..39f72e81be 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -158,9 +158,6 @@ GENERATED_FILES += hmp-commands.h hmp-commands-info.h
endif # CONFIG_SOFTMMU
-# Workaround for http://gcc.gnu.org/PR55489, see configure.
-%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
-
dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y)
@@ -168,6 +165,7 @@ target-obj-y :=
block-obj-y :=
common-obj-y :=
chardev-obj-y :=
+slirp-obj-y :=
include $(SRC_PATH)/Makefile.objs
dummy := $(call unnest-vars,,target-obj-y)
target-obj-y-save := $(target-obj-y)
@@ -180,7 +178,8 @@ dummy := $(call unnest-vars,.., \
qom-obj-y \
io-obj-y \
common-obj-y \
- common-obj-m)
+ common-obj-m \
+ slirp-obj-y)
target-obj-y := $(target-obj-y-save)
all-obj-y += $(common-obj-y)
all-obj-y += $(target-obj-y)
@@ -189,6 +188,7 @@ all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y)
all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
+all-obj-$(CONFIG_SOFTMMU) += $(slirp-obj-y)
$(QEMU_PROG_BUILD): config-devices.mak
diff --git a/VERSION b/VERSION
index fd2a01863f..0bc4611411 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.1.0
+3.1.50
diff --git a/accel/accel.c b/accel/accel.c
index 966b2d8f53..68b6d56323 100644
--- a/accel/accel.c
+++ b/accel/accel.c
@@ -34,6 +34,7 @@
#include "qom/object.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
+#include "qapi/error.h"
static const TypeInfo accel_type = {
.name = TYPE_ACCEL,
@@ -68,7 +69,7 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms)
return ret;
}
-void configure_accelerator(MachineState *ms)
+void configure_accelerator(MachineState *ms, const char *progname)
{
const char *accel;
char **accel_list, **tmp;
@@ -79,8 +80,20 @@ void configure_accelerator(MachineState *ms)
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (accel == NULL) {
- /* Use the default "accelerator", tcg */
- accel = "tcg";
+ /* Select the default accelerator */
+ int pnlen = strlen(progname);
+ if (pnlen >= 3 && g_str_equal(&progname[pnlen - 3], "kvm")) {
+ /* If the program name ends with "kvm", we prefer KVM */
+ accel = "kvm:tcg";
+ } else {
+#if defined(CONFIG_TCG)
+ accel = "tcg";
+#elif defined(CONFIG_KVM)
+ accel = "kvm";
+#else
+#error "No default accelerator available"
+#endif
+ }
}
accel_list = g_strsplit(accel, ":", 0);
@@ -118,12 +131,6 @@ void configure_accelerator(MachineState *ms)
}
}
-void accel_register_compat_props(AccelState *accel)
-{
- AccelClass *class = ACCEL_GET_CLASS(accel);
- register_compat_props_array(class->global_props);
-}
-
void accel_setup_post(MachineState *ms)
{
AccelState *accel = ms->accelerator;
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 4880a05399..4e1de942ce 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -86,7 +86,7 @@ struct KVMState
int robust_singlestep;
int debugregs;
#ifdef KVM_CAP_SET_GUEST_DEBUG
- struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
+ QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
#endif
int many_ioeventfds;
int intx_set_mask;
@@ -102,7 +102,7 @@ struct KVMState
int nr_allocated_irq_routes;
unsigned long *used_gsi_bitmap;
unsigned int gsi_count;
- QTAILQ_HEAD(msi_hashtab, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
+ QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
#endif
KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 639f0b2728..8cb8c8870e 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -16,12 +16,8 @@
* 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/>.
*/
-#ifdef _WIN32
-#include <windows.h>
-#endif
#include "qemu/osdep.h"
-
#include "qemu-common.h"
#define NO_CPU_IO_DEFS
#include "cpu.h"
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index cd75829cf2..941295ea49 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -571,6 +571,81 @@ int cpu_signal_handler(int host_signum, void *pinfo,
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
}
+#elif defined(__riscv)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+ void *puc)
+{
+ siginfo_t *info = pinfo;
+ ucontext_t *uc = puc;
+ greg_t pc = uc->uc_mcontext.__gregs[REG_PC];
+ uint32_t insn = *(uint32_t *)pc;
+ int is_write = 0;
+
+ /* Detect store by reading the instruction at the program
+ counter. Note: we currently only generate 32-bit
+ instructions so we thus only detect 32-bit stores */
+ switch (((insn >> 0) & 0b11)) {
+ case 3:
+ switch (((insn >> 2) & 0b11111)) {
+ case 8:
+ switch (((insn >> 12) & 0b111)) {
+ case 0: /* sb */
+ case 1: /* sh */
+ case 2: /* sw */
+ case 3: /* sd */
+ case 4: /* sq */
+ is_write = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 9:
+ switch (((insn >> 12) & 0b111)) {
+ case 2: /* fsw */
+ case 3: /* fsd */
+ case 4: /* fsq */
+ is_write = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Check for compressed instructions */
+ switch (((insn >> 13) & 0b111)) {
+ case 7:
+ switch (insn & 0b11) {
+ case 0: /*c.sd */
+ case 2: /* c.sdsp */
+ is_write = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 6:
+ switch (insn & 0b11) {
+ case 0: /* c.sw */
+ case 3: /* c.swsp */
+ is_write = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
+}
+
#else
#error host CPU specific signal handler needed
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 362a2276fd..635be73bf4 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -28,9 +28,7 @@
#include "audio.h"
#include "trace.h"
-#if QEMU_GNUC_PREREQ(4, 3)
#pragma GCC diagnostic ignored "-Waddress"
-#endif
#define AUDIO_CAP "alsa"
#include "audio_int.h"
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 244b454012..6c451b995c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -191,7 +191,7 @@ struct SWVoiceCap {
QLIST_ENTRY (SWVoiceCap) entries;
};
-struct AudioState {
+typedef struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
@@ -203,7 +203,7 @@ struct AudioState {
int nb_hw_voices_out;
int nb_hw_voices_in;
int vm_running;
-};
+} AudioState;
extern const struct mixeng_volume nominal_volume;
diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c
index 6630021226..7a34e25c43 100644
--- a/backends/hostmem-file.c
+++ b/backends/hostmem-file.c
@@ -43,7 +43,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
{
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(backend);
#ifdef CONFIG_POSIX
- gchar *path;
+ gchar *name;
#endif
if (!backend->size) {
@@ -58,14 +58,14 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
error_setg(errp, "-mem-path not supported on this host");
#else
backend->force_prealloc = mem_prealloc;
- path = object_get_canonical_path(OBJECT(backend));
+ name = host_memory_backend_get_name(backend);
memory_region_init_ram_from_file(&backend->mr, OBJECT(backend),
- path,
+ name,
backend->size, fb->align,
(backend->share ? RAM_SHARED : 0) |
(fb->is_pmem ? RAM_PMEM : 0),
fb->mem_path, errp);
- g_free(path);
+ g_free(name);
#endif
}
@@ -145,26 +145,20 @@ static void file_memory_backend_set_pmem(Object *o, bool value, Error **errp)
HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o);
if (host_memory_backend_mr_inited(backend)) {
- char *path = object_get_canonical_path_component(o);
- error_setg(errp, "cannot change property 'pmem' of %s '%s'",
- object_get_typename(o),
- path);
- g_free(path);
+ error_setg(errp, "cannot change property 'pmem' of %s.",
+ object_get_typename(o));
return;
}
#ifndef CONFIG_LIBPMEM
if (value) {
Error *local_err = NULL;
- char *path = object_get_canonical_path_component(o);
error_setg(&local_err,
"Lack of libpmem support while setting the 'pmem=on'"
- " of %s '%s'. We can't ensure data persistence.",
- object_get_typename(o),
- path);
- g_free(path);
+ " of %s. We can't ensure data persistence.",
+ object_get_typename(o));
error_propagate(errp, local_err);
return;
}
diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c
index 2eb9c827a5..98c9bf3240 100644
--- a/backends/hostmem-memfd.c
+++ b/backends/hostmem-memfd.c
@@ -53,7 +53,7 @@ memfd_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
return;
}
- name = object_get_canonical_path(OBJECT(backend));
+ name = host_memory_backend_get_name(backend);
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
name, backend->size,
backend->share, fd, errp);
diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c
index 7ddd08d370..24b65d9ae3 100644
--- a/backends/hostmem-ram.c
+++ b/backends/hostmem-ram.c
@@ -16,21 +16,20 @@
#define TYPE_MEMORY_BACKEND_RAM "memory-backend-ram"
-
static void
ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
{
- char *path;
+ char *name;
if (!backend->size) {
error_setg(errp, "can't create backend with size 0");
return;
}
- path = object_get_canonical_path_component(OBJECT(backend));
- memory_region_init_ram_shared_nomigrate(&backend->mr, OBJECT(backend), path,
+ name = host_memory_backend_get_name(backend);
+ memory_region_init_ram_shared_nomigrate(&backend->mr, OBJECT(backend), name,
backend->size, backend->share, errp);
- g_free(path);
+ g_free(name);
}
static void
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 1a89342039..0c8ef17653 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -28,6 +28,16 @@ QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_BIND != MPOL_BIND);
QEMU_BUILD_BUG_ON(HOST_MEM_POLICY_INTERLEAVE != MPOL_INTERLEAVE);
#endif
+char *
+host_memory_backend_get_name(HostMemoryBackend *backend)
+{
+ if (!backend->use_canonical_path) {
+ return object_get_canonical_path_component(OBJECT(backend));
+ }
+
+ return object_get_canonical_path(OBJECT(backend));
+}
+
static void
host_memory_backend_get_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@@ -103,14 +113,23 @@ host_memory_backend_set_host_nodes(Object *obj, Visitor *v, const char *name,
{
#ifdef CONFIG_NUMA
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
- uint16List *l = NULL;
+ uint16List *l, *host_nodes = NULL;
+
+ visit_type_uint16List(v, name, &host_nodes, errp);
- visit_type_uint16List(v, name, &l, errp);
+ for (l = host_nodes; l; l = l->next) {
+ if (l->value >= MAX_NODES) {
+ error_setg(errp, "Invalid host-nodes value: %d", l->value);
+ goto out;
+ }
+ }
- while (l) {
+ for (l = host_nodes; l; l = l->next) {
bitmap_set(backend->host_nodes, l->value, 1);
- l = l->next;
}
+
+out:
+ qapi_free_uint16List(host_nodes);
#else
error_setg(errp, "NUMA node binding are not supported by this QEMU");
#endif
@@ -238,6 +257,11 @@ static void host_memory_backend_init(Object *obj)
backend->prealloc = mem_prealloc;
}
+static void host_memory_backend_post_init(Object *obj)
+{
+ object_apply_compat_props(obj);
+}
+
bool host_memory_backend_mr_inited(HostMemoryBackend *backend)
{
/*
@@ -386,6 +410,23 @@ static void host_memory_backend_set_share(Object *o, bool value, Error **errp)
backend->share = value;
}
+static bool
+host_memory_backend_get_use_canonical_path(Object *obj, Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+
+ return backend->use_canonical_path;
+}
+
+static void
+host_memory_backend_set_use_canonical_path(Object *obj, bool value,
+ Error **errp)
+{
+ HostMemoryBackend *backend = MEMORY_BACKEND(obj);
+
+ backend->use_canonical_path = value;
+}
+
static void
host_memory_backend_class_init(ObjectClass *oc, void *data)
{
@@ -432,6 +473,9 @@ host_memory_backend_class_init(ObjectClass *oc, void *data)
&error_abort);
object_class_property_set_description(oc, "share",
"Mark the memory as private to QEMU or shared", &error_abort);
+ object_class_property_add_bool(oc, "x-use-canonical-path-for-ramblock-id",
+ host_memory_backend_get_use_canonical_path,
+ host_memory_backend_set_use_canonical_path, &error_abort);
}
static const TypeInfo host_memory_backend_info = {
@@ -442,6 +486,7 @@ static const TypeInfo host_memory_backend_info = {
.class_init = host_memory_backend_class_init,
.instance_size = sizeof(HostMemoryBackend),
.instance_init = host_memory_backend_init,
+ .instance_post_init = host_memory_backend_post_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_USER_CREATABLE },
{ }
diff --git a/block.c b/block.c
index 811239ca23..4f5ff2cc12 100644
--- a/block.c
+++ b/block.c
@@ -1079,11 +1079,11 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
const char *filename, Error **errp)
{
BlockDriverState *parent = c->opaque;
- int orig_flags = bdrv_get_flags(parent);
+ bool read_only = bdrv_is_read_only(parent);
int ret;
- if (!(orig_flags & BDRV_O_RDWR)) {
- ret = bdrv_reopen(parent, orig_flags | BDRV_O_RDWR, errp);
+ if (read_only) {
+ ret = bdrv_reopen_set_read_only(parent, false, errp);
if (ret < 0) {
return ret;
}
@@ -1095,8 +1095,8 @@ static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
error_setg_errno(errp, -ret, "Could not update backing file link");
}
- if (!(orig_flags & BDRV_O_RDWR)) {
- bdrv_reopen(parent, orig_flags, NULL);
+ if (read_only) {
+ bdrv_reopen_set_read_only(parent, true, NULL);
}
return ret;
@@ -1139,22 +1139,18 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
{
*flags &= ~(BDRV_O_CACHE_MASK | BDRV_O_RDWR | BDRV_O_AUTO_RDONLY);
- assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
*flags |= BDRV_O_NO_FLUSH;
}
- assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
if (qemu_opt_get_bool_del(opts, BDRV_OPT_CACHE_DIRECT, false)) {
*flags |= BDRV_O_NOCACHE;
}
- assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
if (!qemu_opt_get_bool_del(opts, BDRV_OPT_READ_ONLY, false)) {
*flags |= BDRV_O_RDWR;
}
- assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
*flags |= BDRV_O_AUTO_RDONLY;
}
@@ -2931,7 +2927,6 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
BlockDriverState *bs,
QDict *options,
- int flags,
const BdrvChildRole *role,
QDict *parent_options,
int parent_flags)
@@ -2940,7 +2935,9 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
BlockReopenQueueEntry *bs_entry;
BdrvChild *child;
- QDict *old_options, *explicit_options;
+ QDict *old_options, *explicit_options, *options_copy;
+ int flags;
+ QemuOpts *opts;
/* Make sure that the caller remembered to use a drained section. This is
* important to avoid graph changes between the recursive queuing here and
@@ -2966,22 +2963,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
/*
* Precedence of options:
* 1. Explicitly passed in options (highest)
- * 2. Set in flags (only for top level)
- * 3. Retained from explicitly set options of bs
- * 4. Inherited from parent node
- * 5. Retained from effective options of bs
+ * 2. Retained from explicitly set options of bs
+ * 3. Inherited from parent node
+ * 4. Retained from effective options of bs
*/
- if (!parent_options) {
- /*
- * Any setting represented by flags is always updated. If the
- * corresponding QDict option is set, it takes precedence. Otherwise
- * the flag is translated into a QDict option. The old setting of bs is
- * not considered.
- */
- update_options_from_flags(options, flags);
- }
-
/* Old explicitly set values (don't overwrite by inherited value) */
if (bs_entry) {
old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
@@ -2995,16 +2981,10 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
/* Inherit from parent node */
if (parent_options) {
- QemuOpts *opts;
- QDict *options_copy;
- assert(!flags);
+ flags = 0;
role->inherit_options(&flags, options, parent_flags, parent_options);
- options_copy = qdict_clone_shallow(options);
- opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
- qemu_opts_absorb_qdict(opts, options_copy, NULL);
- update_flags_from_options(&flags, opts);
- qemu_opts_del(opts);
- qobject_unref(options_copy);
+ } else {
+ flags = bdrv_get_flags(bs);
}
/* Old values are used for options that aren't set yet */
@@ -3012,6 +2992,14 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
bdrv_join_options(bs, options, old_options);
qobject_unref(old_options);
+ /* We have the final set of options so let's update the flags */
+ options_copy = qdict_clone_shallow(options);
+ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, options_copy, NULL);
+ update_flags_from_options(&flags, opts);
+ qemu_opts_del(opts);
+ qobject_unref(options_copy);
+
/* bdrv_open_inherit() sets and clears some additional flags internally */
flags &= ~BDRV_O_PROTOCOL;
if (flags & BDRV_O_RDWR) {
@@ -3051,7 +3039,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
qdict_extract_subqdict(options, &new_child_options, child_key_dot);
g_free(child_key_dot);
- bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, 0,
+ bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options,
child->role, options, flags);
}
@@ -3060,10 +3048,9 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs,
- QDict *options, int flags)
+ QDict *options)
{
- return bdrv_reopen_queue_child(bs_queue, bs, options, flags,
- NULL, NULL, 0);
+ return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0);
}
/*
@@ -3125,22 +3112,18 @@ cleanup:
return ret;
}
-
-/* Reopen a single BlockDriverState with the specified flags. */
-int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
+int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
+ Error **errp)
{
- int ret = -1;
- Error *local_err = NULL;
+ int ret;
BlockReopenQueue *queue;
+ QDict *opts = qdict_new();
- bdrv_subtree_drained_begin(bs);
-
- queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
- ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- }
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
+ bdrv_subtree_drained_begin(bs);
+ queue = bdrv_reopen_queue(NULL, bs, opts);
+ ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, errp);
bdrv_subtree_drained_end(bs);
return ret;
@@ -3214,6 +3197,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
Error **errp)
{
int ret = -1;
+ int old_flags;
Error *local_err = NULL;
BlockDriver *drv;
QemuOpts *opts;
@@ -3240,7 +3224,12 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
goto error;
}
+ /* This was already called in bdrv_reopen_queue_child() so the flags
+ * are up-to-date. This time we simply want to remove the options from
+ * QemuOpts in order to indicate that they have been processed. */
+ old_flags = reopen_state->flags;
update_flags_from_options(&reopen_state->flags, opts);
+ assert(old_flags == reopen_state->flags);
discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
if (discard != NULL) {
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 46d585cfd0..7a81892a52 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -57,6 +57,8 @@ ssh.o-libs := $(LIBSSH2_LIBS)
block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
dmg-bz2.o-libs := $(BZIP2_LIBS)
+block-obj-$(if $(CONFIG_LZFSE),m,n) += dmg-lzfse.o
+dmg-lzfse.o-libs := $(LZFSE_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
parallels.o-cflags := $(LIBXML2_CFLAGS)
diff --git a/block/backup.c b/block/backup.c
index 4d084f6ca6..435414e964 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -28,6 +28,13 @@
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
+typedef struct CowRequest {
+ int64_t start_byte;
+ int64_t end_byte;
+ QLIST_ENTRY(CowRequest) list;
+ CoQueue wait_queue; /* coroutines blocked on this request */
+} CowRequest;
+
typedef struct BackupBlockJob {
BlockJob common;
BlockBackend *target;
@@ -322,37 +329,6 @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
hbitmap_set(backup_job->copy_bitmap, 0, len);
}
-void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
- uint64_t bytes)
-{
- BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
- int64_t start, end;
-
- assert(block_job_driver(job) == &backup_job_driver);
-
- start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size);
- end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size);
- wait_for_overlapping_requests(backup_job, start, end);
-}
-
-void backup_cow_request_begin(CowRequest *req, BlockJob *job,
- int64_t offset, uint64_t bytes)
-{
- BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
- int64_t start, end;
-
- assert(block_job_driver(job) == &backup_job_driver);
-
- start = QEMU_ALIGN_DOWN(offset, backup_job->cluster_size);
- end = QEMU_ALIGN_UP(offset + bytes, backup_job->cluster_size);
- cow_request_begin(req, backup_job, start, end);
-}
-
-void backup_cow_request_end(CowRequest *req)
-{
- cow_request_end(req);
-}
-
static void backup_drain(BlockJob *job)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
@@ -409,7 +385,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
HBitmapIter hbi;
hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
- while ((cluster = hbitmap_iter_next(&hbi, true)) != -1) {
+ while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
do {
if (yield_and_check(job)) {
return 0;
@@ -446,7 +422,8 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
break;
}
- offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset);
+ offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset,
+ UINT64_MAX);
if (offset == -1) {
hbitmap_set(job->copy_bitmap, cluster, end - cluster);
break;
diff --git a/block/bochs.c b/block/bochs.c
index 22e7d44211..79f95d3b50 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -85,14 +85,14 @@ static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
const struct bochs_header *bochs = (const void *)buf;
if (buf_size < HEADER_SIZE)
- return 0;
+ return 0;
if (!strcmp(bochs->magic, HEADER_MAGIC) &&
- !strcmp(bochs->type, REDOLOG_TYPE) &&
- !strcmp(bochs->subtype, GROWING_TYPE) &&
- ((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
- (le32_to_cpu(bochs->version) == HEADER_V1)))
- return 100;
+ !strcmp(bochs->type, REDOLOG_TYPE) &&
+ !strcmp(bochs->subtype, GROWING_TYPE) &&
+ ((le32_to_cpu(bochs->version) == HEADER_VERSION) ||
+ (le32_to_cpu(bochs->version) == HEADER_V1)))
+ return 100;
return 0;
}
@@ -125,8 +125,8 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
if (strcmp(bochs.magic, HEADER_MAGIC) ||
strcmp(bochs.type, REDOLOG_TYPE) ||
strcmp(bochs.subtype, GROWING_TYPE) ||
- ((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
- (le32_to_cpu(bochs.version) != HEADER_V1))) {
+ ((le32_to_cpu(bochs.version) != HEADER_VERSION) &&
+ (le32_to_cpu(bochs.version) != HEADER_V1))) {
error_setg(errp, "Image not in Bochs format");
return -EINVAL;
}
@@ -158,7 +158,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
}
for (i = 0; i < s->catalog_size; i++)
- le32_to_cpus(&s->catalog_bitmap[i]);
+ le32_to_cpus(&s->catalog_bitmap[i]);
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
@@ -217,7 +217,7 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
extent_offset = (offset % s->extent_size) / 512;
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
- return 0; /* not allocated */
+ return 0; /* not allocated */
}
bitmap_offset = s->data_offset +
@@ -232,7 +232,7 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
}
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
- return 0; /* not allocated */
+ return 0; /* not allocated */
}
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
diff --git a/block/commit.c b/block/commit.c
index a2da5740b0..53148e610b 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -38,7 +38,7 @@ typedef struct CommitBlockJob {
BlockBackend *base;
BlockDriverState *base_bs;
BlockdevOnError on_error;
- int base_flags;
+ bool base_read_only;
char *backing_file_str;
} CommitBlockJob;
@@ -124,8 +124,8 @@ static void commit_clean(Job *job)
/* restore base open flags here if appropriate (e.g., change the base back
* to r/o). These reopens do not need to be atomic, since we won't abort
* even on failure here */
- if (s->base_flags != bdrv_get_flags(s->base_bs)) {
- bdrv_reopen(s->base_bs, s->base_flags, NULL);
+ if (s->base_read_only) {
+ bdrv_reopen_set_read_only(s->base_bs, true, NULL);
}
g_free(s->backing_file_str);
@@ -264,7 +264,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
const char *filter_node_name, Error **errp)
{
CommitBlockJob *s;
- int orig_base_flags;
BlockDriverState *iter;
BlockDriverState *commit_top_bs = NULL;
Error *local_err = NULL;
@@ -283,11 +282,9 @@ void commit_start(const char *job_id, BlockDriverState *bs,
}
/* convert base to r/w, if necessary */
- orig_base_flags = bdrv_get_flags(base);
- if (!(orig_base_flags & BDRV_O_RDWR)) {
- bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
+ s->base_read_only = bdrv_is_read_only(base);
+ if (s->base_read_only) {
+ if (bdrv_reopen_set_read_only(base, false, errp) != 0) {
goto fail;
}
}
@@ -363,7 +360,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
goto fail;
}
- s->base_flags = orig_base_flags;
s->backing_file_str = g_strdup(backing_file_str);
s->on_error = on_error;
@@ -395,7 +391,7 @@ int bdrv_commit(BlockDriverState *bs)
BlockDriverState *commit_top_bs = NULL;
BlockDriver *drv = bs->drv;
int64_t offset, length, backing_length;
- int ro, open_flags;
+ int ro;
int64_t n;
int ret = 0;
uint8_t *buf = NULL;
@@ -414,10 +410,9 @@ int bdrv_commit(BlockDriverState *bs)
}
ro = bs->backing->bs->read_only;
- open_flags = bs->backing->bs->open_flags;
if (ro) {
- if (bdrv_reopen(bs->backing->bs, open_flags | BDRV_O_RDWR, NULL)) {
+ if (bdrv_reopen_set_read_only(bs->backing->bs, false, NULL)) {
return -EACCES;
}
}
@@ -527,7 +522,7 @@ ro_cleanup:
if (ro) {
/* ignoring error return here */
- bdrv_reopen(bs->backing->bs, open_flags & ~BDRV_O_RDWR, NULL);
+ bdrv_reopen_set_read_only(bs->backing->bs, true, NULL);
}
return ret;
diff --git a/block/crypto.c b/block/crypto.c
index 33ee01bebd..f0a5f6b987 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -229,6 +229,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
block_crypto_read_func,
bs,
cflags,
+ 1,
errp);
if (!crypto->block) {
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 89fd1d7f8b..00ea36f554 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -515,62 +515,7 @@ void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
{
- return hbitmap_iter_next(&iter->hbi, true);
-}
-
-/**
- * Return the next consecutively dirty area in the dirty bitmap
- * belonging to the given iterator @iter.
- *
- * @max_offset: Maximum value that may be returned for
- * *offset + *bytes
- * @offset: Will contain the start offset of the next dirty area
- * @bytes: Will contain the length of the next dirty area
- *
- * Returns: True if a dirty area could be found before max_offset
- * (which means that *offset and *bytes then contain valid
- * values), false otherwise.
- *
- * Note that @iter is never advanced if false is returned. If an area
- * is found (which means that true is returned), it will be advanced
- * past that area.
- */
-bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
- uint64_t *offset, int *bytes)
-{
- uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap);
- uint64_t gran_max_offset;
- int64_t ret;
- int size;
-
- if (max_offset == iter->bitmap->size) {
- /* If max_offset points to the image end, round it up by the
- * bitmap granularity */
- gran_max_offset = ROUND_UP(max_offset, granularity);
- } else {
- gran_max_offset = max_offset;
- }
-
- ret = hbitmap_iter_next(&iter->hbi, false);
- if (ret < 0 || ret + granularity > gran_max_offset) {
- return false;
- }
-
- *offset = ret;
- size = 0;
-
- assert(granularity <= INT_MAX);
-
- do {
- /* Advance iterator */
- ret = hbitmap_iter_next(&iter->hbi, true);
- size += granularity;
- } while (ret + granularity <= gran_max_offset &&
- hbitmap_iter_next(&iter->hbi, false) == ret + granularity &&
- size <= INT_MAX - granularity);
-
- *bytes = MIN(size, max_offset - *offset);
- return true;
+ return hbitmap_iter_next(&iter->hbi);
}
/* Called within bdrv_dirty_bitmap_lock..unlock */
@@ -625,7 +570,6 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
void bdrv_restore_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *backup)
{
HBitmap *tmp = bitmap->bitmap;
- assert(bdrv_dirty_bitmap_enabled(bitmap));
assert(!bdrv_dirty_bitmap_readonly(bitmap));
bitmap->bitmap = backup;
hbitmap_free(tmp);
@@ -782,9 +726,16 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp)
return hbitmap_sha256(bitmap->bitmap, errp);
}
-int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset)
+int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset,
+ uint64_t bytes)
+{
+ return hbitmap_next_zero(bitmap->bitmap, offset, bytes);
+}
+
+bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
+ uint64_t *offset, uint64_t *bytes)
{
- return hbitmap_next_zero(bitmap->bitmap, offset);
+ return hbitmap_next_dirty_area(bitmap->bitmap, offset, bytes);
}
void bdrv_merge_dirty_bitmap(BdrvDirtyBitmap *dest, const BdrvDirtyBitmap *src,
diff --git a/block/dmg-lzfse.c b/block/dmg-lzfse.c
new file mode 100644
index 0000000000..19d25bc646
--- /dev/null
+++ b/block/dmg-lzfse.c
@@ -0,0 +1,49 @@
+/*
+ * DMG lzfse uncompression
+ *
+ * Copyright (c) 2018 Julio Cesar Faracco
+ *
+ * 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/osdep.h"
+#include "qemu-common.h"
+#include "dmg.h"
+#include <lzfse.h>
+
+static int dmg_uncompress_lzfse_do(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out)
+{
+ size_t out_size = lzfse_decode_buffer((uint8_t *) next_out, avail_out,
+ (uint8_t *) next_in, avail_in,
+ NULL);
+
+ /* We need to decode the single chunk only. */
+ /* So, out_size == avail_out is not an error here. */
+ if (out_size > 0) {
+ return out_size;
+ }
+ return -1;
+}
+
+__attribute__((constructor))
+static void dmg_lzfse_init(void)
+{
+ assert(!dmg_uncompress_lzfse);
+ dmg_uncompress_lzfse = dmg_uncompress_lzfse_do;
+}
diff --git a/block/dmg.c b/block/dmg.c
index 1d9283ba2f..43497bf343 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -33,6 +33,9 @@
int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
char *next_out, unsigned int avail_out);
+int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out);
+
enum {
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
* or truncating when converting to 32-bit types
@@ -41,6 +44,19 @@ enum {
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
};
+enum {
+ /* DMG Block Type */
+ UDZE = 0, /* Zeroes */
+ UDRW, /* RAW type */
+ UDIG, /* Ignore */
+ UDCO = 0x80000004,
+ UDZO,
+ UDBZ,
+ ULFO,
+ UDCM = 0x7ffffffe, /* Comments */
+ UDLE = 0xffffffff /* Last Entry */
+};
+
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
{
int len;
@@ -105,15 +121,17 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk,
uint32_t uncompressed_sectors = 0;
switch (s->types[chunk]) {
- case 0x80000005: /* zlib compressed */
- case 0x80000006: /* bzip2 compressed */
+ case UDZO: /* zlib compressed */
+ case UDBZ: /* bzip2 compressed */
+ case ULFO: /* lzfse compressed */
compressed_size = s->lengths[chunk];
uncompressed_sectors = s->sectorcounts[chunk];
break;
- case 1: /* copy */
+ case UDRW: /* copy */
uncompressed_sectors = DIV_ROUND_UP(s->lengths[chunk], 512);
break;
- case 2: /* zero */
+ case UDZE: /* zero */
+ case UDIG: /* ignore */
/* as the all-zeroes block may be large, it is treated specially: the
* sector is not copied from a large buffer, a simple memset is used
* instead. Therefore uncompressed_sectors does not need to be set. */
@@ -182,12 +200,15 @@ typedef struct DmgHeaderState {
static bool dmg_is_known_block_type(uint32_t entry_type)
{
switch (entry_type) {
- case 0x00000001: /* uncompressed */
- case 0x00000002: /* zeroes */
- case 0x80000005: /* zlib */
+ case UDZE: /* zeros */
+ case UDRW: /* uncompressed */
+ case UDIG: /* ignore */
+ case UDZO: /* zlib */
return true;
- case 0x80000006: /* bzip2 */
+ case UDBZ: /* bzip2 */
return !!dmg_uncompress_bz2;
+ case ULFO: /* lzfse */
+ return !!dmg_uncompress_lzfse;
default:
return false;
}
@@ -246,9 +267,10 @@ static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds,
/* sector count */
s->sectorcounts[i] = buff_read_uint64(buffer, offset + 0x10);
- /* all-zeroes sector (type 2) does not need to be "uncompressed" and can
- * therefore be unbounded. */
- if (s->types[i] != 2 && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
+ /* all-zeroes sector (type UDZE and UDIG) does not need to be
+ * "uncompressed" and can therefore be unbounded. */
+ if (s->types[i] != UDZE && s->types[i] != UDIG
+ && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
error_report("sector count %" PRIu64 " for chunk %" PRIu32
" is larger than max (%u)",
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
@@ -425,6 +447,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
}
block_module_load_one("dmg-bz2");
+ block_module_load_one("dmg-lzfse");
s->n_chunks = 0;
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
@@ -552,16 +575,20 @@ static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num)
{
/* binary search */
uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3;
- while (chunk1 != chunk2) {
+ while (chunk1 <= chunk2) {
chunk3 = (chunk1 + chunk2) / 2;
if (s->sectors[chunk3] > sector_num) {
- chunk2 = chunk3;
+ if (chunk3 == 0) {
+ goto err;
+ }
+ chunk2 = chunk3 - 1;
} else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) {
return chunk3;
} else {
- chunk1 = chunk3;
+ chunk1 = chunk3 + 1;
}
}
+err:
return s->n_chunks; /* error */
}
@@ -579,7 +606,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
s->current_chunk = s->n_chunks;
switch (s->types[chunk]) { /* block entry type */
- case 0x80000005: { /* zlib compressed */
+ case UDZO: { /* zlib compressed */
/* we need to buffer, because only the chunk as whole can be
* inflated. */
ret = bdrv_pread(bs->file, s->offsets[chunk],
@@ -602,7 +629,7 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return -1;
}
break; }
- case 0x80000006: /* bzip2 compressed */
+ case UDBZ: /* bzip2 compressed */
if (!dmg_uncompress_bz2) {
break;
}
@@ -623,14 +650,36 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
return ret;
}
break;
- case 1: /* copy */
+ case ULFO:
+ if (!dmg_uncompress_lzfse) {
+ break;
+ }
+ /* we need to buffer, because only the chunk as whole can be
+ * inflated. */
+ ret = bdrv_pread(bs->file, s->offsets[chunk],
+ s->compressed_chunk, s->lengths[chunk]);
+ if (ret != s->lengths[chunk]) {
+ return -1;
+ }
+
+ ret = dmg_uncompress_lzfse((char *)s->compressed_chunk,
+ (unsigned int) s->lengths[chunk],
+ (char *)s->uncompressed_chunk,
+ (unsigned int)
+ (512 * s->sectorcounts[chunk]));
+ if (ret < 0) {
+ return ret;
+ }
+ break;
+ case UDRW: /* copy */
ret = bdrv_pread(bs->file, s->offsets[chunk],
s->uncompressed_chunk, s->lengths[chunk]);
if (ret != s->lengths[chunk]) {
return -1;
}
break;
- case 2: /* zero */
+ case UDZE: /* zeros */
+ case UDIG: /* ignore */
/* see dmg_read, it is treated specially. No buffer needs to be
* pre-filled, the zeroes can be set directly. */
break;
@@ -665,7 +714,8 @@ dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
/* Special case: current chunk is all zeroes. Do not perform a memcpy as
* s->uncompressed_chunk may be too small to cover the large all-zeroes
* section. dmg_read_chunk is called to find s->current_chunk */
- if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */
+ if (s->types[s->current_chunk] == UDZE
+ || s->types[s->current_chunk] == UDIG) { /* all zeroes block entry */
qemu_iovec_memset(qiov, i * 512, 0, 512);
continue;
}
diff --git a/block/dmg.h b/block/dmg.h
index 2ecf239ba5..f28929998f 100644
--- a/block/dmg.h
+++ b/block/dmg.h
@@ -55,4 +55,7 @@ typedef struct BDRVDMGState {
extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
char *next_out, unsigned int avail_out);
+extern int (*dmg_uncompress_lzfse)(char *next_in, unsigned int avail_in,
+ char *next_out, unsigned int avail_out);
+
#endif
diff --git a/block/file-posix.c b/block/file-posix.c
index 07bbdab953..8aee7a3fb8 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -182,25 +182,29 @@ static int64_t raw_getlength(BlockDriverState *bs);
typedef struct RawPosixAIOData {
BlockDriverState *bs;
+ int aio_type;
int aio_fildes;
- union {
- struct iovec *aio_iov;
- void *aio_ioctl_buf;
- };
- int aio_niov;
- uint64_t aio_nbytes;
-#define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */
+
off_t aio_offset;
- int aio_type;
+ uint64_t aio_nbytes;
+
union {
struct {
+ struct iovec *iov;
+ int niov;
+ } io;
+ struct {
+ uint64_t cmd;
+ void *buf;
+ } ioctl;
+ struct {
int aio_fd2;
off_t aio_offset2;
- };
+ } copy_range;
struct {
PreallocMode prealloc;
Error **errp;
- };
+ } truncate;
};
} RawPosixAIOData;
@@ -1148,20 +1152,24 @@ static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
}
#endif
-static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
+#if defined(__linux__)
+static int handle_aiocb_ioctl(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
int ret;
- ret = ioctl(aiocb->aio_fildes, aiocb->aio_ioctl_cmd, aiocb->aio_ioctl_buf);
+ ret = ioctl(aiocb->aio_fildes, aiocb->ioctl.cmd, aiocb->ioctl.buf);
if (ret == -1) {
return -errno;
}
return 0;
}
+#endif /* linux */
-static ssize_t handle_aiocb_flush(RawPosixAIOData *aiocb)
+static int handle_aiocb_flush(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
BDRVRawState *s = aiocb->bs->opaque;
int ret;
@@ -1233,13 +1241,13 @@ static ssize_t handle_aiocb_rw_vector(RawPosixAIOData *aiocb)
do {
if (aiocb->aio_type & QEMU_AIO_WRITE)
len = qemu_pwritev(aiocb->aio_fildes,
- aiocb->aio_iov,
- aiocb->aio_niov,
+ aiocb->io.iov,
+ aiocb->io.niov,
aiocb->aio_offset);
else
len = qemu_preadv(aiocb->aio_fildes,
- aiocb->aio_iov,
- aiocb->aio_niov,
+ aiocb->io.iov,
+ aiocb->io.niov,
aiocb->aio_offset);
} while (len == -1 && errno == EINTR);
@@ -1295,8 +1303,9 @@ static ssize_t handle_aiocb_rw_linear(RawPosixAIOData *aiocb, char *buf)
return offset;
}
-static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
+static int handle_aiocb_rw(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
ssize_t nbytes;
char *buf;
@@ -1305,8 +1314,9 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
* If there is just a single buffer, and it is properly aligned
* we can just use plain pread/pwrite without any problems.
*/
- if (aiocb->aio_niov == 1) {
- return handle_aiocb_rw_linear(aiocb, aiocb->aio_iov->iov_base);
+ if (aiocb->io.niov == 1) {
+ nbytes = handle_aiocb_rw_linear(aiocb, aiocb->io.iov->iov_base);
+ goto out;
}
/*
* We have more than one iovec, and all are properly aligned.
@@ -1318,7 +1328,7 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
nbytes = handle_aiocb_rw_vector(aiocb);
if (nbytes == aiocb->aio_nbytes ||
(nbytes < 0 && nbytes != -ENOSYS)) {
- return nbytes;
+ goto out;
}
preadv_present = false;
}
@@ -1336,16 +1346,17 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
*/
buf = qemu_try_blockalign(aiocb->bs, aiocb->aio_nbytes);
if (buf == NULL) {
- return -ENOMEM;
+ nbytes = -ENOMEM;
+ goto out;
}
if (aiocb->aio_type & QEMU_AIO_WRITE) {
char *p = buf;
int i;
- for (i = 0; i < aiocb->aio_niov; ++i) {
- memcpy(p, aiocb->aio_iov[i].iov_base, aiocb->aio_iov[i].iov_len);
- p += aiocb->aio_iov[i].iov_len;
+ for (i = 0; i < aiocb->io.niov; ++i) {
+ memcpy(p, aiocb->io.iov[i].iov_base, aiocb->io.iov[i].iov_len);
+ p += aiocb->io.iov[i].iov_len;
}
assert(p - buf == aiocb->aio_nbytes);
}
@@ -1356,12 +1367,12 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
size_t count = aiocb->aio_nbytes, copy;
int i;
- for (i = 0; i < aiocb->aio_niov && count; ++i) {
+ for (i = 0; i < aiocb->io.niov && count; ++i) {
copy = count;
- if (copy > aiocb->aio_iov[i].iov_len) {
- copy = aiocb->aio_iov[i].iov_len;
+ if (copy > aiocb->io.iov[i].iov_len) {
+ copy = aiocb->io.iov[i].iov_len;
}
- memcpy(aiocb->aio_iov[i].iov_base, p, copy);
+ memcpy(aiocb->io.iov[i].iov_base, p, copy);
assert(count >= copy);
p += copy;
count -= copy;
@@ -1370,7 +1381,21 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
}
qemu_vfree(buf);
- return nbytes;
+out:
+ if (nbytes == aiocb->aio_nbytes) {
+ return 0;
+ } else if (nbytes >= 0 && nbytes < aiocb->aio_nbytes) {
+ if (aiocb->aio_type & QEMU_AIO_WRITE) {
+ return -EINVAL;
+ } else {
+ iov_memset(aiocb->io.iov, aiocb->io.niov, nbytes,
+ 0, aiocb->aio_nbytes - nbytes);
+ return 0;
+ }
+ } else {
+ assert(nbytes < 0);
+ return nbytes;
+ }
}
#ifdef CONFIG_XFS
@@ -1460,8 +1485,9 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
return ret;
}
-static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
+static int handle_aiocb_write_zeroes(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS)
BDRVRawState *s = aiocb->bs->opaque;
#endif
@@ -1525,8 +1551,9 @@ static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
return -ENOTSUP;
}
-static ssize_t handle_aiocb_write_zeroes_unmap(RawPosixAIOData *aiocb)
+static int handle_aiocb_write_zeroes_unmap(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
BDRVRawState *s G_GNUC_UNUSED = aiocb->bs->opaque;
int ret;
@@ -1568,18 +1595,20 @@ static off_t copy_file_range(int in_fd, off_t *in_off, int out_fd,
}
#endif
-static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb)
+static int handle_aiocb_copy_range(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
uint64_t bytes = aiocb->aio_nbytes;
off_t in_off = aiocb->aio_offset;
- off_t out_off = aiocb->aio_offset2;
+ off_t out_off = aiocb->copy_range.aio_offset2;
while (bytes) {
ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off,
- aiocb->aio_fd2, &out_off,
+ aiocb->copy_range.aio_fd2, &out_off,
bytes, 0);
trace_file_copy_file_range(aiocb->bs, aiocb->aio_fildes, in_off,
- aiocb->aio_fd2, out_off, bytes, 0, ret);
+ aiocb->copy_range.aio_fd2, out_off, bytes,
+ 0, ret);
if (ret == 0) {
/* No progress (e.g. when beyond EOF), let the caller fall back to
* buffer I/O. */
@@ -1600,8 +1629,9 @@ static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb)
return 0;
}
-static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
+static int handle_aiocb_discard(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
int ret = -EOPNOTSUPP;
BDRVRawState *s = aiocb->bs->opaque;
@@ -1640,15 +1670,17 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData *aiocb)
return ret;
}
-static int handle_aiocb_truncate(RawPosixAIOData *aiocb)
+static int handle_aiocb_truncate(void *opaque)
{
+ RawPosixAIOData *aiocb = opaque;
int result = 0;
int64_t current_length = 0;
char *buf = NULL;
struct stat st;
int fd = aiocb->aio_fildes;
int64_t offset = aiocb->aio_offset;
- Error **errp = aiocb->errp;
+ PreallocMode prealloc = aiocb->truncate.prealloc;
+ Error **errp = aiocb->truncate.errp;
if (fstat(fd, &st) < 0) {
result = -errno;
@@ -1657,12 +1689,12 @@ static int handle_aiocb_truncate(RawPosixAIOData *aiocb)
}
current_length = st.st_size;
- if (current_length > offset && aiocb->prealloc != PREALLOC_MODE_OFF) {
+ if (current_length > offset && prealloc != PREALLOC_MODE_OFF) {
error_setg(errp, "Cannot use preallocation for shrinking files");
return -ENOTSUP;
}
- switch (aiocb->prealloc) {
+ switch (prealloc) {
#ifdef CONFIG_POSIX_FALLOCATE
case PREALLOC_MODE_FALLOC:
/*
@@ -1743,7 +1775,7 @@ static int handle_aiocb_truncate(RawPosixAIOData *aiocb)
default:
result = -ENOTSUP;
error_setg(errp, "Unsupported preallocation mode: %s",
- PreallocMode_str(aiocb->prealloc));
+ PreallocMode_str(prealloc));
return result;
}
@@ -1759,104 +1791,19 @@ out:
return result;
}
-static int aio_worker(void *arg)
+static int coroutine_fn raw_thread_pool_submit(BlockDriverState *bs,
+ ThreadPoolFunc func, void *arg)
{
- RawPosixAIOData *aiocb = arg;
- ssize_t ret = 0;
-
- switch (aiocb->aio_type & QEMU_AIO_TYPE_MASK) {
- case QEMU_AIO_READ:
- ret = handle_aiocb_rw(aiocb);
- if (ret >= 0 && ret < aiocb->aio_nbytes) {
- iov_memset(aiocb->aio_iov, aiocb->aio_niov, ret,
- 0, aiocb->aio_nbytes - ret);
-
- ret = aiocb->aio_nbytes;
- }
- if (ret == aiocb->aio_nbytes) {
- ret = 0;
- } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
- ret = -EINVAL;
- }
- break;
- case QEMU_AIO_WRITE:
- ret = handle_aiocb_rw(aiocb);
- if (ret == aiocb->aio_nbytes) {
- ret = 0;
- } else if (ret >= 0 && ret < aiocb->aio_nbytes) {
- ret = -EINVAL;
- }
- break;
- case QEMU_AIO_FLUSH:
- ret = handle_aiocb_flush(aiocb);
- break;
- case QEMU_AIO_IOCTL:
- ret = handle_aiocb_ioctl(aiocb);
- break;
- case QEMU_AIO_DISCARD:
- ret = handle_aiocb_discard(aiocb);
- break;
- case QEMU_AIO_WRITE_ZEROES:
- ret = handle_aiocb_write_zeroes(aiocb);
- break;
- case QEMU_AIO_WRITE_ZEROES | QEMU_AIO_DISCARD:
- ret = handle_aiocb_write_zeroes_unmap(aiocb);
- break;
- case QEMU_AIO_COPY_RANGE:
- ret = handle_aiocb_copy_range(aiocb);
- break;
- case QEMU_AIO_TRUNCATE:
- ret = handle_aiocb_truncate(aiocb);
- break;
- default:
- error_report("invalid aio request (0x%x)", aiocb->aio_type);
- ret = -EINVAL;
- break;
- }
-
- g_free(aiocb);
- return ret;
-}
-
-static int paio_submit_co_full(BlockDriverState *bs, int fd,
- int64_t offset, int fd2, int64_t offset2,
- QEMUIOVector *qiov,
- int bytes, int type)
-{
- RawPosixAIOData *acb = g_new(RawPosixAIOData, 1);
- ThreadPool *pool;
-
- acb->bs = bs;
- acb->aio_type = type;
- acb->aio_fildes = fd;
- acb->aio_fd2 = fd2;
- acb->aio_offset2 = offset2;
-
- acb->aio_nbytes = bytes;
- acb->aio_offset = offset;
-
- if (qiov) {
- acb->aio_iov = qiov->iov;
- acb->aio_niov = qiov->niov;
- assert(qiov->size == bytes);
- }
-
- trace_file_paio_submit_co(offset, bytes, type);
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
- return thread_pool_submit_co(pool, aio_worker, acb);
-}
-
-static inline int paio_submit_co(BlockDriverState *bs, int fd,
- int64_t offset, QEMUIOVector *qiov,
- int bytes, int type)
-{
- return paio_submit_co_full(bs, fd, offset, -1, 0, qiov, bytes, type);
+ /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
+ ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
+ return thread_pool_submit_co(pool, func, arg);
}
static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov, int type)
{
BDRVRawState *s = bs->opaque;
+ RawPosixAIOData acb;
if (fd_open(bs) < 0)
return -EIO;
@@ -1879,7 +1826,20 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
}
}
- return paio_submit_co(bs, s->fd, offset, qiov, bytes, type);
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_fildes = s->fd,
+ .aio_type = type,
+ .aio_offset = offset,
+ .aio_nbytes = bytes,
+ .io = {
+ .iov = qiov->iov,
+ .niov = qiov->niov,
+ },
+ };
+
+ assert(qiov->size == bytes);
+ return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
}
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
@@ -1922,6 +1882,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
static int raw_co_flush_to_disk(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
+ RawPosixAIOData acb;
int ret;
ret = fd_open(bs);
@@ -1929,7 +1890,13 @@ static int raw_co_flush_to_disk(BlockDriverState *bs)
return ret;
}
- return paio_submit_co(bs, s->fd, 0, NULL, 0, QEMU_AIO_FLUSH);
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_fildes = s->fd,
+ .aio_type = QEMU_AIO_FLUSH,
+ };
+
+ return raw_thread_pool_submit(bs, handle_aiocb_flush, &acb);
}
static void raw_aio_attach_aio_context(BlockDriverState *bs,
@@ -1968,21 +1935,20 @@ static int coroutine_fn
raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
PreallocMode prealloc, Error **errp)
{
- RawPosixAIOData *acb = g_new(RawPosixAIOData, 1);
- ThreadPool *pool;
+ RawPosixAIOData acb;
- *acb = (RawPosixAIOData) {
+ acb = (RawPosixAIOData) {
.bs = bs,
.aio_fildes = fd,
.aio_type = QEMU_AIO_TRUNCATE,
.aio_offset = offset,
- .prealloc = prealloc,
- .errp = errp,
+ .truncate = {
+ .prealloc = prealloc,
+ .errp = errp,
+ },
};
- /* @bs can be NULL, bdrv_get_aio_context() returns the main context then */
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
- return thread_pool_submit_co(pool, aio_worker, acb);
+ return raw_thread_pool_submit(bs, handle_aiocb_truncate, &acb);
}
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
@@ -2117,7 +2083,7 @@ again:
#endif
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
- if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
+ if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
#elif defined(DIOCGPART)
{
struct partinfo pi;
@@ -2613,25 +2579,67 @@ static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs,
}
static coroutine_fn int
-raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
+raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int bytes, bool blkdev)
{
BDRVRawState *s = bs->opaque;
+ RawPosixAIOData acb;
+
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_fildes = s->fd,
+ .aio_type = QEMU_AIO_DISCARD,
+ .aio_offset = offset,
+ .aio_nbytes = bytes,
+ };
+
+ if (blkdev) {
+ acb.aio_type |= QEMU_AIO_BLKDEV;
+ }
- return paio_submit_co(bs, s->fd, offset, NULL, bytes, QEMU_AIO_DISCARD);
+ return raw_thread_pool_submit(bs, handle_aiocb_discard, &acb);
}
-static int coroutine_fn raw_co_pwrite_zeroes(
- BlockDriverState *bs, int64_t offset,
- int bytes, BdrvRequestFlags flags)
+static coroutine_fn int
+raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
+{
+ return raw_do_pdiscard(bs, offset, bytes, false);
+}
+
+static int coroutine_fn
+raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
+ BdrvRequestFlags flags, bool blkdev)
{
BDRVRawState *s = bs->opaque;
- int operation = QEMU_AIO_WRITE_ZEROES;
+ RawPosixAIOData acb;
+ ThreadPoolFunc *handler;
+
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_fildes = s->fd,
+ .aio_type = QEMU_AIO_WRITE_ZEROES,
+ .aio_offset = offset,
+ .aio_nbytes = bytes,
+ };
+
+ if (blkdev) {
+ acb.aio_type |= QEMU_AIO_BLKDEV;
+ }
if (flags & BDRV_REQ_MAY_UNMAP) {
- operation |= QEMU_AIO_DISCARD;
+ acb.aio_type |= QEMU_AIO_DISCARD;
+ handler = handle_aiocb_write_zeroes_unmap;
+ } else {
+ handler = handle_aiocb_write_zeroes;
}
- return paio_submit_co(bs, s->fd, offset, NULL, bytes, operation);
+ return raw_thread_pool_submit(bs, handler, &acb);
+}
+
+static int coroutine_fn raw_co_pwrite_zeroes(
+ BlockDriverState *bs, int64_t offset,
+ int bytes, BdrvRequestFlags flags)
+{
+ return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false);
}
static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@@ -2702,6 +2710,7 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags)
{
+ RawPosixAIOData acb;
BDRVRawState *s = bs->opaque;
BDRVRawState *src_s;
@@ -2714,8 +2723,20 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
if (fd_open(src->bs) < 0 || fd_open(dst->bs) < 0) {
return -EIO;
}
- return paio_submit_co_full(bs, src_s->fd, src_offset, s->fd, dst_offset,
- NULL, bytes, QEMU_AIO_COPY_RANGE);
+
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_type = QEMU_AIO_COPY_RANGE,
+ .aio_fildes = src_s->fd,
+ .aio_offset = src_offset,
+ .aio_nbytes = bytes,
+ .copy_range = {
+ .aio_fd2 = s->fd,
+ .aio_offset2 = dst_offset,
+ },
+ };
+
+ return raw_thread_pool_submit(bs, handle_aiocb_copy_range, &acb);
}
BlockDriver bdrv_file = {
@@ -3063,36 +3084,39 @@ hdev_open_Mac_error:
}
#if defined(__linux__)
-
-static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
- unsigned long int req, void *buf,
- BlockCompletionFunc *cb, void *opaque)
+static int coroutine_fn
+hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
BDRVRawState *s = bs->opaque;
- RawPosixAIOData *acb;
- ThreadPool *pool;
+ RawPosixAIOData acb;
+ int ret;
- if (fd_open(bs) < 0)
- return NULL;
+ ret = fd_open(bs);
+ if (ret < 0) {
+ return ret;
+ }
if (req == SG_IO && s->pr_mgr) {
struct sg_io_hdr *io_hdr = buf;
if (io_hdr->cmdp[0] == PERSISTENT_RESERVE_OUT ||
io_hdr->cmdp[0] == PERSISTENT_RESERVE_IN) {
return pr_manager_execute(s->pr_mgr, bdrv_get_aio_context(bs),
- s->fd, io_hdr, cb, opaque);
+ s->fd, io_hdr);
}
}
- acb = g_new(RawPosixAIOData, 1);
- acb->bs = bs;
- acb->aio_type = QEMU_AIO_IOCTL;
- acb->aio_fildes = s->fd;
- acb->aio_offset = 0;
- acb->aio_ioctl_buf = buf;
- acb->aio_ioctl_cmd = req;
- pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
- return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
+ acb = (RawPosixAIOData) {
+ .bs = bs,
+ .aio_type = QEMU_AIO_IOCTL,
+ .aio_fildes = s->fd,
+ .aio_offset = 0,
+ .ioctl = {
+ .buf = buf,
+ .cmd = req,
+ },
+ };
+
+ return raw_thread_pool_submit(bs, handle_aiocb_ioctl, &acb);
}
#endif /* linux */
@@ -3109,22 +3133,18 @@ static int fd_open(BlockDriverState *bs)
static coroutine_fn int
hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
{
- BDRVRawState *s = bs->opaque;
int ret;
ret = fd_open(bs);
if (ret < 0) {
return ret;
}
- return paio_submit_co(bs, s->fd, offset, NULL, bytes,
- QEMU_AIO_DISCARD | QEMU_AIO_BLKDEV);
+ return raw_do_pdiscard(bs, offset, bytes, true);
}
static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags)
{
- BDRVRawState *s = bs->opaque;
- int operation = QEMU_AIO_WRITE_ZEROES | QEMU_AIO_BLKDEV;
int rc;
rc = fd_open(bs);
@@ -3132,11 +3152,7 @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
return rc;
}
- if (flags & BDRV_REQ_MAY_UNMAP) {
- operation |= QEMU_AIO_DISCARD;
- }
-
- return paio_submit_co(bs, s->fd, offset, NULL, bytes, operation);
+ return raw_do_pwrite_zeroes(bs, offset, bytes, flags, true);
}
static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts,
@@ -3241,7 +3257,7 @@ static BlockDriver bdrv_host_device = {
/* generic scsi device */
#ifdef __linux__
- .bdrv_aio_ioctl = hdev_aio_ioctl,
+ .bdrv_co_ioctl = hdev_co_ioctl,
#endif
};
@@ -3363,7 +3379,7 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_lock_medium = cdrom_lock_medium,
/* generic scsi device */
- .bdrv_aio_ioctl = hdev_aio_ioctl,
+ .bdrv_co_ioctl = hdev_co_ioctl,
};
#endif /* __linux__ */
diff --git a/block/file-win32.c b/block/file-win32.c
index f1e2187f3b..6b2d67b239 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -176,7 +176,7 @@ int qemu_ftruncate64(int fd, int64_t length)
BOOL res;
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
- return -1;
+ return -1;
h = (HANDLE)_get_osfhandle(fd);
@@ -184,13 +184,13 @@ int qemu_ftruncate64(int fd, int64_t length)
li.HighPart = 0;
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
- return -1;
+ return -1;
}
high = length >> 32;
dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
- return -1;
+ return -1;
}
res = SetEndOfFile(h);
@@ -203,7 +203,7 @@ static int set_sparse(int fd)
{
DWORD returned;
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
- NULL, 0, NULL, 0, &returned, NULL);
+ NULL, 0, NULL, 0, &returned, NULL);
}
static void raw_detach_aio_context(BlockDriverState *bs)
diff --git a/block/gluster.c b/block/gluster.c
index 5e300c96c8..72891060e3 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -72,7 +72,7 @@ typedef struct ListElement {
GlfsPreopened saved;
} ListElement;
-static QLIST_HEAD(glfs_list, ListElement) glfs_list;
+static QLIST_HEAD(, ListElement) glfs_list;
static QemuOptsList qemu_gluster_create_opts = {
.name = "qemu-gluster-create-opts",
diff --git a/block/iscsi.c b/block/iscsi.c
index 727dee50bf..ff473206e6 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -49,7 +49,9 @@
/* Conflict between scsi/utils.h and libiscsi! :( */
#define SCSI_XFER_NONE ISCSI_XFER_NONE
#include <iscsi/iscsi.h>
+#define inline __attribute__((gnu_inline)) /* required for libiscsi v1.9.0 */
#include <iscsi/scsi-lowlevel.h>
+#undef inline
#undef SCSI_XFER_NONE
QEMU_BUILD_BUG_ON((int)SCSI_XFER_NONE != (int)ISCSI_XFER_NONE);
@@ -117,7 +119,6 @@ typedef struct IscsiAIOCB {
QEMUBH *bh;
IscsiLun *iscsilun;
struct scsi_task *task;
- uint8_t *buf;
int status;
int64_t sector_num;
int nb_sectors;
@@ -125,6 +126,7 @@ typedef struct IscsiAIOCB {
#ifdef __linux__
sg_io_hdr_t *ioh;
#endif
+ bool cancelled;
} IscsiAIOCB;
/* libiscsi uses time_t so its enough to process events every second */
@@ -150,9 +152,6 @@ iscsi_bh_cb(void *p)
qemu_bh_delete(acb->bh);
- g_free(acb->buf);
- acb->buf = NULL;
-
acb->common.cb(acb->common.opaque, acb->status);
if (acb->task != NULL) {
@@ -291,14 +290,20 @@ static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask)
};
}
+/* Called (via iscsi_service) with QemuMutex held. */
static void
iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
void *private_data)
{
IscsiAIOCB *acb = private_data;
- acb->status = -ECANCELED;
- iscsi_schedule_bh(acb);
+ /* If the command callback hasn't been called yet, drop the task */
+ if (!acb->bh) {
+ /* Call iscsi_aio_ioctl_cb() with SCSI_STATUS_CANCELLED */
+ iscsi_scsi_cancel_task(iscsi, acb->task);
+ }
+
+ qemu_aio_unref(acb); /* acquired in iscsi_aio_cancel() */
}
static void
@@ -307,14 +312,25 @@ iscsi_aio_cancel(BlockAIOCB *blockacb)
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
IscsiLun *iscsilun = acb->iscsilun;
- if (acb->status != -EINPROGRESS) {
+ qemu_mutex_lock(&iscsilun->mutex);
+
+ /* If it was cancelled or completed already, our work is done here */
+ if (acb->cancelled || acb->status != -EINPROGRESS) {
+ qemu_mutex_unlock(&iscsilun->mutex);
return;
}
+ acb->cancelled = true;
+
+ qemu_aio_ref(acb); /* released in iscsi_abort_task_cb() */
+
/* send a task mgmt call to the target to cancel the task on the target */
- iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
- iscsi_abort_task_cb, acb);
+ if (iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
+ iscsi_abort_task_cb, acb) < 0) {
+ qemu_aio_unref(acb); /* since iscsi_abort_task_cb() won't be called */
+ }
+ qemu_mutex_unlock(&iscsilun->mutex);
}
static const AIOCBInfo iscsi_aiocb_info = {
@@ -348,6 +364,8 @@ static void iscsi_timed_check_events(void *opaque)
{
IscsiLun *iscsilun = opaque;
+ qemu_mutex_lock(&iscsilun->mutex);
+
/* check for timed out requests */
iscsi_service(iscsilun->iscsi, 0);
@@ -360,6 +378,8 @@ static void iscsi_timed_check_events(void *opaque)
* to return to service once this situation changes. */
iscsi_set_events(iscsilun);
+ qemu_mutex_unlock(&iscsilun->mutex);
+
timer_mod(iscsilun->event_timer,
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + EVENT_INTERVAL);
}
@@ -933,8 +953,13 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
{
IscsiAIOCB *acb = opaque;
- g_free(acb->buf);
- acb->buf = NULL;
+ if (status == SCSI_STATUS_CANCELLED) {
+ if (!acb->bh) {
+ acb->status = -ECANCELED;
+ iscsi_schedule_bh(acb);
+ }
+ return;
+ }
acb->status = 0;
if (status < 0) {
@@ -1010,8 +1035,8 @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
acb->iscsilun = iscsilun;
acb->bh = NULL;
acb->status = -EINPROGRESS;
- acb->buf = NULL;
acb->ioh = buf;
+ acb->cancelled = false;
if (req != SG_IO) {
iscsi_ioctl_handle_emulated(acb, req, buf);
diff --git a/block/linux-aio.c b/block/linux-aio.c
index 217ce60138..d4b61fb251 100644
--- a/block/linux-aio.c
+++ b/block/linux-aio.c
@@ -384,10 +384,10 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
switch (type) {
case QEMU_AIO_WRITE:
io_prep_pwritev(iocbs, fd, qiov->iov, qiov->niov, offset);
- break;
+ break;
case QEMU_AIO_READ:
io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
- break;
+ break;
/* Currently Linux kernel does not support other operations */
default:
fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
diff --git a/block/mirror.c b/block/mirror.c
index 8f52c6215d..24ede6fdaa 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -72,7 +72,7 @@ typedef struct MirrorBlockJob {
unsigned long *in_flight_bitmap;
int in_flight;
int64_t bytes_in_flight;
- QTAILQ_HEAD(MirrorOpList, MirrorOp) ops_in_flight;
+ QTAILQ_HEAD(, MirrorOp) ops_in_flight;
int ret;
bool unmap;
int target_cluster_size;
@@ -277,7 +277,8 @@ static int mirror_cow_align(MirrorBlockJob *s, int64_t *offset,
return ret;
}
-static inline void mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
+static inline void coroutine_fn
+mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
{
MirrorOp *op;
@@ -295,7 +296,8 @@ static inline void mirror_wait_for_any_operation(MirrorBlockJob *s, bool active)
abort();
}
-static inline void mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s)
+static inline void coroutine_fn
+mirror_wait_for_free_in_flight_slot(MirrorBlockJob *s)
{
/* Only non-active operations use up in-flight slots */
mirror_wait_for_any_operation(s, false);
@@ -598,7 +600,7 @@ static void mirror_free_init(MirrorBlockJob *s)
* mirror_resume() because mirror_run() will begin iterating again
* when the job is resumed.
*/
-static void mirror_wait_for_all_io(MirrorBlockJob *s)
+static void coroutine_fn mirror_wait_for_all_io(MirrorBlockJob *s)
{
while (s->in_flight > 0) {
mirror_wait_for_free_in_flight_slot(s);
@@ -669,9 +671,10 @@ static int mirror_exit_common(Job *job)
if (s->should_complete && !abort) {
BlockDriverState *to_replace = s->to_replace ?: src;
+ bool ro = bdrv_is_read_only(to_replace);
- if (bdrv_get_flags(target_bs) != bdrv_get_flags(to_replace)) {
- bdrv_reopen(target_bs, bdrv_get_flags(to_replace), NULL);
+ if (ro != bdrv_is_read_only(target_bs)) {
+ bdrv_reopen_set_read_only(target_bs, ro, NULL);
}
/* The mirror job has no requests in flight any more, but we need to
@@ -731,7 +734,7 @@ static void mirror_abort(Job *job)
assert(ret == 0);
}
-static void mirror_throttle(MirrorBlockJob *s)
+static void coroutine_fn mirror_throttle(MirrorBlockJob *s)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
@@ -1106,7 +1109,7 @@ static void mirror_complete(Job *job, Error **errp)
job_enter(job);
}
-static void mirror_pause(Job *job)
+static void coroutine_fn mirror_pause(Job *job)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
@@ -1177,29 +1180,28 @@ static const BlockJobDriver commit_active_job_driver = {
.drain = mirror_drain,
};
-static void do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
- uint64_t offset, uint64_t bytes,
- QEMUIOVector *qiov, int flags)
+static void coroutine_fn
+do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
+ uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov, int flags)
{
- BdrvDirtyBitmapIter *iter;
QEMUIOVector target_qiov;
- uint64_t dirty_offset;
- int dirty_bytes;
+ uint64_t dirty_offset = offset;
+ uint64_t dirty_bytes;
if (qiov) {
qemu_iovec_init(&target_qiov, qiov->niov);
}
- iter = bdrv_dirty_iter_new(job->dirty_bitmap);
- bdrv_set_dirty_iter(iter, offset);
-
while (true) {
bool valid_area;
int ret;
bdrv_dirty_bitmap_lock(job->dirty_bitmap);
- valid_area = bdrv_dirty_iter_next_area(iter, offset + bytes,
- &dirty_offset, &dirty_bytes);
+ dirty_bytes = MIN(offset + bytes - dirty_offset, INT_MAX);
+ valid_area = bdrv_dirty_bitmap_next_dirty_area(job->dirty_bitmap,
+ &dirty_offset,
+ &dirty_bytes);
if (!valid_area) {
bdrv_dirty_bitmap_unlock(job->dirty_bitmap);
break;
@@ -1255,9 +1257,10 @@ static void do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
break;
}
}
+
+ dirty_offset += dirty_bytes;
}
- bdrv_dirty_iter_free(iter);
if (qiov) {
qemu_iovec_destroy(&target_qiov);
}
@@ -1689,13 +1692,15 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque,
bool auto_complete, Error **errp)
{
- int orig_base_flags;
+ bool base_read_only;
Error *local_err = NULL;
- orig_base_flags = bdrv_get_flags(base);
+ base_read_only = bdrv_is_read_only(base);
- if (bdrv_reopen(base, bs->open_flags, errp)) {
- return;
+ if (base_read_only) {
+ if (bdrv_reopen_set_read_only(base, false, errp) < 0) {
+ return;
+ }
}
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
@@ -1714,6 +1719,8 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
error_restore_flags:
/* ignore error and errp for bdrv_reopen, because we want to propagate
* the original error */
- bdrv_reopen(base, orig_base_flags, NULL);
+ if (base_read_only) {
+ bdrv_reopen_set_read_only(base, true, NULL);
+ }
return;
}
diff --git a/block/nbd-client.c b/block/nbd-client.c
index fc5b7eda8e..813539676d 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -28,6 +28,8 @@
*/
#include "qemu/osdep.h"
+
+#include "trace.h"
#include "qapi/error.h"
#include "nbd-client.h"
@@ -79,7 +81,8 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
assert(s->reply.handle == 0);
ret = nbd_receive_reply(s->ioc, &s->reply, &local_err);
if (local_err) {
- error_report_err(local_err);
+ trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
+ error_free(local_err);
}
if (ret <= 0) {
break;
@@ -246,11 +249,11 @@ static int nbd_parse_blockstatus_payload(NBDClientSession *client,
}
context_id = payload_advance32(&payload);
- if (client->info.meta_base_allocation_id != context_id) {
+ if (client->info.context_id != context_id) {
error_setg(errp, "Protocol error: unexpected context id %d for "
"NBD_REPLY_TYPE_BLOCK_STATUS, when negotiated context "
"id is %d", context_id,
- client->info.meta_base_allocation_id);
+ client->info.context_id);
return -EINVAL;
}
@@ -771,7 +774,11 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request,
ret = nbd_co_receive_return_code(client, request->handle, &local_err);
if (local_err) {
- error_report_err(local_err);
+ trace_nbd_co_request_fail(request->from, request->len, request->handle,
+ request->flags, request->type,
+ nbd_cmd_lookup(request->type),
+ ret, error_get_pretty(local_err));
+ error_free(local_err);
}
return ret;
}
@@ -802,7 +809,11 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
ret = nbd_co_receive_cmdread_reply(client, request.handle, offset, qiov,
&local_err);
if (local_err) {
- error_report_err(local_err);
+ trace_nbd_co_request_fail(request.from, request.len, request.handle,
+ request.flags, request.type,
+ nbd_cmd_lookup(request.type),
+ ret, error_get_pretty(local_err));
+ error_free(local_err);
}
return ret;
}
@@ -925,7 +936,11 @@ int coroutine_fn nbd_client_co_block_status(BlockDriverState *bs,
ret = nbd_co_receive_blockstatus_reply(client, request.handle, bytes,
&extent, &local_err);
if (local_err) {
- error_report_err(local_err);
+ trace_nbd_co_request_fail(request.from, request.len, request.handle,
+ request.flags, request.type,
+ nbd_cmd_lookup(request.type),
+ ret, error_get_pretty(local_err));
+ error_free(local_err);
}
if (ret < 0) {
return ret;
@@ -984,10 +999,11 @@ int nbd_client_init(BlockDriverState *bs,
client->info.structured_reply = true;
client->info.base_allocation = true;
client->info.x_dirty_bitmap = g_strdup(x_dirty_bitmap);
- ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), export,
- tlscreds, hostname,
+ client->info.name = g_strdup(export ?: "");
+ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), tlscreds, hostname,
&client->ioc, &client->info, errp);
g_free(client->info.x_dirty_bitmap);
+ g_free(client->info.name);
if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
return ret;
diff --git a/block/nvme.c b/block/nvme.c
index 29294038fc..982097b5b1 100644
--- a/block/nvme.c
+++ b/block/nvme.c
@@ -837,7 +837,7 @@ try_map:
}
for (j = 0; j < qiov->iov[i].iov_len / s->page_size; j++) {
- pagelist[entries++] = iova + j * s->page_size;
+ pagelist[entries++] = cpu_to_le64(iova + j * s->page_size);
}
trace_nvme_cmd_map_qiov_iov(s, i, qiov->iov[i].iov_base,
qiov->iov[i].iov_len / s->page_size);
@@ -850,20 +850,16 @@ try_map:
case 0:
abort();
case 1:
- cmd->prp1 = cpu_to_le64(pagelist[0]);
+ cmd->prp1 = pagelist[0];
cmd->prp2 = 0;
break;
case 2:
- cmd->prp1 = cpu_to_le64(pagelist[0]);
- cmd->prp2 = cpu_to_le64(pagelist[1]);;
+ cmd->prp1 = pagelist[0];
+ cmd->prp2 = pagelist[1];
break;
default:
- cmd->prp1 = cpu_to_le64(pagelist[0]);
- cmd->prp2 = cpu_to_le64(req->prp_list_iova);
- for (i = 0; i < entries - 1; ++i) {
- pagelist[i] = cpu_to_le64(pagelist[i + 1]);
- }
- pagelist[entries - 1] = 0;
+ cmd->prp1 = pagelist[0];
+ cmd->prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
break;
}
trace_nvme_cmd_map_qiov(s, cmd, req, qiov, entries);
diff --git a/block/qcow.c b/block/qcow.c
index 4518cb4c35..0a235bf393 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -213,7 +213,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
s->crypto = qcrypto_block_open(crypto_opts, "encrypt.",
- NULL, NULL, cflags, errp);
+ NULL, NULL, cflags, 1, errp);
if (!s->crypto) {
ret = -EINVAL;
goto fail;
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index accebef4cf..b946301429 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -77,8 +77,6 @@ typedef struct Qcow2BitmapTable {
uint32_t size; /* number of 64bit entries */
QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry;
} Qcow2BitmapTable;
-typedef QSIMPLEQ_HEAD(Qcow2BitmapTableList, Qcow2BitmapTable)
- Qcow2BitmapTableList;
typedef struct Qcow2Bitmap {
Qcow2BitmapTable table;
@@ -1316,7 +1314,7 @@ void qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
int ret;
Qcow2BitmapList *bm_list;
Qcow2Bitmap *bm;
- Qcow2BitmapTableList drop_tables;
+ QSIMPLEQ_HEAD(, Qcow2BitmapTable) drop_tables;
Qcow2BitmapTable *tb, *tb_next;
if (!bdrv_has_changed_persistent_bitmaps(bs)) {
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d37fe08b3d..30eca26c47 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -402,7 +402,7 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size,
}
}
- return i;
+ return i;
}
/*
@@ -1571,76 +1571,6 @@ again:
return 0;
}
-static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
- const uint8_t *buf, int buf_size)
-{
- z_stream strm1, *strm = &strm1;
- int ret, out_len;
-
- memset(strm, 0, sizeof(*strm));
-
- strm->next_in = (uint8_t *)buf;
- strm->avail_in = buf_size;
- strm->next_out = out_buf;
- strm->avail_out = out_buf_size;
-
- ret = inflateInit2(strm, -12);
- if (ret != Z_OK)
- return -1;
- ret = inflate(strm, Z_FINISH);
- out_len = strm->next_out - out_buf;
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
- out_len != out_buf_size) {
- inflateEnd(strm);
- return -1;
- }
- inflateEnd(strm);
- return 0;
-}
-
-int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
-{
- BDRVQcow2State *s = bs->opaque;
- int ret, csize, nb_csectors, sector_offset;
- uint64_t coffset;
-
- coffset = cluster_offset & s->cluster_offset_mask;
- if (s->cluster_cache_offset != coffset) {
- nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
- sector_offset = coffset & 511;
- csize = nb_csectors * 512 - sector_offset;
-
- /* Allocate buffers on first decompress operation, most images are
- * uncompressed and the memory overhead can be avoided. The buffers
- * are freed in .bdrv_close().
- */
- if (!s->cluster_data) {
- /* one more sector for decompressed data alignment */
- s->cluster_data = qemu_try_blockalign(bs->file->bs,
- QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512);
- if (!s->cluster_data) {
- return -ENOMEM;
- }
- }
- if (!s->cluster_cache) {
- s->cluster_cache = g_malloc(s->cluster_size);
- }
-
- BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
- ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data,
- nb_csectors);
- if (ret < 0) {
- return ret;
- }
- if (decompress_buffer(s->cluster_cache, s->cluster_size,
- s->cluster_data + sector_offset, csize) < 0) {
- return -EIO;
- }
- s->cluster_cache_offset = coffset;
- }
- return 0;
-}
-
/*
* This discards as many clusters of nb_clusters as possible at once (i.e.
* all clusters in the same L2 slice) and returns the number of discarded
diff --git a/block/qcow2.c b/block/qcow2.c
index 991d6ac91b..4897abae5e 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -74,6 +74,13 @@ typedef struct {
#define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77
#define QCOW2_EXT_MAGIC_BITMAPS 0x23852875
+static int coroutine_fn
+qcow2_co_preadv_compressed(BlockDriverState *bs,
+ uint64_t file_cluster_offset,
+ uint64_t offset,
+ uint64_t bytes,
+ QEMUIOVector *qiov);
+
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const QCowHeader *cow_header = (const void *)buf;
@@ -294,7 +301,7 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
}
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
qcow2_crypto_hdr_read_func,
- bs, cflags, errp);
+ bs, cflags, 1, errp);
if (!s->crypto) {
return -EINVAL;
}
@@ -1414,7 +1421,6 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
goto fail;
}
- s->cluster_cache_offset = -1;
s->flags = flags;
ret = qcow2_refcount_init(bs);
@@ -1445,7 +1451,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
}
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
- NULL, NULL, cflags, errp);
+ NULL, NULL, cflags, 1, errp);
if (!s->crypto) {
ret = -EINVAL;
goto fail;
@@ -1914,15 +1920,15 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
break;
case QCOW2_CLUSTER_COMPRESSED:
- /* add AIO support for compressed blocks ? */
- ret = qcow2_decompress_cluster(bs, cluster_offset);
+ qemu_co_mutex_unlock(&s->lock);
+ ret = qcow2_co_preadv_compressed(bs, cluster_offset,
+ offset, cur_bytes,
+ &hd_qiov);
+ qemu_co_mutex_lock(&s->lock);
if (ret < 0) {
goto fail;
}
- qemu_iovec_from_buf(&hd_qiov, 0,
- s->cluster_cache + offset_in_cluster,
- cur_bytes);
break;
case QCOW2_CLUSTER_NORMAL:
@@ -2058,8 +2064,6 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
qemu_iovec_init(&hd_qiov, qiov->niov);
- s->cluster_cache_offset = -1; /* disable compressed cache */
-
qemu_co_mutex_lock(&s->lock);
while (bytes != 0) {
@@ -2223,8 +2227,6 @@ static void qcow2_close(BlockDriverState *bs)
g_free(s->image_backing_file);
g_free(s->image_backing_format);
- g_free(s->cluster_cache);
- qemu_vfree(s->cluster_data);
qcow2_refcount_close(bs);
qcow2_free_snapshots(bs);
}
@@ -3401,7 +3403,6 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
QCowL2Meta *l2meta = NULL;
assert(!bs->encrypted);
- s->cluster_cache_offset = -1; /* disable compressed cache */
qemu_co_mutex_lock(&s->lock);
@@ -3722,14 +3723,15 @@ fail:
/*
* qcow2_compress()
*
- * @dest - destination buffer, at least of @size-1 bytes
- * @src - source buffer, @size bytes
+ * @dest - destination buffer, @dest_size bytes
+ * @src - source buffer, @src_size bytes
*
* Returns: compressed size on success
- * -1 if compression is inefficient
+ * -1 destination buffer is not enough to store compressed data
* -2 on any other error
*/
-static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
+static ssize_t qcow2_compress(void *dest, size_t dest_size,
+ const void *src, size_t src_size)
{
ssize_t ret;
z_stream strm;
@@ -3738,20 +3740,20 @@ static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
memset(&strm, 0, sizeof(strm));
ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-12, 9, Z_DEFAULT_STRATEGY);
- if (ret != 0) {
+ if (ret != Z_OK) {
return -2;
}
/* strm.next_in is not const in old zlib versions, such as those used on
* OpenBSD/NetBSD, so cast the const away */
- strm.avail_in = size;
+ strm.avail_in = src_size;
strm.next_in = (void *) src;
- strm.avail_out = size - 1;
+ strm.avail_out = dest_size;
strm.next_out = dest;
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_END) {
- ret = size - 1 - strm.avail_out;
+ ret = dest_size - strm.avail_out;
} else {
ret = (ret == Z_OK ? -1 : -2);
}
@@ -3761,20 +3763,68 @@ static ssize_t qcow2_compress(void *dest, const void *src, size_t size)
return ret;
}
+/*
+ * qcow2_decompress()
+ *
+ * Decompress some data (not more than @src_size bytes) to produce exactly
+ * @dest_size bytes.
+ *
+ * @dest - destination buffer, @dest_size bytes
+ * @src - source buffer, @src_size bytes
+ *
+ * Returns: 0 on success
+ * -1 on fail
+ */
+static ssize_t qcow2_decompress(void *dest, size_t dest_size,
+ const void *src, size_t src_size)
+{
+ int ret = 0;
+ z_stream strm;
+
+ memset(&strm, 0, sizeof(strm));
+ strm.avail_in = src_size;
+ strm.next_in = (void *) src;
+ strm.avail_out = dest_size;
+ strm.next_out = dest;
+
+ ret = inflateInit2(&strm, -12);
+ if (ret != Z_OK) {
+ return -1;
+ }
+
+ ret = inflate(&strm, Z_FINISH);
+ if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
+ /* We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
+ * @src buffer may be processed partly (because in qcow2 we know size of
+ * compressed data with precision of one sector) */
+ ret = -1;
+ }
+
+ inflateEnd(&strm);
+
+ return ret;
+}
+
#define MAX_COMPRESS_THREADS 4
+typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
+ const void *src, size_t src_size);
typedef struct Qcow2CompressData {
void *dest;
+ size_t dest_size;
const void *src;
- size_t size;
+ size_t src_size;
ssize_t ret;
+
+ Qcow2CompressFunc func;
} Qcow2CompressData;
static int qcow2_compress_pool_func(void *opaque)
{
Qcow2CompressData *data = opaque;
- data->ret = qcow2_compress(data->dest, data->src, data->size);
+ data->ret = data->func(data->dest, data->dest_size,
+ data->src, data->src_size);
return 0;
}
@@ -3784,17 +3834,19 @@ static void qcow2_compress_complete(void *opaque, int ret)
qemu_coroutine_enter(opaque);
}
-/* See qcow2_compress definition for parameters description */
-static ssize_t qcow2_co_compress(BlockDriverState *bs,
- void *dest, const void *src, size_t size)
+static ssize_t coroutine_fn
+qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
+ const void *src, size_t src_size, Qcow2CompressFunc func)
{
BDRVQcow2State *s = bs->opaque;
BlockAIOCB *acb;
ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
Qcow2CompressData arg = {
.dest = dest,
+ .dest_size = dest_size,
.src = src,
- .size = size,
+ .src_size = src_size,
+ .func = func,
};
while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
@@ -3817,6 +3869,22 @@ static ssize_t qcow2_co_compress(BlockDriverState *bs,
return arg.ret;
}
+static ssize_t coroutine_fn
+qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
+ const void *src, size_t src_size)
+{
+ return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
+ qcow2_compress);
+}
+
+static ssize_t coroutine_fn
+qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
+ const void *src, size_t src_size)
+{
+ return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
+ qcow2_decompress);
+}
+
/* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */
static coroutine_fn int
@@ -3861,7 +3929,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
out_buf = g_malloc(s->cluster_size);
- out_len = qcow2_co_compress(bs, out_buf, buf, s->cluster_size);
+ out_len = qcow2_co_compress(bs, out_buf, s->cluster_size - 1,
+ buf, s->cluster_size);
if (out_len == -2) {
ret = -EINVAL;
goto fail;
@@ -3909,6 +3978,55 @@ fail:
return ret;
}
+static int coroutine_fn
+qcow2_co_preadv_compressed(BlockDriverState *bs,
+ uint64_t file_cluster_offset,
+ uint64_t offset,
+ uint64_t bytes,
+ QEMUIOVector *qiov)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret = 0, csize, nb_csectors;
+ uint64_t coffset;
+ uint8_t *buf, *out_buf;
+ struct iovec iov;
+ QEMUIOVector local_qiov;
+ int offset_in_cluster = offset_into_cluster(s, offset);
+
+ coffset = file_cluster_offset & s->cluster_offset_mask;
+ nb_csectors = ((file_cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
+ csize = nb_csectors * 512 - (coffset & 511);
+
+ buf = g_try_malloc(csize);
+ if (!buf) {
+ return -ENOMEM;
+ }
+ iov.iov_base = buf;
+ iov.iov_len = csize;
+ qemu_iovec_init_external(&local_qiov, &iov, 1);
+
+ out_buf = qemu_blockalign(bs, s->cluster_size);
+
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
+ ret = bdrv_co_preadv(bs->file, coffset, csize, &local_qiov, 0);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ if (qcow2_co_decompress(bs, out_buf, s->cluster_size, buf, csize) < 0) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ qemu_iovec_from_buf(qiov, 0, out_buf + offset_in_cluster, bytes);
+
+fail:
+ qemu_vfree(out_buf);
+ g_free(buf);
+
+ return ret;
+}
+
static int make_completely_empty(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
diff --git a/block/qcow2.h b/block/qcow2.h
index 8662b68575..438a1dee9e 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -281,7 +281,7 @@ typedef struct BDRVQcow2State {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
- QLIST_HEAD(QCowClusterAlloc, QCowL2Meta) cluster_allocs;
+ QLIST_HEAD(, QCowL2Meta) cluster_allocs;
uint64_t *refcount_table;
uint64_t refcount_table_offset;
@@ -616,7 +616,6 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size);
int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
-int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
diff --git a/block/replication.c b/block/replication.c
index 6349d6958e..e70dd95001 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -20,6 +20,7 @@
#include "block/block_backup.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
#include "replication.h"
typedef enum {
@@ -39,8 +40,8 @@ typedef struct BDRVReplicationState {
char *top_id;
ReplicationState *rs;
Error *blocker;
- int orig_hidden_flags;
- int orig_secondary_flags;
+ bool orig_hidden_read_only;
+ bool orig_secondary_read_only;
int error;
} BDRVReplicationState;
@@ -218,9 +219,6 @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs,
QEMUIOVector *qiov)
{
BDRVReplicationState *s = bs->opaque;
- BdrvChild *child = s->secondary_disk;
- BlockJob *job = NULL;
- CowRequest req;
int ret;
if (s->mode == REPLICATION_MODE_PRIMARY) {
@@ -233,28 +231,9 @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs,
return ret;
}
- if (child && child->bs) {
- job = child->bs->job;
- }
-
- if (job) {
- uint64_t remaining_bytes = remaining_sectors * BDRV_SECTOR_SIZE;
-
- backup_wait_for_overlapping_requests(child->bs->job,
- sector_num * BDRV_SECTOR_SIZE,
- remaining_bytes);
- backup_cow_request_begin(&req, child->bs->job,
- sector_num * BDRV_SECTOR_SIZE,
- remaining_bytes);
- ret = bdrv_co_preadv(bs->file, sector_num * BDRV_SECTOR_SIZE,
- remaining_bytes, qiov, 0);
- backup_cow_request_end(&req);
- goto out;
- }
-
ret = bdrv_co_preadv(bs->file, sector_num * BDRV_SECTOR_SIZE,
remaining_sectors * BDRV_SECTOR_SIZE, qiov, 0);
-out:
+
return replication_return_value(s, ret);
}
@@ -371,44 +350,38 @@ static void secondary_do_checkpoint(BDRVReplicationState *s, Error **errp)
}
}
+/* This function is supposed to be called twice:
+ * first with writable = true, then with writable = false.
+ * The first call puts s->hidden_disk and s->secondary_disk in
+ * r/w mode, and the second puts them back in their original state.
+ */
static void reopen_backing_file(BlockDriverState *bs, bool writable,
Error **errp)
{
BDRVReplicationState *s = bs->opaque;
BlockReopenQueue *reopen_queue = NULL;
- int orig_hidden_flags, orig_secondary_flags;
- int new_hidden_flags, new_secondary_flags;
Error *local_err = NULL;
if (writable) {
- orig_hidden_flags = s->orig_hidden_flags =
- bdrv_get_flags(s->hidden_disk->bs);
- new_hidden_flags = (orig_hidden_flags | BDRV_O_RDWR) &
- ~BDRV_O_INACTIVE;
- orig_secondary_flags = s->orig_secondary_flags =
- bdrv_get_flags(s->secondary_disk->bs);
- new_secondary_flags = (orig_secondary_flags | BDRV_O_RDWR) &
- ~BDRV_O_INACTIVE;
- } else {
- orig_hidden_flags = (s->orig_hidden_flags | BDRV_O_RDWR) &
- ~BDRV_O_INACTIVE;
- new_hidden_flags = s->orig_hidden_flags;
- orig_secondary_flags = (s->orig_secondary_flags | BDRV_O_RDWR) &
- ~BDRV_O_INACTIVE;
- new_secondary_flags = s->orig_secondary_flags;
+ s->orig_hidden_read_only = bdrv_is_read_only(s->hidden_disk->bs);
+ s->orig_secondary_read_only = bdrv_is_read_only(s->secondary_disk->bs);
}
bdrv_subtree_drained_begin(s->hidden_disk->bs);
bdrv_subtree_drained_begin(s->secondary_disk->bs);
- if (orig_hidden_flags != new_hidden_flags) {
- reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL,
- new_hidden_flags);
+ if (s->orig_hidden_read_only) {
+ QDict *opts = qdict_new();
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
+ reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs,
+ opts);
}
- if (!(orig_secondary_flags & BDRV_O_RDWR)) {
+ if (s->orig_secondary_read_only) {
+ QDict *opts = qdict_new();
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
- NULL, new_secondary_flags);
+ opts);
}
if (reopen_queue) {
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 0125df9d49..ed14f7afbe 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -391,12 +391,12 @@ struct BDRVSheepdogState {
uint32_t aioreq_seq_num;
/* Every aio request must be linked to either of these queues. */
- QLIST_HEAD(inflight_aio_head, AIOReq) inflight_aio_head;
- QLIST_HEAD(failed_aio_head, AIOReq) failed_aio_head;
+ QLIST_HEAD(, AIOReq) inflight_aio_head;
+ QLIST_HEAD(, AIOReq) failed_aio_head;
CoMutex queue_lock;
CoQueue overlapping_queue;
- QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
+ QLIST_HEAD(, SheepdogAIOCB) inflight_aiocb_head;
};
typedef struct BDRVSheepdogReopenState {
@@ -1224,7 +1224,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
SheepdogVdiReq hdr;
SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
unsigned int wlen, rlen = 0;
- char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+ char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN] QEMU_NONSTRING;
fd = connect_to_sdog(s, errp);
if (fd < 0) {
diff --git a/block/stream.c b/block/stream.c
index 81a7ec8ece..7a49ac0992 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -34,7 +34,7 @@ typedef struct StreamBlockJob {
BlockDriverState *base;
BlockdevOnError on_error;
char *backing_file_str;
- int bs_flags;
+ bool bs_read_only;
} StreamBlockJob;
static int coroutine_fn stream_populate(BlockBackend *blk,
@@ -89,10 +89,10 @@ static void stream_clean(Job *job)
BlockDriverState *bs = blk_bs(bjob->blk);
/* Reopen the image back in read-only mode if necessary */
- if (s->bs_flags != bdrv_get_flags(bs)) {
+ if (s->bs_read_only) {
/* Give up write permissions before making it read-only */
blk_set_perm(bjob->blk, 0, BLK_PERM_ALL, &error_abort);
- bdrv_reopen(bs, s->bs_flags, NULL);
+ bdrv_reopen_set_read_only(bs, true, NULL);
}
g_free(s->backing_file_str);
@@ -226,12 +226,12 @@ void stream_start(const char *job_id, BlockDriverState *bs,
{
StreamBlockJob *s;
BlockDriverState *iter;
- int orig_bs_flags;
+ bool bs_read_only;
/* Make sure that the image is opened in read-write mode */
- orig_bs_flags = bdrv_get_flags(bs);
- if (!(orig_bs_flags & BDRV_O_RDWR)) {
- if (bdrv_reopen(bs, orig_bs_flags | BDRV_O_RDWR, errp) != 0) {
+ bs_read_only = bdrv_is_read_only(bs);
+ if (bs_read_only) {
+ if (bdrv_reopen_set_read_only(bs, false, errp) != 0) {
return;
}
}
@@ -261,7 +261,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
s->base = base;
s->backing_file_str = g_strdup(backing_file_str);
- s->bs_flags = orig_bs_flags;
+ s->bs_read_only = bs_read_only;
s->on_error = on_error;
trace_stream_start(bs, base, s);
@@ -269,7 +269,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
return;
fail:
- if (orig_bs_flags != bdrv_get_flags(bs)) {
- bdrv_reopen(bs, orig_bs_flags, NULL);
+ if (bs_read_only) {
+ bdrv_reopen_set_read_only(bs, true, NULL);
}
}
diff --git a/block/trace-events b/block/trace-events
index 3e8c47bb24..693c14c443 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ -156,3 +156,7 @@ nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pa
# block/iscsi.c
iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, uint64_t bytes, int ret) "src_lun %p offset %"PRIu64" dst_lun %p offset %"PRIu64" bytes %"PRIu64" ret %d"
+
+# block/nbd-client.c
+nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s"
+nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s"
diff --git a/block/vhdx.h b/block/vhdx.h
index 3a5f5293ad..1bfb4e4f73 100644
--- a/block/vhdx.h
+++ b/block/vhdx.h
@@ -398,7 +398,7 @@ typedef struct BDRVVHDXState {
bool log_replayed_on_open;
- QLIST_HEAD(VHDXRegionHead, VHDXRegionEntry) regions;
+ QLIST_HEAD(, VHDXRegionEntry) regions;
} BDRVVHDXState;
void vhdx_guid_generate(MSGUID *guid);
diff --git a/block/vpc.c b/block/vpc.c
index 80c5b2b197..d886465b7e 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -187,7 +187,7 @@ static uint32_t vpc_checksum(uint8_t* buf, size_t size)
static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
- return 100;
+ return 100;
return 0;
}
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 1d170c80b8..d73ac1b026 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -140,11 +140,13 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
}
void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
- bool has_writable, bool writable, Error **errp)
+ bool has_writable, bool writable,
+ bool has_bitmap, const char *bitmap, Error **errp)
{
BlockDriverState *bs = NULL;
BlockBackend *on_eject_blk;
NBDExport *exp;
+ int64_t len;
if (!nbd_server) {
error_setg(errp, "NBD server not running");
@@ -167,6 +169,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
return;
}
+ len = bdrv_getlength(bs);
+ if (len < 0) {
+ error_setg_errno(errp, -len,
+ "Failed to determine the NBD export's length");
+ return;
+ }
+
if (!has_writable) {
writable = false;
}
@@ -174,14 +183,13 @@ void qmp_nbd_server_add(const char *device, bool has_name, const char *name,
writable = false;
}
- exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY,
+ exp = nbd_export_new(bs, 0, len, name, NULL, bitmap,
+ writable ? 0 : NBD_FLAG_READ_ONLY,
NULL, false, on_eject_blk, errp);
if (!exp) {
return;
}
- nbd_export_set_name(exp, name);
-
/* The list of named exports has a strong reference to this export now and
* our only way of accessing it is through nbd_export_find(), so we can drop
* the strong reference that is @exp. */
@@ -214,31 +222,13 @@ void qmp_nbd_server_remove(const char *name,
void qmp_nbd_server_stop(Error **errp)
{
- nbd_export_close_all();
-
- nbd_server_free(nbd_server);
- nbd_server = NULL;
-}
-
-void qmp_x_nbd_server_add_bitmap(const char *name, const char *bitmap,
- bool has_bitmap_export_name,
- const char *bitmap_export_name,
- Error **errp)
-{
- NBDExport *exp;
-
if (!nbd_server) {
error_setg(errp, "NBD server not running");
return;
}
- exp = nbd_export_find(name);
- if (exp == NULL) {
- error_setg(errp, "Export '%s' is not found", name);
- return;
- }
+ nbd_export_close_all();
- nbd_export_bitmap(exp, bitmap,
- has_bitmap_export_name ? bitmap_export_name : bitmap,
- errp);
+ nbd_server_free(nbd_server);
+ nbd_server = NULL;
}
diff --git a/blockdev.c b/blockdev.c
index 81f95d920b..a8fa8748a9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -992,9 +992,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
blk = blockdev_init(filename, bs_opts, &local_err);
bs_opts = NULL;
if (!blk) {
- if (local_err) {
- error_propagate(errp, local_err);
- }
+ error_propagate(errp, local_err);
goto fail;
} else {
assert(!local_err);
@@ -1341,7 +1339,7 @@ struct BlkActionState {
const BlkActionOps *ops;
JobTxn *block_job_txn;
TransactionProperties *txn_props;
- QSIMPLEQ_ENTRY(BlkActionState) entry;
+ QTAILQ_ENTRY(BlkActionState) entry;
};
/* internal snapshot private data */
@@ -1703,8 +1701,7 @@ static void external_snapshot_commit(BlkActionState *common)
* bdrv_reopen_multiple() across all the entries at once, because we
* don't want to abort all of them if one of them fails the reopen */
if (!atomic_read(&state->old_bs->copy_on_read)) {
- bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
- NULL);
+ bdrv_reopen_set_read_only(state->old_bs, true, NULL);
}
aio_context_release(aio_context);
@@ -1966,7 +1963,7 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
action->has_granularity, action->granularity,
action->has_persistent, action->persistent,
action->has_autoload, action->autoload,
- action->has_x_disabled, action->x_disabled,
+ action->has_disabled, action->disabled,
&local_err);
if (!local_err) {
@@ -2051,7 +2048,7 @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common,
return;
}
- action = common->action->u.x_block_dirty_bitmap_enable.data;
+ action = common->action->u.block_dirty_bitmap_enable.data;
state->bitmap = block_dirty_bitmap_lookup(action->node,
action->name,
NULL,
@@ -2092,7 +2089,7 @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common,
return;
}
- action = common->action->u.x_block_dirty_bitmap_disable.data;
+ action = common->action->u.block_dirty_bitmap_disable.data;
state->bitmap = block_dirty_bitmap_lookup(action->node,
action->name,
NULL,
@@ -2122,33 +2119,28 @@ static void block_dirty_bitmap_disable_abort(BlkActionState *common)
}
}
+static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
+ const char *target,
+ strList *bitmaps,
+ HBitmap **backup,
+ Error **errp);
+
static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
Error **errp)
{
BlockDirtyBitmapMerge *action;
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
common, common);
- BdrvDirtyBitmap *merge_source;
if (action_check_completion_mode(common, errp) < 0) {
return;
}
- action = common->action->u.x_block_dirty_bitmap_merge.data;
- state->bitmap = block_dirty_bitmap_lookup(action->node,
- action->dst_name,
- &state->bs,
- errp);
- if (!state->bitmap) {
- return;
- }
-
- merge_source = bdrv_find_dirty_bitmap(state->bs, action->src_name);
- if (!merge_source) {
- return;
- }
+ action = common->action->u.block_dirty_bitmap_merge.data;
- bdrv_merge_dirty_bitmap(state->bitmap, merge_source, &state->backup, errp);
+ state->bitmap = do_block_dirty_bitmap_merge(action->node, action->target,
+ action->bitmaps, &state->backup,
+ errp);
}
static void abort_prepare(BlkActionState *common, Error **errp)
@@ -2212,17 +2204,17 @@ static const BlkActionOps actions[] = {
.commit = block_dirty_bitmap_free_backup,
.abort = block_dirty_bitmap_restore,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_ENABLE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_enable_prepare,
.abort = block_dirty_bitmap_enable_abort,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_DISABLE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_disable_prepare,
.abort = block_dirty_bitmap_disable_abort,
},
- [TRANSACTION_ACTION_KIND_X_BLOCK_DIRTY_BITMAP_MERGE] = {
+ [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE] = {
.instance_size = sizeof(BlockDirtyBitmapState),
.prepare = block_dirty_bitmap_merge_prepare,
.commit = block_dirty_bitmap_free_backup,
@@ -2269,8 +2261,8 @@ void qmp_transaction(TransactionActionList *dev_list,
BlkActionState *state, *next;
Error *local_err = NULL;
- QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;
- QSIMPLEQ_INIT(&snap_bdrv_states);
+ QTAILQ_HEAD(, BlkActionState) snap_bdrv_states;
+ QTAILQ_INIT(&snap_bdrv_states);
/* Does this transaction get canceled as a group on failure?
* If not, we don't really need to make a JobTxn.
@@ -2301,7 +2293,7 @@ void qmp_transaction(TransactionActionList *dev_list,
state->action = dev_info;
state->block_job_txn = block_job_txn;
state->txn_props = props;
- QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
+ QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
state->ops->prepare(state, &local_err);
if (local_err) {
@@ -2310,7 +2302,7 @@ void qmp_transaction(TransactionActionList *dev_list,
}
}
- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+ QTAILQ_FOREACH(state, &snap_bdrv_states, entry) {
if (state->ops->commit) {
state->ops->commit(state);
}
@@ -2321,13 +2313,13 @@ void qmp_transaction(TransactionActionList *dev_list,
delete_and_fail:
/* failure, and it is all-or-none; roll back all operations */
- QSIMPLEQ_FOREACH(state, &snap_bdrv_states, entry) {
+ QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, entry) {
if (state->ops->abort) {
state->ops->abort(state);
}
}
exit:
- QSIMPLEQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
+ QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
if (state->ops->clean) {
state->ops->clean(state);
}
@@ -2938,7 +2930,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
bdrv_clear_dirty_bitmap(bitmap, NULL);
}
-void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name,
+void qmp_block_dirty_bitmap_enable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
@@ -2959,7 +2951,7 @@ void qmp_x_block_dirty_bitmap_enable(const char *node, const char *name,
bdrv_enable_dirty_bitmap(bitmap);
}
-void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name,
+void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
Error **errp)
{
BlockDriverState *bs;
@@ -2980,24 +2972,56 @@ void qmp_x_block_dirty_bitmap_disable(const char *node, const char *name,
bdrv_disable_dirty_bitmap(bitmap);
}
-void qmp_x_block_dirty_bitmap_merge(const char *node, const char *dst_name,
- const char *src_name, Error **errp)
+static BdrvDirtyBitmap *do_block_dirty_bitmap_merge(const char *node,
+ const char *target,
+ strList *bitmaps,
+ HBitmap **backup,
+ Error **errp)
{
BlockDriverState *bs;
- BdrvDirtyBitmap *dst, *src;
+ BdrvDirtyBitmap *dst, *src, *anon;
+ strList *lst;
+ Error *local_err = NULL;
- dst = block_dirty_bitmap_lookup(node, dst_name, &bs, errp);
+ dst = block_dirty_bitmap_lookup(node, target, &bs, errp);
if (!dst) {
- return;
+ return NULL;
}
- src = bdrv_find_dirty_bitmap(bs, src_name);
- if (!src) {
- error_setg(errp, "Dirty bitmap '%s' not found", src_name);
- return;
+ anon = bdrv_create_dirty_bitmap(bs, bdrv_dirty_bitmap_granularity(dst),
+ NULL, errp);
+ if (!anon) {
+ return NULL;
}
- bdrv_merge_dirty_bitmap(dst, src, NULL, errp);
+ for (lst = bitmaps; lst; lst = lst->next) {
+ src = bdrv_find_dirty_bitmap(bs, lst->value);
+ if (!src) {
+ error_setg(errp, "Dirty bitmap '%s' not found", lst->value);
+ dst = NULL;
+ goto out;
+ }
+
+ bdrv_merge_dirty_bitmap(anon, src, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ dst = NULL;
+ goto out;
+ }
+ }
+
+ /* Merge into dst; dst is unchanged on failure. */
+ bdrv_merge_dirty_bitmap(dst, anon, backup, errp);
+
+ out:
+ bdrv_release_dirty_bitmap(bs, anon);
+ return dst;
+}
+
+void qmp_block_dirty_bitmap_merge(const char *node, const char *target,
+ strList *bitmaps, Error **errp)
+{
+ do_block_dirty_bitmap_merge(node, target, bitmaps, NULL, errp);
}
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
@@ -4100,7 +4124,6 @@ void qmp_change_backing_file(const char *device,
BlockDriverState *image_bs = NULL;
Error *local_err = NULL;
bool ro;
- int open_flags;
int ret;
bs = qmp_get_root_bs(device, errp);
@@ -4142,13 +4165,10 @@ void qmp_change_backing_file(const char *device,
}
/* if not r/w, reopen to make r/w */
- open_flags = image_bs->open_flags;
ro = bdrv_is_read_only(image_bs);
if (ro) {
- bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (bdrv_reopen_set_read_only(image_bs, false, errp) != 0) {
goto out;
}
}
@@ -4164,7 +4184,7 @@ void qmp_change_backing_file(const char *device,
}
if (ro) {
- bdrv_reopen(image_bs, open_flags, &local_err);
+ bdrv_reopen_set_read_only(image_bs, true, &local_err);
error_propagate(errp, local_err);
}
@@ -4259,7 +4279,7 @@ void qmp_blockdev_del(const char *node_name, Error **errp)
goto out;
}
- if (!bs->monitor_list.tqe_prev) {
+ if (!QTAILQ_IN_USE(bs, monitor_list)) {
error_setg(errp, "Node %s is not owned by the monitor",
bs->node_name);
goto out;
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 7cccf3eb8b..32378af7b2 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1367,7 +1367,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
if (!have_guest_base) {
/*
* Go through ELF program header table and find out whether
- * any of the segments drop below our current mmap_min_addr and
+ * any of the segments drop below our current mmap_min_addr and
* in that case set guest_base to corresponding address.
*/
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
diff --git a/bsd-user/x86_64/target_syscall.h b/bsd-user/x86_64/target_syscall.h
index 211ce29e90..a5d779884f 100644
--- a/bsd-user/x86_64/target_syscall.h
+++ b/bsd-user/x86_64/target_syscall.h
@@ -12,7 +12,7 @@ struct target_pt_regs {
abi_ulong rbp;
abi_ulong rbx;
/* arguments: non interrupts/non tracing syscalls only save up to here */
- abi_ulong r11;
+ abi_ulong r11;
abi_ulong r10;
abi_ulong r9;
abi_ulong r8;
diff --git a/chardev/char.c b/chardev/char.c
index 152dde5327..ccba36bafb 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -193,6 +193,8 @@ void qemu_chr_be_update_read_handlers(Chardev *s,
{
ChardevClass *cc = CHARDEV_GET_CLASS(s);
+ assert(qemu_chr_has_feature(s, QEMU_CHAR_FEATURE_GCONTEXT)
+ || !context);
s->gcontext = context;
if (cc->chr_update_read_handler) {
cc->chr_update_read_handler(s);
@@ -240,6 +242,15 @@ static void char_init(Object *obj)
chr->logfd = -1;
qemu_mutex_init(&chr->chr_write_lock);
+
+ /*
+ * Assume if chr_update_read_handler is implemented it will
+ * take the updated gcontext into account.
+ */
+ if (CHARDEV_GET_CLASS(chr)->chr_update_read_handler) {
+ qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT);
+ }
+
}
static int null_chr_write(Chardev *chr, const uint8_t *buf, int len)
diff --git a/chardev/spice.c b/chardev/spice.c
index e66e3ad568..173c257949 100644
--- a/chardev/spice.c
+++ b/chardev/spice.c
@@ -77,7 +77,6 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
return bytes;
}
-#if SPICE_SERVER_VERSION >= 0x000c02
static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
{
SpiceChardev *scd = container_of(sin, SpiceChardev, sin);
@@ -95,7 +94,6 @@ static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
trace_spice_vmc_event(chr_event);
qemu_chr_be_event(chr, chr_event);
}
-#endif
static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
{
@@ -119,9 +117,7 @@ static SpiceCharDeviceInterface vmc_interface = {
.state = vmc_state,
.write = vmc_write,
.read = vmc_read,
-#if SPICE_SERVER_VERSION >= 0x000c02
.event = vmc_event,
-#endif
#if SPICE_SERVER_VERSION >= 0x000c06
.flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE,
#endif
@@ -223,9 +219,7 @@ static void char_spice_finalize(Object *obj)
}
g_free((char *)s->sin.subtype);
-#if SPICE_SERVER_VERSION >= 0x000c02
g_free((char *)s->sin.portname);
-#endif
}
static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
@@ -240,7 +234,6 @@ static void spice_vmc_set_fe_open(struct Chardev *chr, int fe_open)
static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
{
-#if SPICE_SERVER_VERSION >= 0x000c02
SpiceChardev *s = SPICE_CHARDEV(chr);
if (fe_open) {
@@ -248,7 +241,6 @@ static void spice_port_set_fe_open(struct Chardev *chr, int fe_open)
} else {
spice_server_port_event(&s->sin, SPICE_PORT_EVENT_CLOSED);
}
-#endif
}
static void spice_chr_accept_input(struct Chardev *chr)
@@ -298,7 +290,6 @@ static void qemu_chr_open_spice_vmc(Chardev *chr,
chr_open(chr, type);
}
-#if SPICE_SERVER_VERSION >= 0x000c02
static void qemu_chr_open_spice_port(Chardev *chr,
ChardevBackend *backend,
bool *be_opened,
@@ -331,7 +322,6 @@ void qemu_spice_register_ports(void)
vmc_register_interface(s);
}
}
-#endif
static void qemu_chr_parse_spice_vmc(QemuOpts *opts, ChardevBackend *backend,
Error **errp)
diff --git a/configure b/configure
index 0a3c6a72c3..8f312ac3e2 100755
--- a/configure
+++ b/configure
@@ -107,6 +107,9 @@ update_cxxflags() {
-Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\
-Wold-style-declaration|-Wold-style-definition|-Wredundant-decls)
;;
+ -std=gnu99)
+ QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }"-std=gnu++98"
+ ;;
*)
QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg
;;
@@ -346,6 +349,7 @@ fdt=""
netmap="no"
sdl=""
sdlabi=""
+sdl_image=""
virtfs=""
mpath=""
vnc="yes"
@@ -357,7 +361,6 @@ vnc_png=""
xkbcommon=""
xen=""
xen_ctrl_version=""
-xen_pv_domain_build="no"
xen_pci_passthrough=""
linux_aio=""
cap_ng=""
@@ -434,6 +437,7 @@ capstone=""
lzo=""
snappy=""
bzip2=""
+lzfse=""
guest_agent=""
guest_agent_with_vss="no"
guest_agent_ntddscsi="no"
@@ -584,7 +588,7 @@ ARFLAGS="${ARFLAGS-rv}"
# left shift of signed integers is well defined and has the expected
# 2s-complement style results. (Both clang and gcc agree that it
# provides these semantics.)
-QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv $QEMU_CFLAGS"
+QEMU_CFLAGS="-fno-strict-aliasing -fno-common -fwrapv -std=gnu99 $QEMU_CFLAGS"
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
@@ -709,6 +713,12 @@ elif check_define __s390__ ; then
else
cpu="s390"
fi
+elif check_define __riscv ; then
+ if check_define _LP64 ; then
+ cpu="riscv64"
+ else
+ cpu="riscv32"
+ fi
elif check_define __arm__ ; then
cpu="arm"
elif check_define __aarch64__ ; then
@@ -721,7 +731,7 @@ ARCH=
# Normalise host CPU name and set ARCH.
# Note that this case should only have supported host CPUs, not guests.
case "$cpu" in
- ppc|ppc64|s390|s390x|sparc64|x32)
+ ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64)
cpu="$cpu"
supported_cpu="yes"
eval "cross_cc_${cpu}=\$host_cc"
@@ -905,9 +915,6 @@ fi
if test "$mingw32" = "yes" ; then
EXESUF=".exe"
DSOSUF=".dll"
- QEMU_CFLAGS="-DWIN32_LEAN_AND_MEAN -DWINVER=0x501 $QEMU_CFLAGS"
- # enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
- QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
# MinGW needs -mthreads for TLS and macro _MT.
QEMU_CFLAGS="-mthreads $QEMU_CFLAGS"
LIBS="-lwinmm -lws2_32 -liphlpapi $LIBS"
@@ -1039,6 +1046,10 @@ for opt do
;;
--with-sdlabi=*) sdlabi="$optarg"
;;
+ --disable-sdl-image) sdl_image="no"
+ ;;
+ --enable-sdl-image) sdl_image="yes"
+ ;;
--disable-qom-cast-debug) qom_cast_debug="no"
;;
--enable-qom-cast-debug) qom_cast_debug="yes"
@@ -1115,10 +1126,6 @@ for opt do
;;
--enable-xen-pci-passthrough) xen_pci_passthrough="yes"
;;
- --disable-xen-pv-domain-build) xen_pv_domain_build="no"
- ;;
- --enable-xen-pv-domain-build) xen_pv_domain_build="yes"
- ;;
--disable-brlapi) brlapi="no"
;;
--enable-brlapi) brlapi="yes"
@@ -1310,6 +1317,10 @@ for opt do
;;
--enable-bzip2) bzip2="yes"
;;
+ --enable-lzfse) lzfse="yes"
+ ;;
+ --disable-lzfse) lzfse="no"
+ ;;
--enable-guest-agent) guest_agent="yes"
;;
--disable-guest-agent) guest_agent="no"
@@ -1677,8 +1688,6 @@ Advanced options (experts only):
--tls-priority default TLS protocol/cipher priority string
--enable-gprof QEMU profiling with gprof
--enable-profiler profiler support
- --enable-xen-pv-domain-build
- xen pv domain builder
--enable-debug-stack-usage
track the maximum stack usage of stacks created by qemu_alloc_stack
@@ -1703,6 +1712,7 @@ disabled with --disable-FEATURE, default is enabled if available:
gcrypt libgcrypt cryptography support
sdl SDL UI
--with-sdlabi select preferred SDL ABI 1.2 or 2.0
+ sdl_image SDL Image support for icons
gtk gtk UI
vte vte support for the gtk UI
curses curses UI
@@ -1745,6 +1755,8 @@ disabled with --disable-FEATURE, default is enabled if available:
snappy support of snappy compression library
bzip2 support of bzip2 compression library
(for reading bzip2-compressed dmg images)
+ lzfse support of lzfse compression library
+ (for reading lzfse-compressed dmg images)
seccomp seccomp support
coroutine-pool coroutine freelist (better performance)
glusterfs GlusterFS backend
@@ -1794,6 +1806,9 @@ if ! $python -c 'import sys; sys.exit(sys.version_info < (2,7))'; then
"Use --python=/path/to/python to specify a supported Python."
fi
+# Preserve python version since some functionality is dependent on it
+python_version=$($python -V 2>&1 | sed -e 's/Python\ //')
+
# Suppress writing compiled files
python="$python -B"
@@ -1840,6 +1855,31 @@ if test "$bogus_os" = "yes"; then
error_exit "Unrecognized host OS (uname -s reports '$(uname -s)')"
fi
+# Check whether the compiler matches our minimum requirements:
+cat > $TMPC << EOF
+#if defined(__clang_major__) && defined(__clang_minor__)
+# ifdef __apple_build_version__
+# if __clang_major__ < 5 || (__clang_major__ == 5 && __clang_minor__ < 1)
+# error You need at least XCode Clang v5.1 to compile QEMU
+# endif
+# else
+# if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 4)
+# error You need at least Clang v3.4 to compile QEMU
+# endif
+# endif
+#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
+# error You need at least GCC v4.8 to compile QEMU
+# endif
+#else
+# error You either need GCC or Clang to compiler QEMU
+#endif
+int main (void) { return 0; }
+EOF
+if ! compile_prog "" "" ; then
+ error_exit "You need at least GCC v4.8 or Clang v3.4 (or XCode Clang v5.1)"
+fi
+
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wno-missing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
@@ -1911,21 +1951,7 @@ else
QEMU_CFLAGS="$QEMU_CFLAGS -Wno-missing-braces"
fi
-# Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and
-# large functions that use global variables. The bug is in all releases of
-# GCC, but it became particularly acute in 4.6.x and 4.7.x. It is fixed in
-# 4.7.3 and 4.8.0. We should be able to delete this at the end of 2013.
-cat > $TMPC << EOF
-#if __GNUC__ == 4 && (__GNUC_MINOR__ == 6 || (__GNUC_MINOR__ == 7 && __GNUC_PATCHLEVEL__ <= 2))
-int main(void) { return 0; }
-#else
-#error No bug in this compiler.
-#endif
-EOF
-if compile_prog "-Werror -fno-gcse" "" ; then
- TRANSLATE_OPT_CFLAGS=-fno-gcse
-fi
-
+# Static linking is not possible with modules or PIE
if test "$static" = "yes" ; then
if test "$modules" = "yes" ; then
error_exit "static and modules are mutually incompatible"
@@ -2264,6 +2290,24 @@ EOF
fi
##########################################
+# lzfse check
+
+if test "$lzfse" != "no" ; then
+ cat > $TMPC << EOF
+#include <lzfse.h>
+int main(void) { lzfse_decode_scratch_size(); return 0; }
+EOF
+ if compile_prog "" "-llzfse" ; then
+ lzfse="yes"
+ else
+ if test "$lzfse" = "yes"; then
+ feature_not_found "lzfse" "Install lzfse devel"
+ fi
+ lzfse="no"
+ fi
+fi
+
+##########################################
# libseccomp check
libseccomp_minver="2.2.0"
@@ -2639,12 +2683,6 @@ if test "$xen_pci_passthrough" != "no"; then
fi
fi
-if test "$xen_pv_domain_build" = "yes" &&
- test "$xen" != "yes"; then
- error_exit "User requested Xen PV domain builder support" \
- "which requires Xen support."
-fi
-
##########################################
# Windows Hypervisor Platform accelerator (WHPX) check
if test "$whpx" != "no" ; then
@@ -2976,11 +3014,44 @@ EOF
fi # sdl compile test
}
+sdl_image_probe ()
+{
+ if test "$sdl_image" != "no" ; then
+ if $pkg_config SDL2_image --exists; then
+ if test "$static" = "yes"; then
+ sdl_image_libs=$($pkg_config SDL2_image --libs --static 2>/dev/null)
+ else
+ sdl_image_libs=$($pkg_config SDL2_image --libs 2>/dev/null)
+ fi
+ sdl_image_cflags=$($pkg_config SDL2_image --cflags 2>/dev/null)
+ sdl_image=yes
+
+ sdl_cflags="$sdl_cflags $sdl_image_cflags"
+ sdl_libs="$sdl_libs $sdl_image_libs"
+ else
+ if test "$sdl_image" = "yes" ; then
+ feature_not_found "sdl_image" "Install SDL Image devel"
+ else
+ sdl_image=no
+ fi
+ fi
+ fi
+}
+
if test "$sdl" != "no" ; then
sdl_probe
fi
if test "$sdl" = "yes" ; then
+ sdl_image_probe
+else
+ if test "$sdl_image" = "yes"; then
+ echo "warning: SDL Image requested, but SDL is not available, disabling"
+ fi
+ sdl_image=no
+fi
+
+if test "$sdl" = "yes" ; then
cat > $TMPC <<EOF
#include <SDL.h>
#if defined(SDL_VIDEO_DRIVER_X11)
@@ -3679,8 +3750,8 @@ if test "$mingw32" != yes -a "$pthread" = no; then
"Make sure to have the pthread libs and headers installed."
fi
-# check for pthread_setname_np
-pthread_setname_np=no
+# check for pthread_setname_np with thread id
+pthread_setname_np_w_tid=no
cat > $TMPC << EOF
#include <pthread.h>
@@ -3694,7 +3765,24 @@ int main(void)
}
EOF
if compile_prog "" "$pthread_lib" ; then
- pthread_setname_np=yes
+ pthread_setname_np_w_tid=yes
+fi
+
+# check for pthread_setname_np without thread id
+pthread_setname_np_wo_tid=no
+cat > $TMPC << EOF
+#include <pthread.h>
+
+static void *f(void *p) { pthread_setname_np("QEMU"); }
+int main(void)
+{
+ pthread_t thread;
+ pthread_create(&thread, 0, f, 0);
+ return 0;
+}
+EOF
+if compile_prog "" "$pthread_lib" ; then
+ pthread_setname_np_wo_tid=yes
fi
##########################################
@@ -3880,7 +3968,7 @@ if test "$fdt" != "no" ; then
cat > $TMPC << EOF
#include <libfdt.h>
#include <libfdt_env.h>
-int main(void) { fdt_first_subnode(0, 0); return 0; }
+int main(void) { fdt_check_full(NULL, 0); return 0; }
EOF
if compile_prog "" "$fdt_libs" ; then
# system DTC is good - use it
@@ -4563,7 +4651,7 @@ int main(void) { spice_server_new(); return 0; }
EOF
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
- if $pkg_config --atleast-version=0.12.0 spice-server && \
+ if $pkg_config --atleast-version=0.12.5 spice-server && \
$pkg_config --atleast-version=0.12.3 spice-protocol && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
@@ -4574,7 +4662,7 @@ EOF
else
if test "$spice" = "yes" ; then
feature_not_found "spice" \
- "Install spice-server(>=0.12.0) and spice-protocol(>=0.12.3) devel"
+ "Install spice-server(>=0.12.5) and spice-protocol(>=0.12.3) devel"
fi
spice="no"
fi
@@ -5123,11 +5211,6 @@ fi
int128=no
cat > $TMPC << EOF
-#if defined(__clang_major__) && defined(__clang_minor__)
-# if ((__clang_major__ < 3) || (__clang_major__ == 3) && (__clang_minor__ < 2))
-# error __int128_t does not work in CLANG before 3.2
-# endif
-#endif
__int128_t a;
__uint128_t b;
int main (void) {
@@ -5707,6 +5790,8 @@ qemu_confdir=$sysconfdir$confsuffix
qemu_moddir=$libdir$confsuffix
qemu_datadir=$datadir$confsuffix
qemu_localedir="$datadir/locale"
+qemu_icondir="$datadir/icons"
+qemu_desktopdir="$datadir/applications"
# We can only support ivshmem if we have eventfd
if [ "$eventfd" = "yes" ]; then
@@ -5851,8 +5936,12 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
roms="$roms spapr-rtas"
fi
+# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
if test "$cpu" = "s390x" ; then
- roms="$roms s390-ccw"
+ write_c_skeleton
+ if compile_prog "-march=z900" ""; then
+ roms="$roms s390-ccw"
+ fi
fi
# Probe for the need for relocating the user-only binary.
@@ -5972,7 +6061,7 @@ echo "LDFLAGS $LDFLAGS"
echo "QEMU_LDFLAGS $QEMU_LDFLAGS"
echo "make $make"
echo "install $install"
-echo "python $python"
+echo "python $python ($python_version)"
if test "$slirp" = "yes" ; then
echo "smbd $smbd"
fi
@@ -5989,6 +6078,7 @@ if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
fi
echo "SDL support $sdl $(echo_version $sdl $sdlversion)"
+echo "SDL image support $sdl_image"
echo "GTK support $gtk $(echo_version $gtk $gtk_version)"
echo "GTK GL support $gtk_gl"
echo "VTE support $vte $(echo_version $vte $vteversion)"
@@ -6018,7 +6108,6 @@ fi
echo "xen support $xen"
if test "$xen" = "yes" ; then
echo "xen ctrl version $xen_ctrl_version"
- echo "pv dom build $xen_pv_domain_build"
fi
echo "brlapi support $brlapi"
echo "bluez support $bluez"
@@ -6090,6 +6179,7 @@ echo "Live block migration $live_block_migration"
echo "lzo support $lzo"
echo "snappy support $snappy"
echo "bzip2 support $bzip2"
+echo "lzfse support $lzfse"
echo "NUMA host support $numa"
echo "libxml2 $libxml2"
echo "tcmalloc support $tcmalloc"
@@ -6172,6 +6262,8 @@ if test "$mingw32" = "no" ; then
fi
echo "qemu_helperdir=$libexecdir" >> $config_host_mak
echo "qemu_localedir=$qemu_localedir" >> $config_host_mak
+echo "qemu_icondir=$qemu_icondir" >> $config_host_mak
+echo "qemu_desktopdir=$qemu_desktopdir" >> $config_host_mak
echo "libs_softmmu=$libs_softmmu" >> $config_host_mak
echo "GIT=$git" >> $config_host_mak
echo "GIT_SUBMODULES=$git_submodules" >> $config_host_mak
@@ -6326,6 +6418,9 @@ if test "$sdl" = "yes" ; then
echo "CONFIG_SDLABI=$sdlabi" >> $config_host_mak
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
echo "SDL_LIBS=$sdl_libs" >> $config_host_mak
+ if test "$sdl_image" = "yes" ; then
+ echo "CONFIG_SDL_IMAGE=y" >> $config_host_mak
+ fi
fi
if test "$cocoa" = "yes" ; then
echo "CONFIG_COCOA=y" >> $config_host_mak
@@ -6487,9 +6582,6 @@ fi
if test "$xen" = "yes" ; then
echo "CONFIG_XEN_BACKEND=y" >> $config_host_mak
echo "CONFIG_XEN_CTRL_INTERFACE_VERSION=$xen_ctrl_version" >> $config_host_mak
- if test "$xen_pv_domain_build" = "yes" ; then
- echo "CONFIG_XEN_PV_DOMAIN_BUILD=y" >> $config_host_mak
- fi
fi
if test "$linux_aio" = "yes" ; then
echo "CONFIG_LINUX_AIO=y" >> $config_host_mak
@@ -6612,6 +6704,11 @@ if test "$bzip2" = "yes" ; then
echo "BZIP2_LIBS=-lbz2" >> $config_host_mak
fi
+if test "$lzfse" = "yes" ; then
+ echo "CONFIG_LZFSE=y" >> $config_host_mak
+ echo "LZFSE_LIBS=-llzfse" >> $config_host_mak
+fi
+
if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak
@@ -6846,11 +6943,14 @@ fi
# Hold two types of flag:
# CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on
# a thread we have a handle to
-# CONFIG_PTHREAD_SETNAME_NP - A way of doing it on a particular
+# CONFIG_PTHREAD_SETNAME_NP_W_TID - A way of doing it on a particular
# platform
-if test "$pthread_setname_np" = "yes" ; then
+if test "$pthread_setname_np_w_tid" = "yes" ; then
+ echo "CONFIG_THREAD_SETNAME_BYTHREAD=y" >> $config_host_mak
+ echo "CONFIG_PTHREAD_SETNAME_NP_W_TID=y" >> $config_host_mak
+elif test "$pthread_setname_np_wo_tid" = "yes" ; then
echo "CONFIG_THREAD_SETNAME_BYTHREAD=y" >> $config_host_mak
- echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
+ echo "CONFIG_PTHREAD_SETNAME_NP_WO_TID=y" >> $config_host_mak
fi
if test "$vxhs" = "yes" ; then
@@ -6900,6 +7000,8 @@ elif test "$ARCH" = "x86_64" -o "$ARCH" = "x32" ; then
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/i386 $QEMU_INCLUDES"
elif test "$ARCH" = "ppc64" ; then
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/ppc $QEMU_INCLUDES"
+elif test "$ARCH" = "riscv32" -o "$ARCH" = "riscv64" ; then
+ QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/riscv $QEMU_INCLUDES"
else
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/\$(ARCH) $QEMU_INCLUDES"
fi
@@ -6914,6 +7016,7 @@ echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak
echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak
echo "INSTALL_LIB=$install -c -m 0644" >> $config_host_mak
echo "PYTHON=$python" >> $config_host_mak
+echo "PYTHON_VERSION=$python_version" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
if $iasl -h > /dev/null 2>&1; then
echo "IASL=$iasl" >> $config_host_mak
@@ -6963,7 +7066,6 @@ echo "LIBS_QGA+=$libs_qga" >> $config_host_mak
echo "TASN1_LIBS=$tasn1_libs" >> $config_host_mak
echo "TASN1_CFLAGS=$tasn1_cflags" >> $config_host_mak
echo "POD2MAN=$POD2MAN" >> $config_host_mak
-echo "TRANSLATE_OPT_CFLAGS=$TRANSLATE_OPT_CFLAGS" >> $config_host_mak
if test "$gcov" = "yes" ; then
echo "CONFIG_GCOV=y" >> $config_host_mak
echo "GCOV=$gcov_tool" >> $config_host_mak
@@ -7397,7 +7499,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
ppc*)
disas_config "PPC"
;;
- riscv)
+ riscv*)
disas_config "RISCV"
;;
s390*)
@@ -7426,7 +7528,7 @@ alpha)
esac
if test "$gprof" = "yes" ; then
- echo "TARGET_GPROF=yes" >> $config_target_mak
+ echo "TARGET_GPROF=y" >> $config_target_mak
if test "$target_linux_user" = "yes" ; then
cflags="-p $cflags"
ldflags="-p $ldflags"
diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c
index 9b93dab662..7115b0d6d0 100644
--- a/contrib/elf2dmp/main.c
+++ b/contrib/elf2dmp/main.c
@@ -296,7 +296,7 @@ static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
static int fill_context(KDDEBUGGER_DATA64 *kdbg,
struct va_space *vs, QEMU_Elf *qe)
{
- int i;
+ int i;
for (i = 0; i < qe->state_nr; i++) {
uint64_t Prcb;
uint64_t Context;
diff --git a/contrib/elf2dmp/pdb.h b/contrib/elf2dmp/pdb.h
index 4351a2dd61..a3a3cac2c1 100644
--- a/contrib/elf2dmp/pdb.h
+++ b/contrib/elf2dmp/pdb.h
@@ -8,8 +8,6 @@
#ifndef PDB_H
#define PDB_H
-#include <stdint.h>
-#include <stdlib.h>
typedef struct GUID {
unsigned int Data1;
diff --git a/contrib/elf2dmp/pe.h b/contrib/elf2dmp/pe.h
index 374e06a9c5..dafb26afbb 100644
--- a/contrib/elf2dmp/pe.h
+++ b/contrib/elf2dmp/pe.h
@@ -8,7 +8,6 @@
#ifndef PE_H
#define PE_H
-#include <stdint.h>
typedef struct IMAGE_DOS_HEADER {
uint16_t e_magic; /* 0x00: MZ Header signature */
diff --git a/contrib/elf2dmp/qemu_elf.h b/contrib/elf2dmp/qemu_elf.h
index d85d6558fa..86e6e688fb 100644
--- a/contrib/elf2dmp/qemu_elf.h
+++ b/contrib/elf2dmp/qemu_elf.h
@@ -8,7 +8,6 @@
#ifndef QEMU_ELF_H
#define QEMU_ELF_H
-#include <stdint.h>
#include <elf.h>
typedef struct QEMUCPUSegment {
diff --git a/contrib/gitdm/aliases b/contrib/gitdm/aliases
new file mode 100644
index 0000000000..07fd3391a5
--- /dev/null
+++ b/contrib/gitdm/aliases
@@ -0,0 +1,27 @@
+#
+# This is the email aliases file, mapping secondary addresses
+# onto a single, canonical address. Duplicates some info from .mailmap
+#
+
+# weird commits
+balrog@c046a42c-6fe2-441c-8c8c-71466251a162 balrogg@gmail.com
+aliguori@c046a42c-6fe2-441c-8c8c-71466251a162 anthony@codemonkey.ws
+aurel32@c046a42c-6fe2-441c-8c8c-71466251a162 aurelien@aurel32.net
+blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162 blauwirbel@gmail.com
+edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162 edgar.iglesias@gmail.com
+bellard@c046a42c-6fe2-441c-8c8c-71466251a162 fabrice@bellard.org
+j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162 l_indien@magic.fr
+pbrook@c046a42c-6fe2-441c-8c8c-71466251a162 paul@codesourcery.com
+ths@c046a42c-6fe2-441c-8c8c-71466251a162 ths@networkno.de
+malc@c046a42c-6fe2-441c-8c8c-71466251a162 av1474@comtv.ru
+
+# There is also a:
+# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
+# for the cvs2svn initialization commit e63c3dc74bf.
+
+# Next, translate a few commits where mailman rewrote the From: line due
+# to strict SPF, although we prefer to avoid adding more entries like that.
+"Ed Swierk via Qemu-devel" eswierk@skyportsystems.com
+"Ian McKellar via Qemu-devel" ianloic@google.com
+"Julia Suvorova via Qemu-devel" jusual@mail.ru
+"Justin Terry (VM) via Qemu-devel" juterry@microsoft.com
diff --git a/contrib/gitdm/domain-map b/contrib/gitdm/domain-map
new file mode 100644
index 0000000000..0ab41ee27a
--- /dev/null
+++ b/contrib/gitdm/domain-map
@@ -0,0 +1,21 @@
+#
+# QEMU gitdm domain-map
+#
+# This maps email domains to nice easy to read company names
+#
+
+amd.com AMD
+greensocs.com GreenSocs
+ibm.com IBM
+igalia.com Igalia
+linaro.org Linaro
+nokia.com Nokia
+oracle.com Oracle
+proxmox.com Proxmox
+redhat.com Red Hat
+siemens.com Siemens
+sifive.com SiFive
+suse.de SUSE
+virtuozzo.com Virtuozzo
+wdc.com Western Digital
+xilinx.com Xilinx
diff --git a/contrib/gitdm/filetypes.txt b/contrib/gitdm/filetypes.txt
new file mode 100644
index 0000000000..15d6f803b9
--- /dev/null
+++ b/contrib/gitdm/filetypes.txt
@@ -0,0 +1,146 @@
+# -*- coding:utf-8 -*-
+# Copyright (C) 2006 Libresoft
+#
+# 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; either version 2 of the License, or
+# (at your option any later version.
+#
+# This program 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 Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Authors : Gregorio Robles <grex@gsyc.escet.urjc.es>
+# Authors : Germán Póo-Caamaño <gpoo@gnome.org>
+#
+# This QEMU version is a cut-down version of what originally shipped
+# in the gitdm sample-config directory.
+#
+# This file contains associations parameters regarding filetypes
+# (documentation, develompent, multimedia, images...)
+#
+# format:
+# filetype <type> <regex> [<comment>]
+#
+# Order:
+# The list should keep an order, so filetypes can be counted properly.
+# ie. we want ltmain.sh -> 'build' instead of 'code'.
+#
+# If there is an filetype which is not in order but has values, it will
+# be added at the end.
+#
+order build,tests,code,documentation,devel-doc,blobs
+
+#
+#
+# Code files (headers and the like included
+# (most common languages first
+#
+filetype code \.c$ # C
+filetype code \.inc.c$ # C
+filetype code \.C$ # C++
+filetype code \.cpp$ # C++
+filetype code \.c\+\+$ # C++
+filetype code \.cxx$ # C++
+filetype code \.cc$ # C++
+filetype code \.h$ # C or C++ header
+filetype code \.hh$ # C++ header
+filetype code \.hpp$ # C++ header
+filetype code \.hxx$ # C++ header
+filetype code \.sh$ # Shell
+filetype code \.pl$ # Perl
+filetype code \.py$ # Python
+filetype code \.s$ # Assembly
+filetype code \.S$ # Assembly
+filetype code \.asm$ # Assembly
+filetype code \.awk$ # awk
+filetype code ^common$ # script fragements
+filetype code ^common.*$ # script fragements
+filetype code (qom|qmp)-\w+$ # python script fragments
+
+#
+# Interface/api files
+#
+filetype interface \.json$ # json
+filetype interface \.hx$ # documented options
+
+#
+# Test related blobs (unfortunately we can't filter out test code)
+#
+filetype tests \.hex$
+filetype tests \d{2,3}$ # test data 00-999
+filetype tests ^[A-Z]{4}$ # ACPI test data
+filetype tests ^[A-Z]{4}\.*$ # ACPI test data
+filetype tests \.out$
+filetype tests \.out\.nocache$
+filetype tests \.err$
+filetype tests \.exit$ # bad-if-FOO.exit etc
+filetype tests \.decode$
+filetype tests \.yml$ # travis/shippable config
+
+#
+# Development documentation files (for hacking generally)
+#
+filetype devel-doc ^readme.*$
+filetype devel-doc ^changelog.*
+filetype devel-doc ^hacking.*$
+filetype devel-doc ^licen(s|c)e.*$
+filetype devel-doc ^copying.*$
+filetype devel-doc ^MAINTAINERS$
+filetype devel-doc ^BSD-2-Clause$
+filetype devel-doc ^BSD-3-Clause$
+filetype devel-doc ^GPL-2.0$
+filetype devel-doc \.txt$
+filetype devel-doc \.rst$
+filetype devel-doc \.texi$
+filetype devel-doc \.pod$
+
+#
+# Building, compiling, and configuration admin files
+#
+filetype build configure.*$
+filetype build Makefile$
+filetype build Makefile\.*$
+filetype build config$
+filetype build conf$
+filetype build \.cfg$
+filetype build \.mk$
+filetype build \.mak$
+filetype build \.docker$
+filetype build \.pre$
+filetype build ^.gitignore$
+filetype build ^.gitmodules$
+filetype build ^.gitpublish$
+filetype build ^.mailmap$
+filetype build ^.dir-locals.el$
+filetype build ^.editorconfig$
+filetype build ^.exrc$
+filetype build ^.gdbinit$
+filetype build \.cocci$ # Coccinelle semantic patches
+
+#
+# Misc blobs
+#
+filetype blobs \.bin$
+filetype blobs \.dtb$
+filetype blobs \.dts$
+filetype blobs \.rom$
+filetype blobs \.img$
+filetype blobs \.ndrv$
+filetype blobs \.bmp$
+filetype blobs \.svg$
+filetype blobs ^pi_10.com$
+
+
+#
+# Documentation files
+#
+filetype documentation \.html$
+filetype documentation \.txt$
+filetype documentation \.texi$
+filetype documentation \.po$ # translation files
diff --git a/contrib/gitdm/group-map-academics b/contrib/gitdm/group-map-academics
new file mode 100644
index 0000000000..08f9d81d13
--- /dev/null
+++ b/contrib/gitdm/group-map-academics
@@ -0,0 +1,14 @@
+#
+# QEMU is quite often used for academic research purposes and we like
+# it even better when the work is up-streamed so the project can
+# benefit.
+#
+# We group our academic contributors here
+#
+
+# Institute for System Programming of Russian Academy of Science
+ispras.ru
+
+# Columbia University
+cs.columbia.edu
+cota@braap.org
diff --git a/contrib/gitdm/group-map-cadence b/contrib/gitdm/group-map-cadence
new file mode 100644
index 0000000000..ab97dd2fc3
--- /dev/null
+++ b/contrib/gitdm/group-map-cadence
@@ -0,0 +1,3 @@
+# Cadence Design Systems
+
+jcmvbkbc@gmail.com
diff --git a/contrib/gitdm/group-map-codeweavers b/contrib/gitdm/group-map-codeweavers
new file mode 100644
index 0000000000..c4803489e2
--- /dev/null
+++ b/contrib/gitdm/group-map-codeweavers
@@ -0,0 +1 @@
+sergio.g.delreal@gmail.com
diff --git a/contrib/gitdm/group-map-ibm b/contrib/gitdm/group-map-ibm
new file mode 100644
index 0000000000..22727319b3
--- /dev/null
+++ b/contrib/gitdm/group-map-ibm
@@ -0,0 +1,13 @@
+#
+# Some IBM contributors submit via another domain
+#
+
+aik@ozlabs.ru
+andrew@aj.id.au
+benh@kernel.crashing.org
+clg@kaod.org
+danielhb413@gmail.com
+groug@kaod.org
+jcfaracco@gmail.com
+joel@jms.id.au
+sjitindarsingh@gmail.com
diff --git a/contrib/gitdm/group-map-individuals b/contrib/gitdm/group-map-individuals
new file mode 100644
index 0000000000..afdbe7d460
--- /dev/null
+++ b/contrib/gitdm/group-map-individuals
@@ -0,0 +1,10 @@
+#
+# Individual and personal contributors
+#
+# This is simply to allow prolific developers with no company
+# affiliations to be grouped together in the summary stats.
+#
+
+f4bug@amsat.org
+mjt@tls.msk.ru
+mark.cave-ayland@ilande.co.uk
diff --git a/contrib/gitdm/group-map-redhat b/contrib/gitdm/group-map-redhat
new file mode 100644
index 0000000000..6d05c6b54f
--- /dev/null
+++ b/contrib/gitdm/group-map-redhat
@@ -0,0 +1,7 @@
+#
+# Red Hat contributors using non-corporate email
+#
+
+david@gibson.dropbear.id.au
+laurent@vivier.eu
+pjp@fedoraproject.org
diff --git a/contrib/gitdm/group-map-wavecomp b/contrib/gitdm/group-map-wavecomp
new file mode 100644
index 0000000000..2801a966b6
--- /dev/null
+++ b/contrib/gitdm/group-map-wavecomp
@@ -0,0 +1,19 @@
+#
+# Wave Computing acquired MIPS in June 2018. Also, from February 2013
+# to October 2017, MIPS was owned by Imagination Technologies.
+#
+
+aleksandar.markovic@imgtec.com
+aleksandar.markovic@mips.com
+amarkovic@wavecomp.com
+arikalo@wavecomp.com
+dnikolic@wavecomp.com
+james.hogan@mips.com
+leon.alrae@imgtec.com
+matthew.fortune@mips.com
+paul.burton@imgtec.com
+pburton@wavecomp.com
+smarkovic@wavecomp.com
+yongbok.kim@imgtec.com
+yongbok.kim@mips.com
+ysu@wavecomp.com
diff --git a/contrib/ivshmem-client/ivshmem-client.h b/contrib/ivshmem-client/ivshmem-client.h
index 5ee942262b..fe3cc4a03d 100644
--- a/contrib/ivshmem-client/ivshmem-client.h
+++ b/contrib/ivshmem-client/ivshmem-client.h
@@ -46,9 +46,7 @@ typedef struct IvshmemClientPeer {
int vectors[IVSHMEM_CLIENT_MAX_VECTORS]; /**< one fd per vector */
unsigned vectors_count; /**< number of vectors */
} IvshmemClientPeer;
-QTAILQ_HEAD(IvshmemClientPeerList, IvshmemClientPeer);
-typedef struct IvshmemClientPeerList IvshmemClientPeerList;
typedef struct IvshmemClient IvshmemClient;
/**
@@ -73,7 +71,7 @@ struct IvshmemClient {
int sock_fd; /**< unix sock filedesc */
int shm_fd; /**< shm file descriptor */
- IvshmemClientPeerList peer_list; /**< list of peers */
+ QTAILQ_HEAD(, IvshmemClientPeer) peer_list; /**< list of peers */
IvshmemClientPeer local; /**< our own infos */
IvshmemClientNotifCb notif_cb; /**< notification callback */
diff --git a/contrib/ivshmem-server/ivshmem-server.h b/contrib/ivshmem-server/ivshmem-server.h
index 4af08e1bb7..d870adb6a0 100644
--- a/contrib/ivshmem-server/ivshmem-server.h
+++ b/contrib/ivshmem-server/ivshmem-server.h
@@ -52,9 +52,6 @@ typedef struct IvshmemServerPeer {
EventNotifier vectors[IVSHMEM_SERVER_MAX_VECTORS]; /**< one per vector */
unsigned vectors_count; /**< number of vectors */
} IvshmemServerPeer;
-QTAILQ_HEAD(IvshmemServerPeerList, IvshmemServerPeer);
-
-typedef struct IvshmemServerPeerList IvshmemServerPeerList;
/**
* Structure describing an ivshmem server
@@ -72,7 +69,7 @@ typedef struct IvshmemServer {
unsigned n_vectors; /**< number of vectors */
uint16_t cur_id; /**< id to be given to next client */
bool verbose; /**< true in verbose mode */
- IvshmemServerPeerList peer_list; /**< list of peers */
+ QTAILQ_HEAD(, IvshmemServerPeer) peer_list; /**< list of peers */
} IvshmemServer;
/**
diff --git a/contrib/rdmacm-mux/Makefile.objs b/contrib/rdmacm-mux/Makefile.objs
new file mode 100644
index 0000000000..3df744af89
--- /dev/null
+++ b/contrib/rdmacm-mux/Makefile.objs
@@ -0,0 +1,3 @@
+ifdef CONFIG_PVRDMA
+rdmacm-mux-obj-y = main.o
+endif
diff --git a/contrib/rdmacm-mux/main.c b/contrib/rdmacm-mux/main.c
new file mode 100644
index 0000000000..ae88c77a1e
--- /dev/null
+++ b/contrib/rdmacm-mux/main.c
@@ -0,0 +1,800 @@
+/*
+ * QEMU paravirtual RDMA - rdmacm-mux implementation
+ *
+ * Copyright (C) 2018 Oracle
+ * Copyright (C) 2018 Red Hat Inc
+ *
+ * Authors:
+ * Yuval Shaia <yuval.shaia@oracle.com>
+ * Marcel Apfelbaum <marcel@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 "qemu/osdep.h"
+#include "sys/poll.h"
+#include "sys/ioctl.h"
+#include "pthread.h"
+#include "syslog.h"
+
+#include "infiniband/verbs.h"
+#include "infiniband/umad.h"
+#include "infiniband/umad_types.h"
+#include "infiniband/umad_sa.h"
+#include "infiniband/umad_cm.h"
+
+#include "rdmacm-mux.h"
+
+#define SCALE_US 1000
+#define COMMID_TTL 2 /* How many SCALE_US a context of MAD session is saved */
+#define SLEEP_SECS 5 /* This is used both in poll() and thread */
+#define SERVER_LISTEN_BACKLOG 10
+#define MAX_CLIENTS 4096
+#define MAD_RMPP_VERSION 0
+#define MAD_METHOD_MASK0 0x8
+
+#define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof(long)))
+
+#define CM_REQ_DGID_POS 80
+#define CM_SIDR_REQ_DGID_POS 44
+
+/* The below can be override by command line parameter */
+#define UNIX_SOCKET_PATH "/var/run/rdmacm-mux"
+/* Has format %s-%s-%d" <path>-<rdma-dev--name>-<port> */
+#define SOCKET_PATH_MAX (PATH_MAX - NAME_MAX - sizeof(int) - 2)
+#define RDMA_PORT_NUM 1
+
+typedef struct RdmaCmServerArgs {
+ char unix_socket_path[PATH_MAX];
+ char rdma_dev_name[NAME_MAX];
+ int rdma_port_num;
+} RdmaCMServerArgs;
+
+typedef struct CommId2FdEntry {
+ int fd;
+ int ttl; /* Initialized to 2, decrement each timeout, entry delete when 0 */
+ __be64 gid_ifid;
+} CommId2FdEntry;
+
+typedef struct RdmaCmUMadAgent {
+ int port_id;
+ int agent_id;
+ GHashTable *gid2fd; /* Used to find fd of a given gid */
+ GHashTable *commid2fd; /* Used to find fd on of a given comm_id */
+} RdmaCmUMadAgent;
+
+typedef struct RdmaCmServer {
+ bool run;
+ RdmaCMServerArgs args;
+ struct pollfd fds[MAX_CLIENTS];
+ int nfds;
+ RdmaCmUMadAgent umad_agent;
+ pthread_t umad_recv_thread;
+ pthread_rwlock_t lock;
+} RdmaCMServer;
+
+static RdmaCMServer server = {0};
+
+static void usage(const char *progname)
+{
+ printf("Usage: %s [OPTION]...\n"
+ "Start a RDMA-CM multiplexer\n"
+ "\n"
+ "\t-h Show this help\n"
+ "\t-d rdma-device-name Name of RDMA device to register with\n"
+ "\t-s unix-socket-path Path to unix socket to listen on (default %s)\n"
+ "\t-p rdma-device-port Port number of RDMA device to register with (default %d)\n",
+ progname, UNIX_SOCKET_PATH, RDMA_PORT_NUM);
+}
+
+static void help(const char *progname)
+{
+ fprintf(stderr, "Try '%s -h' for more information.\n", progname);
+}
+
+static void parse_args(int argc, char *argv[])
+{
+ int c;
+ char unix_socket_path[SOCKET_PATH_MAX];
+
+ strcpy(server.args.rdma_dev_name, "");
+ strcpy(unix_socket_path, UNIX_SOCKET_PATH);
+ server.args.rdma_port_num = RDMA_PORT_NUM;
+
+ while ((c = getopt(argc, argv, "hs:d:p:")) != -1) {
+ switch (c) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+
+ case 'd':
+ strncpy(server.args.rdma_dev_name, optarg, NAME_MAX - 1);
+ break;
+
+ case 's':
+ /* This is temporary, final name will build below */
+ strncpy(unix_socket_path, optarg, SOCKET_PATH_MAX);
+ break;
+
+ case 'p':
+ server.args.rdma_port_num = atoi(optarg);
+ break;
+
+ default:
+ help(argv[0]);
+ exit(1);
+ }
+ }
+
+ if (!strcmp(server.args.rdma_dev_name, "")) {
+ fprintf(stderr, "Missing RDMA device name\n");
+ help(argv[0]);
+ exit(1);
+ }
+
+ /* Build unique unix-socket file name */
+ snprintf(server.args.unix_socket_path, PATH_MAX, "%s-%s-%d",
+ unix_socket_path, server.args.rdma_dev_name,
+ server.args.rdma_port_num);
+
+ syslog(LOG_INFO, "unix_socket_path=%s", server.args.unix_socket_path);
+ syslog(LOG_INFO, "rdma-device-name=%s", server.args.rdma_dev_name);
+ syslog(LOG_INFO, "rdma-device-port=%d", server.args.rdma_port_num);
+}
+
+static void hash_tbl_alloc(void)
+{
+
+ server.umad_agent.gid2fd = g_hash_table_new_full(g_int64_hash,
+ g_int64_equal,
+ g_free, g_free);
+ server.umad_agent.commid2fd = g_hash_table_new_full(g_int_hash,
+ g_int_equal,
+ g_free, g_free);
+}
+
+static void hash_tbl_free(void)
+{
+ if (server.umad_agent.commid2fd) {
+ g_hash_table_destroy(server.umad_agent.commid2fd);
+ }
+ if (server.umad_agent.gid2fd) {
+ g_hash_table_destroy(server.umad_agent.gid2fd);
+ }
+}
+
+
+static int _hash_tbl_search_fd_by_ifid(__be64 *gid_ifid)
+{
+ int *fd;
+
+ fd = g_hash_table_lookup(server.umad_agent.gid2fd, gid_ifid);
+ if (!fd) {
+ /* Let's try IPv4 */
+ *gid_ifid |= 0x00000000ffff0000;
+ fd = g_hash_table_lookup(server.umad_agent.gid2fd, gid_ifid);
+ }
+
+ return fd ? *fd : 0;
+}
+
+static int hash_tbl_search_fd_by_ifid(int *fd, __be64 *gid_ifid)
+{
+ pthread_rwlock_rdlock(&server.lock);
+ *fd = _hash_tbl_search_fd_by_ifid(gid_ifid);
+ pthread_rwlock_unlock(&server.lock);
+
+ if (!fd) {
+ syslog(LOG_WARNING, "Can't find matching for ifid 0x%llx\n", *gid_ifid);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int hash_tbl_search_fd_by_comm_id(uint32_t comm_id, int *fd,
+ __be64 *gid_idid)
+{
+ CommId2FdEntry *fde;
+
+ pthread_rwlock_rdlock(&server.lock);
+ fde = g_hash_table_lookup(server.umad_agent.commid2fd, &comm_id);
+ pthread_rwlock_unlock(&server.lock);
+
+ if (!fde) {
+ syslog(LOG_WARNING, "Can't find matching for comm_id 0x%x\n", comm_id);
+ return -ENOENT;
+ }
+
+ *fd = fde->fd;
+ *gid_idid = fde->gid_ifid;
+
+ return 0;
+}
+
+static RdmaCmMuxErrCode add_fd_ifid_pair(int fd, __be64 gid_ifid)
+{
+ int fd1;
+
+ pthread_rwlock_wrlock(&server.lock);
+
+ fd1 = _hash_tbl_search_fd_by_ifid(&gid_ifid);
+ if (fd1) { /* record already exist - an error */
+ pthread_rwlock_unlock(&server.lock);
+ return fd == fd1 ? RDMACM_MUX_ERR_CODE_EEXIST :
+ RDMACM_MUX_ERR_CODE_EACCES;
+ }
+
+ g_hash_table_insert(server.umad_agent.gid2fd, g_memdup(&gid_ifid,
+ sizeof(gid_ifid)), g_memdup(&fd, sizeof(fd)));
+
+ pthread_rwlock_unlock(&server.lock);
+
+ syslog(LOG_INFO, "0x%lx registered on socket %d",
+ be64toh((uint64_t)gid_ifid), fd);
+
+ return RDMACM_MUX_ERR_CODE_OK;
+}
+
+static RdmaCmMuxErrCode delete_fd_ifid_pair(int fd, __be64 gid_ifid)
+{
+ int fd1;
+
+ pthread_rwlock_wrlock(&server.lock);
+
+ fd1 = _hash_tbl_search_fd_by_ifid(&gid_ifid);
+ if (!fd1) { /* record not exist - an error */
+ pthread_rwlock_unlock(&server.lock);
+ return RDMACM_MUX_ERR_CODE_ENOTFOUND;
+ }
+
+ g_hash_table_remove(server.umad_agent.gid2fd, g_memdup(&gid_ifid,
+ sizeof(gid_ifid)));
+ pthread_rwlock_unlock(&server.lock);
+
+ syslog(LOG_INFO, "0x%lx unregistered on socket %d",
+ be64toh((uint64_t)gid_ifid), fd);
+
+ return RDMACM_MUX_ERR_CODE_OK;
+}
+
+static void hash_tbl_save_fd_comm_id_pair(int fd, uint32_t comm_id,
+ uint64_t gid_ifid)
+{
+ CommId2FdEntry fde = {fd, COMMID_TTL, gid_ifid};
+
+ pthread_rwlock_wrlock(&server.lock);
+ g_hash_table_insert(server.umad_agent.commid2fd,
+ g_memdup(&comm_id, sizeof(comm_id)),
+ g_memdup(&fde, sizeof(fde)));
+ pthread_rwlock_unlock(&server.lock);
+}
+
+static gboolean remove_old_comm_ids(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ CommId2FdEntry *fde = (CommId2FdEntry *)value;
+
+ return !fde->ttl--;
+}
+
+static gboolean remove_entry_from_gid2fd(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ if (*(int *)value == *(int *)user_data) {
+ syslog(LOG_INFO, "0x%lx unregistered on socket %d",
+ be64toh(*(uint64_t *)key), *(int *)value);
+ return true;
+ }
+
+ return false;
+}
+
+static void hash_tbl_remove_fd_ifid_pair(int fd)
+{
+ pthread_rwlock_wrlock(&server.lock);
+ g_hash_table_foreach_remove(server.umad_agent.gid2fd,
+ remove_entry_from_gid2fd, (gpointer)&fd);
+ pthread_rwlock_unlock(&server.lock);
+}
+
+static int get_fd(const char *mad, int *fd, __be64 *gid_ifid)
+{
+ struct umad_hdr *hdr = (struct umad_hdr *)mad;
+ char *data = (char *)hdr + sizeof(*hdr);
+ int32_t comm_id = 0;
+ uint16_t attr_id = be16toh(hdr->attr_id);
+ int rc = 0;
+
+ switch (attr_id) {
+ case UMAD_CM_ATTR_REQ:
+ memcpy(gid_ifid, data + CM_REQ_DGID_POS, sizeof(*gid_ifid));
+ rc = hash_tbl_search_fd_by_ifid(fd, gid_ifid);
+ break;
+
+ case UMAD_CM_ATTR_SIDR_REQ:
+ memcpy(gid_ifid, data + CM_SIDR_REQ_DGID_POS, sizeof(*gid_ifid));
+ rc = hash_tbl_search_fd_by_ifid(fd, gid_ifid);
+ break;
+
+ case UMAD_CM_ATTR_REP:
+ /* Fall through */
+ case UMAD_CM_ATTR_REJ:
+ /* Fall through */
+ case UMAD_CM_ATTR_DREQ:
+ /* Fall through */
+ case UMAD_CM_ATTR_DREP:
+ /* Fall through */
+ case UMAD_CM_ATTR_RTU:
+ data += sizeof(comm_id);
+ /* Fall through */
+ case UMAD_CM_ATTR_SIDR_REP:
+ memcpy(&comm_id, data, sizeof(comm_id));
+ if (comm_id) {
+ rc = hash_tbl_search_fd_by_comm_id(comm_id, fd, gid_ifid);
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ syslog(LOG_WARNING, "Unsupported attr_id 0x%x\n", attr_id);
+ }
+
+ syslog(LOG_DEBUG, "mad_to_vm: %d 0x%x 0x%x\n", *fd, attr_id, comm_id);
+
+ return rc;
+}
+
+static void *umad_recv_thread_func(void *args)
+{
+ int rc;
+ RdmaCmMuxMsg msg = {};
+ int fd = -2;
+
+ msg.hdr.msg_type = RDMACM_MUX_MSG_TYPE_REQ;
+ msg.hdr.op_code = RDMACM_MUX_OP_CODE_MAD;
+
+ while (server.run) {
+ do {
+ msg.umad_len = sizeof(msg.umad.mad);
+ rc = umad_recv(server.umad_agent.port_id, &msg.umad, &msg.umad_len,
+ SLEEP_SECS * SCALE_US);
+ if ((rc == -EIO) || (rc == -EINVAL)) {
+ syslog(LOG_CRIT, "Fatal error while trying to read MAD");
+ }
+
+ if (rc == -ETIMEDOUT) {
+ g_hash_table_foreach_remove(server.umad_agent.commid2fd,
+ remove_old_comm_ids, NULL);
+ }
+ } while (rc && server.run);
+
+ if (server.run) {
+ rc = get_fd(msg.umad.mad, &fd, &msg.hdr.sgid.global.interface_id);
+ if (rc) {
+ continue;
+ }
+
+ send(fd, &msg, sizeof(msg), 0);
+ }
+ }
+
+ return NULL;
+}
+
+static int read_and_process(int fd)
+{
+ int rc;
+ RdmaCmMuxMsg msg = {};
+ struct umad_hdr *hdr;
+ uint32_t *comm_id = 0;
+ uint16_t attr_id;
+
+ rc = recv(fd, &msg, sizeof(msg), 0);
+ syslog(LOG_DEBUG, "Socket %d, recv %d\n", fd, rc);
+
+ if (rc < 0 && errno != EWOULDBLOCK) {
+ syslog(LOG_ERR, "Fail to read from socket %d\n", fd);
+ return -EIO;
+ }
+
+ if (!rc) {
+ syslog(LOG_ERR, "Fail to read from socket %d\n", fd);
+ return -EPIPE;
+ }
+
+ if (msg.hdr.msg_type != RDMACM_MUX_MSG_TYPE_REQ) {
+ syslog(LOG_WARNING, "Got non-request message (%d) from socket %d\n",
+ msg.hdr.msg_type, fd);
+ return -EPERM;
+ }
+
+ switch (msg.hdr.op_code) {
+ case RDMACM_MUX_OP_CODE_REG:
+ rc = add_fd_ifid_pair(fd, msg.hdr.sgid.global.interface_id);
+ break;
+
+ case RDMACM_MUX_OP_CODE_UNREG:
+ rc = delete_fd_ifid_pair(fd, msg.hdr.sgid.global.interface_id);
+ break;
+
+ case RDMACM_MUX_OP_CODE_MAD:
+ /* If this is REQ or REP then store the pair comm_id,fd to be later
+ * used for other messages where gid is unknown */
+ hdr = (struct umad_hdr *)msg.umad.mad;
+ attr_id = be16toh(hdr->attr_id);
+ if ((attr_id == UMAD_CM_ATTR_REQ) || (attr_id == UMAD_CM_ATTR_DREQ) ||
+ (attr_id == UMAD_CM_ATTR_SIDR_REQ) ||
+ (attr_id == UMAD_CM_ATTR_REP) || (attr_id == UMAD_CM_ATTR_DREP)) {
+ comm_id = (uint32_t *)(msg.umad.mad + sizeof(*hdr));
+ hash_tbl_save_fd_comm_id_pair(fd, *comm_id,
+ msg.hdr.sgid.global.interface_id);
+ }
+
+ syslog(LOG_DEBUG, "vm_to_mad: %d 0x%x 0x%x\n", fd, attr_id,
+ comm_id ? *comm_id : 0);
+ rc = umad_send(server.umad_agent.port_id, server.umad_agent.agent_id,
+ &msg.umad, msg.umad_len, 1, 0);
+ if (rc) {
+ syslog(LOG_ERR,
+ "Fail to send MAD message (0x%x) from socket %d, err=%d",
+ attr_id, fd, rc);
+ }
+ break;
+
+ default:
+ syslog(LOG_ERR, "Got invalid op_code (%d) from socket %d",
+ msg.hdr.msg_type, fd);
+ rc = RDMACM_MUX_ERR_CODE_EINVAL;
+ }
+
+ msg.hdr.msg_type = RDMACM_MUX_MSG_TYPE_RESP;
+ msg.hdr.err_code = rc;
+ rc = send(fd, &msg, sizeof(msg), 0);
+
+ return rc == sizeof(msg) ? 0 : -EPIPE;
+}
+
+static int accept_all(void)
+{
+ int fd, rc = 0;;
+
+ pthread_rwlock_wrlock(&server.lock);
+
+ do {
+ if ((server.nfds + 1) > MAX_CLIENTS) {
+ syslog(LOG_WARNING, "Too many clients (%d)", server.nfds);
+ rc = -EIO;
+ goto out;
+ }
+
+ fd = accept(server.fds[0].fd, NULL, NULL);
+ if (fd < 0) {
+ if (errno != EWOULDBLOCK) {
+ syslog(LOG_WARNING, "accept() failed");
+ rc = -EIO;
+ goto out;
+ }
+ break;
+ }
+
+ syslog(LOG_INFO, "Client connected on socket %d\n", fd);
+ server.fds[server.nfds].fd = fd;
+ server.fds[server.nfds].events = POLLIN;
+ server.nfds++;
+ } while (fd != -1);
+
+out:
+ pthread_rwlock_unlock(&server.lock);
+ return rc;
+}
+
+static void compress_fds(void)
+{
+ int i, j;
+ int closed = 0;
+
+ pthread_rwlock_wrlock(&server.lock);
+
+ for (i = 1; i < server.nfds; i++) {
+ if (!server.fds[i].fd) {
+ closed++;
+ for (j = i; j < server.nfds - 1; j++) {
+ server.fds[j] = server.fds[j + 1];
+ }
+ }
+ }
+
+ server.nfds -= closed;
+
+ pthread_rwlock_unlock(&server.lock);
+}
+
+static void close_fd(int idx)
+{
+ close(server.fds[idx].fd);
+ syslog(LOG_INFO, "Socket %d closed\n", server.fds[idx].fd);
+ hash_tbl_remove_fd_ifid_pair(server.fds[idx].fd);
+ server.fds[idx].fd = 0;
+}
+
+static void run(void)
+{
+ int rc, nfds, i;
+ bool compress = false;
+
+ syslog(LOG_INFO, "Service started");
+
+ while (server.run) {
+ rc = poll(server.fds, server.nfds, SLEEP_SECS * SCALE_US);
+ if (rc < 0) {
+ if (errno != EINTR) {
+ syslog(LOG_WARNING, "poll() failed");
+ }
+ continue;
+ }
+
+ if (rc == 0) {
+ continue;
+ }
+
+ nfds = server.nfds;
+ for (i = 0; i < nfds; i++) {
+ syslog(LOG_DEBUG, "pollfd[%d]: revents 0x%x, events 0x%x\n", i,
+ server.fds[i].revents, server.fds[i].events);
+ if (server.fds[i].revents == 0) {
+ continue;
+ }
+
+ if (server.fds[i].revents != POLLIN) {
+ if (i == 0) {
+ syslog(LOG_NOTICE, "Unexpected poll() event (0x%x)\n",
+ server.fds[i].revents);
+ } else {
+ close_fd(i);
+ compress = true;
+ }
+ continue;
+ }
+
+ if (i == 0) {
+ rc = accept_all();
+ if (rc) {
+ continue;
+ }
+ } else {
+ rc = read_and_process(server.fds[i].fd);
+ if (rc) {
+ close_fd(i);
+ compress = true;
+ }
+ }
+ }
+
+ if (compress) {
+ compress = false;
+ compress_fds();
+ }
+ }
+}
+
+static void fini_listener(void)
+{
+ int i;
+
+ if (server.fds[0].fd <= 0) {
+ return;
+ }
+
+ for (i = server.nfds - 1; i >= 0; i--) {
+ if (server.fds[i].fd) {
+ close(server.fds[i].fd);
+ }
+ }
+
+ unlink(server.args.unix_socket_path);
+}
+
+static void fini_umad(void)
+{
+ if (server.umad_agent.agent_id) {
+ umad_unregister(server.umad_agent.port_id, server.umad_agent.agent_id);
+ }
+
+ if (server.umad_agent.port_id) {
+ umad_close_port(server.umad_agent.port_id);
+ }
+
+ hash_tbl_free();
+}
+
+static void fini(void)
+{
+ if (server.umad_recv_thread) {
+ pthread_join(server.umad_recv_thread, NULL);
+ server.umad_recv_thread = 0;
+ }
+ fini_umad();
+ fini_listener();
+ pthread_rwlock_destroy(&server.lock);
+
+ syslog(LOG_INFO, "Service going down");
+}
+
+static int init_listener(void)
+{
+ struct sockaddr_un sun;
+ int rc, on = 1;
+
+ server.fds[0].fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (server.fds[0].fd < 0) {
+ syslog(LOG_ALERT, "socket() failed");
+ return -EIO;
+ }
+
+ rc = setsockopt(server.fds[0].fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on));
+ if (rc < 0) {
+ syslog(LOG_ALERT, "setsockopt() failed");
+ rc = -EIO;
+ goto err;
+ }
+
+ rc = ioctl(server.fds[0].fd, FIONBIO, (char *)&on);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "ioctl() failed");
+ rc = -EIO;
+ goto err;
+ }
+
+ if (strlen(server.args.unix_socket_path) >= sizeof(sun.sun_path)) {
+ syslog(LOG_ALERT,
+ "Invalid unix_socket_path, size must be less than %ld\n",
+ sizeof(sun.sun_path));
+ rc = -EINVAL;
+ goto err;
+ }
+
+ sun.sun_family = AF_UNIX;
+ rc = snprintf(sun.sun_path, sizeof(sun.sun_path), "%s",
+ server.args.unix_socket_path);
+ if (rc < 0 || rc >= sizeof(sun.sun_path)) {
+ syslog(LOG_ALERT, "Could not copy unix socket path\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
+ rc = bind(server.fds[0].fd, (struct sockaddr *)&sun, sizeof(sun));
+ if (rc < 0) {
+ syslog(LOG_ALERT, "bind() failed");
+ rc = -EIO;
+ goto err;
+ }
+
+ rc = listen(server.fds[0].fd, SERVER_LISTEN_BACKLOG);
+ if (rc < 0) {
+ syslog(LOG_ALERT, "listen() failed");
+ rc = -EIO;
+ goto err;
+ }
+
+ server.fds[0].events = POLLIN;
+ server.nfds = 1;
+ server.run = true;
+
+ return 0;
+
+err:
+ close(server.fds[0].fd);
+ return rc;
+}
+
+static int init_umad(void)
+{
+ long method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK];
+
+ server.umad_agent.port_id = umad_open_port(server.args.rdma_dev_name,
+ server.args.rdma_port_num);
+
+ if (server.umad_agent.port_id < 0) {
+ syslog(LOG_WARNING, "umad_open_port() failed");
+ return -EIO;
+ }
+
+ memset(&method_mask, 0, sizeof(method_mask));
+ method_mask[0] = MAD_METHOD_MASK0;
+ server.umad_agent.agent_id = umad_register(server.umad_agent.port_id,
+ UMAD_CLASS_CM,
+ UMAD_SA_CLASS_VERSION,
+ MAD_RMPP_VERSION, method_mask);
+ if (server.umad_agent.agent_id < 0) {
+ syslog(LOG_WARNING, "umad_register() failed");
+ return -EIO;
+ }
+
+ hash_tbl_alloc();
+
+ return 0;
+}
+
+static void signal_handler(int sig, siginfo_t *siginfo, void *context)
+{
+ static bool warned;
+
+ /* Prevent stop if clients are connected */
+ if (server.nfds != 1) {
+ if (!warned) {
+ syslog(LOG_WARNING,
+ "Can't stop while active client exist, resend SIGINT to overid");
+ warned = true;
+ return;
+ }
+ }
+
+ if (sig == SIGINT) {
+ server.run = false;
+ fini();
+ }
+
+ exit(0);
+}
+
+static int init(void)
+{
+ int rc;
+ struct sigaction sig = {};
+
+ rc = init_listener();
+ if (rc) {
+ return rc;
+ }
+
+ rc = init_umad();
+ if (rc) {
+ return rc;
+ }
+
+ pthread_rwlock_init(&server.lock, 0);
+
+ rc = pthread_create(&server.umad_recv_thread, NULL, umad_recv_thread_func,
+ NULL);
+ if (rc) {
+ syslog(LOG_ERR, "Fail to create UMAD receiver thread (%d)\n", rc);
+ return rc;
+ }
+
+ sig.sa_sigaction = &signal_handler;
+ sig.sa_flags = SA_SIGINFO;
+ rc = sigaction(SIGINT, &sig, NULL);
+ if (rc < 0) {
+ syslog(LOG_ERR, "Fail to install SIGINT handler (%d)\n", errno);
+ return rc;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+
+ memset(&server, 0, sizeof(server));
+
+ parse_args(argc, argv);
+
+ rc = init();
+ if (rc) {
+ syslog(LOG_ERR, "Fail to initialize server (%d)\n", rc);
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ run();
+
+out:
+ fini();
+
+ return rc;
+}
diff --git a/contrib/rdmacm-mux/rdmacm-mux.h b/contrib/rdmacm-mux/rdmacm-mux.h
new file mode 100644
index 0000000000..942a802c47
--- /dev/null
+++ b/contrib/rdmacm-mux/rdmacm-mux.h
@@ -0,0 +1,61 @@
+/*
+ * QEMU paravirtual RDMA - rdmacm-mux declarations
+ *
+ * Copyright (C) 2018 Oracle
+ * Copyright (C) 2018 Red Hat Inc
+ *
+ * Authors:
+ * Yuval Shaia <yuval.shaia@oracle.com>
+ * Marcel Apfelbaum <marcel@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 RDMACM_MUX_H
+#define RDMACM_MUX_H
+
+#include "linux/if.h"
+#include "infiniband/verbs.h"
+#include "infiniband/umad.h"
+#include "rdma/rdma_user_cm.h"
+
+typedef enum RdmaCmMuxMsgType {
+ RDMACM_MUX_MSG_TYPE_REQ = 0,
+ RDMACM_MUX_MSG_TYPE_RESP = 1,
+} RdmaCmMuxMsgType;
+
+typedef enum RdmaCmMuxOpCode {
+ RDMACM_MUX_OP_CODE_REG = 0,
+ RDMACM_MUX_OP_CODE_UNREG = 1,
+ RDMACM_MUX_OP_CODE_MAD = 2,
+} RdmaCmMuxOpCode;
+
+typedef enum RdmaCmMuxErrCode {
+ RDMACM_MUX_ERR_CODE_OK = 0,
+ RDMACM_MUX_ERR_CODE_EINVAL = 1,
+ RDMACM_MUX_ERR_CODE_EEXIST = 2,
+ RDMACM_MUX_ERR_CODE_EACCES = 3,
+ RDMACM_MUX_ERR_CODE_ENOTFOUND = 4,
+} RdmaCmMuxErrCode;
+
+typedef struct RdmaCmMuxHdr {
+ RdmaCmMuxMsgType msg_type;
+ RdmaCmMuxOpCode op_code;
+ union ibv_gid sgid;
+ RdmaCmMuxErrCode err_code;
+} RdmaCmUHdr;
+
+typedef struct RdmaCmUMad {
+ struct ib_user_mad hdr;
+ char mad[RDMA_MAX_PRIVATE_DATA];
+} RdmaCmUMad;
+
+typedef struct RdmaCmMuxMsg {
+ RdmaCmUHdr hdr;
+ int umad_len;
+ RdmaCmUMad umad;
+} RdmaCmMuxMsg;
+
+#endif
diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c
index 571f114a56..858221ad95 100644
--- a/contrib/vhost-user-blk/vhost-user-blk.c
+++ b/contrib/vhost-user-blk/vhost-user-blk.c
@@ -20,7 +20,6 @@
#include "contrib/libvhost-user/libvhost-user-glib.h"
#include "contrib/libvhost-user/libvhost-user.h"
-#include <glib.h>
struct virtio_blk_inhdr {
unsigned char status;
diff --git a/contrib/vhost-user-scsi/vhost-user-scsi.c b/contrib/vhost-user-scsi/vhost-user-scsi.c
index 02c29019d1..496dd6e693 100644
--- a/contrib/vhost-user-scsi/vhost-user-scsi.c
+++ b/contrib/vhost-user-scsi/vhost-user-scsi.c
@@ -16,7 +16,6 @@
#include "contrib/libvhost-user/libvhost-user-glib.h"
#include "standard-headers/linux/virtio_scsi.h"
-#include <glib.h>
#define VUS_ISCSI_INITIATOR "iqn.2016-11.com.nutanix:vhost-user-scsi"
diff --git a/cpus-common.c b/cpus-common.c
index 98dd8c6ff1..3ca58c64e8 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -99,7 +99,7 @@ void cpu_list_remove(CPUState *cpu)
return;
}
- assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
+ assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus)));
QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX;
diff --git a/cpus.c b/cpus.c
index 0ddeeefc14..b09b702712 100644
--- a/cpus.c
+++ b/cpus.c
@@ -2100,7 +2100,8 @@ void qemu_init_vcpu(CPUState *cpu)
void cpu_stop_current(void)
{
if (current_cpu) {
- qemu_cpu_stop(current_cpu, true);
+ current_cpu->stop = true;
+ cpu_exit(current_cpu);
}
}
diff --git a/crypto/aes.c b/crypto/aes.c
index 3456eacd08..773d246b00 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -1071,7 +1071,7 @@ int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key) {
u32 *rk;
- int i = 0;
+ int i = 0;
u32 temp;
if (!userKey || !key)
@@ -1160,7 +1160,7 @@ int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
rk[15] = rk[ 7] ^ rk[14];
rk += 8;
- }
+ }
}
abort();
}
@@ -1247,7 +1247,7 @@ void AES_encrypt(const unsigned char *in, unsigned char *out,
t1 = AES_Te0[s1 >> 24] ^ AES_Te1[(s2 >> 16) & 0xff] ^ AES_Te2[(s3 >> 8) & 0xff] ^ AES_Te3[s0 & 0xff] ^ rk[ 5];
t2 = AES_Te0[s2 >> 24] ^ AES_Te1[(s3 >> 16) & 0xff] ^ AES_Te2[(s0 >> 8) & 0xff] ^ AES_Te3[s1 & 0xff] ^ rk[ 6];
t3 = AES_Te0[s3 >> 24] ^ AES_Te1[(s0 >> 16) & 0xff] ^ AES_Te2[(s1 >> 8) & 0xff] ^ AES_Te3[s2 & 0xff] ^ rk[ 7];
- /* round 2: */
+ /* round 2: */
s0 = AES_Te0[t0 >> 24] ^ AES_Te1[(t1 >> 16) & 0xff] ^ AES_Te2[(t2 >> 8) & 0xff] ^ AES_Te3[t3 & 0xff] ^ rk[ 8];
s1 = AES_Te0[t1 >> 24] ^ AES_Te1[(t2 >> 16) & 0xff] ^ AES_Te2[(t3 >> 8) & 0xff] ^ AES_Te3[t0 & 0xff] ^ rk[ 9];
s2 = AES_Te0[t2 >> 24] ^ AES_Te1[(t3 >> 16) & 0xff] ^ AES_Te2[(t0 >> 8) & 0xff] ^ AES_Te3[t1 & 0xff] ^ rk[10];
@@ -1257,7 +1257,7 @@ void AES_encrypt(const unsigned char *in, unsigned char *out,
t1 = AES_Te0[s1 >> 24] ^ AES_Te1[(s2 >> 16) & 0xff] ^ AES_Te2[(s3 >> 8) & 0xff] ^ AES_Te3[s0 & 0xff] ^ rk[13];
t2 = AES_Te0[s2 >> 24] ^ AES_Te1[(s3 >> 16) & 0xff] ^ AES_Te2[(s0 >> 8) & 0xff] ^ AES_Te3[s1 & 0xff] ^ rk[14];
t3 = AES_Te0[s3 >> 24] ^ AES_Te1[(s0 >> 16) & 0xff] ^ AES_Te2[(s1 >> 8) & 0xff] ^ AES_Te3[s2 & 0xff] ^ rk[15];
- /* round 4: */
+ /* round 4: */
s0 = AES_Te0[t0 >> 24] ^ AES_Te1[(t1 >> 16) & 0xff] ^ AES_Te2[(t2 >> 8) & 0xff] ^ AES_Te3[t3 & 0xff] ^ rk[16];
s1 = AES_Te0[t1 >> 24] ^ AES_Te1[(t2 >> 16) & 0xff] ^ AES_Te2[(t3 >> 8) & 0xff] ^ AES_Te3[t0 & 0xff] ^ rk[17];
s2 = AES_Te0[t2 >> 24] ^ AES_Te1[(t3 >> 16) & 0xff] ^ AES_Te2[(t0 >> 8) & 0xff] ^ AES_Te3[t1 & 0xff] ^ rk[18];
@@ -1267,7 +1267,7 @@ void AES_encrypt(const unsigned char *in, unsigned char *out,
t1 = AES_Te0[s1 >> 24] ^ AES_Te1[(s2 >> 16) & 0xff] ^ AES_Te2[(s3 >> 8) & 0xff] ^ AES_Te3[s0 & 0xff] ^ rk[21];
t2 = AES_Te0[s2 >> 24] ^ AES_Te1[(s3 >> 16) & 0xff] ^ AES_Te2[(s0 >> 8) & 0xff] ^ AES_Te3[s1 & 0xff] ^ rk[22];
t3 = AES_Te0[s3 >> 24] ^ AES_Te1[(s0 >> 16) & 0xff] ^ AES_Te2[(s1 >> 8) & 0xff] ^ AES_Te3[s2 & 0xff] ^ rk[23];
- /* round 6: */
+ /* round 6: */
s0 = AES_Te0[t0 >> 24] ^ AES_Te1[(t1 >> 16) & 0xff] ^ AES_Te2[(t2 >> 8) & 0xff] ^ AES_Te3[t3 & 0xff] ^ rk[24];
s1 = AES_Te0[t1 >> 24] ^ AES_Te1[(t2 >> 16) & 0xff] ^ AES_Te2[(t3 >> 8) & 0xff] ^ AES_Te3[t0 & 0xff] ^ rk[25];
s2 = AES_Te0[t2 >> 24] ^ AES_Te1[(t3 >> 16) & 0xff] ^ AES_Te2[(t0 >> 8) & 0xff] ^ AES_Te3[t1 & 0xff] ^ rk[26];
@@ -1277,7 +1277,7 @@ void AES_encrypt(const unsigned char *in, unsigned char *out,
t1 = AES_Te0[s1 >> 24] ^ AES_Te1[(s2 >> 16) & 0xff] ^ AES_Te2[(s3 >> 8) & 0xff] ^ AES_Te3[s0 & 0xff] ^ rk[29];
t2 = AES_Te0[s2 >> 24] ^ AES_Te1[(s3 >> 16) & 0xff] ^ AES_Te2[(s0 >> 8) & 0xff] ^ AES_Te3[s1 & 0xff] ^ rk[30];
t3 = AES_Te0[s3 >> 24] ^ AES_Te1[(s0 >> 16) & 0xff] ^ AES_Te2[(s1 >> 8) & 0xff] ^ AES_Te3[s2 & 0xff] ^ rk[31];
- /* round 8: */
+ /* round 8: */
s0 = AES_Te0[t0 >> 24] ^ AES_Te1[(t1 >> 16) & 0xff] ^ AES_Te2[(t2 >> 8) & 0xff] ^ AES_Te3[t3 & 0xff] ^ rk[32];
s1 = AES_Te0[t1 >> 24] ^ AES_Te1[(t2 >> 16) & 0xff] ^ AES_Te2[(t3 >> 8) & 0xff] ^ AES_Te3[t0 & 0xff] ^ rk[33];
s2 = AES_Te0[t2 >> 24] ^ AES_Te1[(t3 >> 16) & 0xff] ^ AES_Te2[(t0 >> 8) & 0xff] ^ AES_Te3[t1 & 0xff] ^ rk[34];
@@ -1569,33 +1569,33 @@ void AES_decrypt(const unsigned char *in, unsigned char *out,
* apply last round and
* map cipher state to byte array block:
*/
- s0 =
+ s0 =
(AES_Td4[(t0 >> 24) ] & 0xff000000) ^
(AES_Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(AES_Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(AES_Td4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[0];
+ rk[0];
PUTU32(out , s0);
- s1 =
+ s1 =
(AES_Td4[(t1 >> 24) ] & 0xff000000) ^
(AES_Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(AES_Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(AES_Td4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[1];
+ rk[1];
PUTU32(out + 4, s1);
- s2 =
+ s2 =
(AES_Td4[(t2 >> 24) ] & 0xff000000) ^
(AES_Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(AES_Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(AES_Td4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[2];
+ rk[2];
PUTU32(out + 8, s2);
- s3 =
+ s3 =
(AES_Td4[(t3 >> 24) ] & 0xff000000) ^
(AES_Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(AES_Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(AES_Td4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[3];
+ rk[3];
PUTU32(out + 12, s3);
}
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 5738124773..6bac79c3ab 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -504,14 +504,14 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
* to reset the encryption cipher every time the master
* key crosses a sector boundary.
*/
- if (qcrypto_block_decrypt_helper(cipher,
- niv,
- ivgen,
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
- 0,
- splitkey,
- splitkeylen,
- errp) < 0) {
+ if (qcrypto_block_cipher_decrypt_helper(cipher,
+ niv,
+ ivgen,
+ QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
+ 0,
+ splitkey,
+ splitkeylen,
+ errp) < 0) {
goto cleanup;
}
@@ -636,6 +636,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
+ size_t n_threads,
Error **errp)
{
QCryptoBlockLUKS *luks;
@@ -836,11 +837,10 @@ qcrypto_block_luks_open(QCryptoBlock *block,
goto fail;
}
- block->cipher = qcrypto_cipher_new(cipheralg,
- ciphermode,
- masterkey, masterkeylen,
- errp);
- if (!block->cipher) {
+ ret = qcrypto_block_init_cipher(block, cipheralg, ciphermode,
+ masterkey, masterkeylen, n_threads,
+ errp);
+ if (ret < 0) {
ret = -ENOTSUP;
goto fail;
}
@@ -863,7 +863,7 @@ qcrypto_block_luks_open(QCryptoBlock *block,
fail:
g_free(masterkey);
- qcrypto_cipher_free(block->cipher);
+ qcrypto_block_free_cipher(block);
qcrypto_ivgen_free(block->ivgen);
g_free(luks);
g_free(password);
@@ -1030,11 +1030,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Setup the block device payload encryption objects */
- block->cipher = qcrypto_cipher_new(luks_opts.cipher_alg,
- luks_opts.cipher_mode,
- masterkey, luks->header.key_bytes,
- errp);
- if (!block->cipher) {
+ if (qcrypto_block_init_cipher(block, luks_opts.cipher_alg,
+ luks_opts.cipher_mode, masterkey,
+ luks->header.key_bytes, 1, errp) < 0) {
goto error;
}
@@ -1219,12 +1217,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
/* Now we encrypt the split master key with the key generated
* from the user's password, before storing it */
- if (qcrypto_block_encrypt_helper(cipher, block->niv, ivgen,
- QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
- 0,
- splitkey,
- splitkeylen,
- errp) < 0) {
+ if (qcrypto_block_cipher_encrypt_helper(cipher, block->niv, ivgen,
+ QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
+ 0,
+ splitkey,
+ splitkeylen,
+ errp) < 0) {
goto error;
}
@@ -1341,6 +1339,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
qcrypto_ivgen_free(ivgen);
qcrypto_cipher_free(cipher);
+ qcrypto_block_free_cipher(block);
+ qcrypto_ivgen_free(block->ivgen);
+
g_free(luks);
return -1;
}
@@ -1406,8 +1407,7 @@ qcrypto_block_luks_decrypt(QCryptoBlock *block,
{
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
- return qcrypto_block_decrypt_helper(block->cipher,
- block->niv, block->ivgen,
+ return qcrypto_block_decrypt_helper(block,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
offset, buf, len, errp);
}
@@ -1422,8 +1422,7 @@ qcrypto_block_luks_encrypt(QCryptoBlock *block,
{
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
- return qcrypto_block_encrypt_helper(block->cipher,
- block->niv, block->ivgen,
+ return qcrypto_block_encrypt_helper(block,
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
offset, buf, len, errp);
}
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
index 7606231e79..cefb3b2a7b 100644
--- a/crypto/block-qcow.c
+++ b/crypto/block-qcow.c
@@ -44,6 +44,7 @@ qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
static int
qcrypto_block_qcow_init(QCryptoBlock *block,
const char *keysecret,
+ size_t n_threads,
Error **errp)
{
char *password;
@@ -71,11 +72,11 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
goto fail;
}
- block->cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
- QCRYPTO_CIPHER_MODE_CBC,
- keybuf, G_N_ELEMENTS(keybuf),
- errp);
- if (!block->cipher) {
+ ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALG_AES_128,
+ QCRYPTO_CIPHER_MODE_CBC,
+ keybuf, G_N_ELEMENTS(keybuf),
+ n_threads, errp);
+ if (ret < 0) {
ret = -ENOTSUP;
goto fail;
}
@@ -86,7 +87,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
return 0;
fail:
- qcrypto_cipher_free(block->cipher);
+ qcrypto_block_free_cipher(block);
qcrypto_ivgen_free(block->ivgen);
return ret;
}
@@ -99,6 +100,7 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
void *opaque G_GNUC_UNUSED,
unsigned int flags,
+ size_t n_threads,
Error **errp)
{
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
@@ -112,8 +114,8 @@ qcrypto_block_qcow_open(QCryptoBlock *block,
optprefix ? optprefix : "");
return -1;
}
- return qcrypto_block_qcow_init(block,
- options->u.qcow.key_secret, errp);
+ return qcrypto_block_qcow_init(block, options->u.qcow.key_secret,
+ n_threads, errp);
}
}
@@ -133,7 +135,7 @@ qcrypto_block_qcow_create(QCryptoBlock *block,
return -1;
}
/* QCow2 has no special header, since everything is hardwired */
- return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
+ return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, 1, errp);
}
@@ -152,8 +154,7 @@ qcrypto_block_qcow_decrypt(QCryptoBlock *block,
{
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
- return qcrypto_block_decrypt_helper(block->cipher,
- block->niv, block->ivgen,
+ return qcrypto_block_decrypt_helper(block,
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
offset, buf, len, errp);
}
@@ -168,8 +169,7 @@ qcrypto_block_qcow_encrypt(QCryptoBlock *block,
{
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
- return qcrypto_block_encrypt_helper(block->cipher,
- block->niv, block->ivgen,
+ return qcrypto_block_encrypt_helper(block,
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
offset, buf, len, errp);
}
diff --git a/crypto/block.c b/crypto/block.c
index e59d1140fe..d70d401f87 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -52,6 +52,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
+ size_t n_threads,
Error **errp)
{
QCryptoBlock *block = g_new0(QCryptoBlock, 1);
@@ -69,11 +70,14 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
block->driver = qcrypto_block_drivers[options->format];
if (block->driver->open(block, options, optprefix,
- readfunc, opaque, flags, errp) < 0) {
+ readfunc, opaque, flags, n_threads, errp) < 0)
+ {
g_free(block);
return NULL;
}
+ qemu_mutex_init(&block->mutex);
+
return block;
}
@@ -105,6 +109,8 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
return NULL;
}
+ qemu_mutex_init(&block->mutex);
+
return block;
}
@@ -148,12 +154,97 @@ int qcrypto_block_encrypt(QCryptoBlock *block,
QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
{
- return block->cipher;
+ /* Ciphers should be accessed through pop/push method to be thread-safe.
+ * Better, they should not be accessed externally at all (note, that
+ * pop/push are static functions)
+ * This function is used only in test with one thread (it's safe to skip
+ * pop/push interface), so it's enough to assert it here:
+ */
+ assert(block->n_ciphers <= 1);
+ return block->ciphers ? block->ciphers[0] : NULL;
+}
+
+
+static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
+{
+ QCryptoCipher *cipher;
+
+ qemu_mutex_lock(&block->mutex);
+
+ assert(block->n_free_ciphers > 0);
+ block->n_free_ciphers--;
+ cipher = block->ciphers[block->n_free_ciphers];
+
+ qemu_mutex_unlock(&block->mutex);
+
+ return cipher;
+}
+
+
+static void qcrypto_block_push_cipher(QCryptoBlock *block,
+ QCryptoCipher *cipher)
+{
+ qemu_mutex_lock(&block->mutex);
+
+ assert(block->n_free_ciphers < block->n_ciphers);
+ block->ciphers[block->n_free_ciphers] = cipher;
+ block->n_free_ciphers++;
+
+ qemu_mutex_unlock(&block->mutex);
}
+int qcrypto_block_init_cipher(QCryptoBlock *block,
+ QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key, size_t nkey,
+ size_t n_threads, Error **errp)
+{
+ size_t i;
+
+ assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
+
+ block->ciphers = g_new0(QCryptoCipher *, n_threads);
+
+ for (i = 0; i < n_threads; i++) {
+ block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
+ if (!block->ciphers[i]) {
+ qcrypto_block_free_cipher(block);
+ return -1;
+ }
+ block->n_ciphers++;
+ block->n_free_ciphers++;
+ }
+
+ return 0;
+}
+
+
+void qcrypto_block_free_cipher(QCryptoBlock *block)
+{
+ size_t i;
+
+ if (!block->ciphers) {
+ return;
+ }
+
+ assert(block->n_ciphers == block->n_free_ciphers);
+
+ for (i = 0; i < block->n_ciphers; i++) {
+ qcrypto_cipher_free(block->ciphers[i]);
+ }
+
+ g_free(block->ciphers);
+ block->ciphers = NULL;
+ block->n_ciphers = block->n_free_ciphers = 0;
+}
+
QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
{
+ /* ivgen should be accessed under mutex. However, this function is used only
+ * in test with one thread, so it's enough to assert it here:
+ */
+ assert(block->n_ciphers <= 1);
return block->ivgen;
}
@@ -184,20 +275,29 @@ void qcrypto_block_free(QCryptoBlock *block)
block->driver->cleanup(block);
- qcrypto_cipher_free(block->cipher);
+ qcrypto_block_free_cipher(block);
qcrypto_ivgen_free(block->ivgen);
+ qemu_mutex_destroy(&block->mutex);
g_free(block);
}
-int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
- size_t niv,
- QCryptoIVGen *ivgen,
- int sectorsize,
- uint64_t offset,
- uint8_t *buf,
- size_t len,
- Error **errp)
+typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
+ const void *in,
+ void *out,
+ size_t len,
+ Error **errp);
+
+static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
+ size_t niv,
+ QCryptoIVGen *ivgen,
+ QemuMutex *ivgen_mutex,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ QCryptoCipherEncDecFunc func,
+ Error **errp)
{
uint8_t *iv;
int ret = -1;
@@ -211,10 +311,15 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
while (len > 0) {
size_t nbytes;
if (niv) {
- if (qcrypto_ivgen_calculate(ivgen,
- startsector,
- iv, niv,
- errp) < 0) {
+ if (ivgen_mutex) {
+ qemu_mutex_lock(ivgen_mutex);
+ }
+ ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
+ if (ivgen_mutex) {
+ qemu_mutex_unlock(ivgen_mutex);
+ }
+
+ if (ret < 0) {
goto cleanup;
}
@@ -226,8 +331,7 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
}
nbytes = len > sectorsize ? sectorsize : len;
- if (qcrypto_cipher_decrypt(cipher, buf, buf,
- nbytes, errp) < 0) {
+ if (func(cipher, buf, buf, nbytes, errp) < 0) {
goto cleanup;
}
@@ -243,54 +347,69 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
}
-int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
- size_t niv,
- QCryptoIVGen *ivgen,
+int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
+ size_t niv,
+ QCryptoIVGen *ivgen,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ Error **errp)
+{
+ return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
+ offset, buf, len,
+ qcrypto_cipher_decrypt, errp);
+}
+
+
+int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
+ size_t niv,
+ QCryptoIVGen *ivgen,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ Error **errp)
+{
+ return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
+ offset, buf, len,
+ qcrypto_cipher_encrypt, errp);
+}
+
+int qcrypto_block_decrypt_helper(QCryptoBlock *block,
int sectorsize,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp)
{
- uint8_t *iv;
- int ret = -1;
- uint64_t startsector = offset / sectorsize;
+ int ret;
+ QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
- assert(QEMU_IS_ALIGNED(offset, sectorsize));
- assert(QEMU_IS_ALIGNED(len, sectorsize));
+ ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
+ &block->mutex, sectorsize, offset, buf,
+ len, qcrypto_cipher_decrypt, errp);
- iv = niv ? g_new0(uint8_t, niv) : NULL;
+ qcrypto_block_push_cipher(block, cipher);
- while (len > 0) {
- size_t nbytes;
- if (niv) {
- if (qcrypto_ivgen_calculate(ivgen,
- startsector,
- iv, niv,
- errp) < 0) {
- goto cleanup;
- }
+ return ret;
+}
- if (qcrypto_cipher_setiv(cipher,
- iv, niv,
- errp) < 0) {
- goto cleanup;
- }
- }
+int qcrypto_block_encrypt_helper(QCryptoBlock *block,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ Error **errp)
+{
+ int ret;
+ QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
- nbytes = len > sectorsize ? sectorsize : len;
- if (qcrypto_cipher_encrypt(cipher, buf, buf,
- nbytes, errp) < 0) {
- goto cleanup;
- }
+ ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
+ &block->mutex, sectorsize, offset, buf,
+ len, qcrypto_cipher_encrypt, errp);
- startsector++;
- buf += nbytes;
- len -= nbytes;
- }
+ qcrypto_block_push_cipher(block, cipher);
- ret = 0;
- cleanup:
- g_free(iv);
return ret;
}
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
index 41840abcec..5438e822fd 100644
--- a/crypto/blockpriv.h
+++ b/crypto/blockpriv.h
@@ -22,6 +22,7 @@
#define QCRYPTO_BLOCKPRIV_H
#include "crypto/block.h"
+#include "qemu/thread.h"
typedef struct QCryptoBlockDriver QCryptoBlockDriver;
@@ -31,8 +32,12 @@ struct QCryptoBlock {
const QCryptoBlockDriver *driver;
void *opaque;
- QCryptoCipher *cipher;
+ QCryptoCipher **ciphers;
+ size_t n_ciphers;
+ size_t n_free_ciphers;
QCryptoIVGen *ivgen;
+ QemuMutex mutex;
+
QCryptoHashAlgorithm kdfhash;
size_t niv;
uint64_t payload_offset; /* In bytes */
@@ -46,6 +51,7 @@ struct QCryptoBlockDriver {
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
+ size_t n_threads,
Error **errp);
int (*create)(QCryptoBlock *block,
@@ -78,22 +84,44 @@ struct QCryptoBlockDriver {
};
-int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
- size_t niv,
- QCryptoIVGen *ivgen,
+int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
+ size_t niv,
+ QCryptoIVGen *ivgen,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ Error **errp);
+
+int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
+ size_t niv,
+ QCryptoIVGen *ivgen,
+ int sectorsize,
+ uint64_t offset,
+ uint8_t *buf,
+ size_t len,
+ Error **errp);
+
+int qcrypto_block_decrypt_helper(QCryptoBlock *block,
int sectorsize,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
-int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
- size_t niv,
- QCryptoIVGen *ivgen,
+int qcrypto_block_encrypt_helper(QCryptoBlock *block,
int sectorsize,
uint64_t offset,
uint8_t *buf,
size_t len,
Error **errp);
+int qcrypto_block_init_cipher(QCryptoBlock *block,
+ QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key, size_t nkey,
+ size_t n_threads, Error **errp);
+
+void qcrypto_block_free_cipher(QCryptoBlock *block);
+
#endif /* QCRYPTO_BLOCKPRIV_H */
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index aec2855750..7f34ad0528 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -16,6 +16,8 @@ CONFIG_VIRTIO_VGA=y
CONFIG_XICS=$(CONFIG_PSERIES)
CONFIG_XICS_SPAPR=$(CONFIG_PSERIES)
CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM))
+CONFIG_XIVE=$(CONFIG_PSERIES)
+CONFIG_XIVE_SPAPR=$(CONFIG_PSERIES)
CONFIG_MEM_DEVICE=y
CONFIG_DIMM=y
CONFIG_SPAPR_RNG=y
diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak
index 7937c69e22..c9c5971409 100644
--- a/default-configs/riscv32-softmmu.mak
+++ b/default-configs/riscv32-softmmu.mak
@@ -1,7 +1,14 @@
# Default configuration for riscv-softmmu
+include pci.mak
+include usb.mak
+
CONFIG_SERIAL=y
CONFIG_VIRTIO_MMIO=y
-include virtio.mak
CONFIG_CADENCE=y
+
+CONFIG_PCI_GENERIC=y
+
+CONFIG_VGA=y
+CONFIG_VGA_PCI=y
diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak
index 7937c69e22..c9c5971409 100644
--- a/default-configs/riscv64-softmmu.mak
+++ b/default-configs/riscv64-softmmu.mak
@@ -1,7 +1,14 @@
# Default configuration for riscv-softmmu
+include pci.mak
+include usb.mak
+
CONFIG_SERIAL=y
CONFIG_VIRTIO_MMIO=y
-include virtio.mak
CONFIG_CADENCE=y
+
+CONFIG_PCI_GENERIC=y
+
+CONFIG_VGA=y
+CONFIG_VGA_PCI=y
diff --git a/default-configs/virtio.mak b/default-configs/virtio.mak
index 1304849018..ecb4420e74 100644
--- a/default-configs/virtio.mak
+++ b/default-configs/virtio.mak
@@ -1,7 +1,7 @@
CONFIG_VHOST_USER_SCSI=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
CONFIG_VHOST_USER_BLK=$(call land,$(CONFIG_VHOST_USER),$(CONFIG_LINUX))
CONFIG_VIRTIO=y
-CONFIG_VIRTIO_9P=y
+CONFIG_VIRTIO_9P=$(CONFIG_VIRTFS)
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_CRYPTO=y
@@ -12,3 +12,4 @@ CONFIG_VIRTIO_RNG=y
CONFIG_SCSI=y
CONFIG_VIRTIO_SCSI=y
CONFIG_VIRTIO_SERIAL=y
+CONFIG_VIRTIO_INPUT_HOST=$(CONFIG_LINUX)
diff --git a/device_tree.c b/device_tree.c
index 6d9c9726f6..296278e12a 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -91,7 +91,7 @@ void *load_device_tree(const char *filename_path, int *sizep)
/* First allocate space in qemu for device tree */
fdt = g_malloc0(dt_size);
- dt_file_load_size = load_image(filename_path, fdt);
+ dt_file_load_size = load_image_size(filename_path, fdt, dt_size);
if (dt_file_load_size < 0) {
error_report("Unable to open device tree file '%s'",
filename_path);
diff --git a/disas.c b/disas.c
index 5325b7e6be..d9aa713a40 100644
--- a/disas.c
+++ b/disas.c
@@ -522,8 +522,14 @@ void disas(FILE *out, void *code, unsigned long size)
# ifdef _ARCH_PPC64
s.info.cap_mode = CS_MODE_64;
# endif
-#elif defined(__riscv__)
- print_insn = print_insn_riscv;
+#elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
+#if defined(_ILP32) || (__riscv_xlen == 32)
+ print_insn = print_insn_riscv32;
+#elif defined(_LP64)
+ print_insn = print_insn_riscv64;
+#else
+#error unsupported RISC-V ABI
+#endif
#elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
print_insn = print_insn_arm_a64;
s.info.cap_arch = CS_ARCH_ARM64;
@@ -588,7 +594,10 @@ static int
physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info)
{
- cpu_physical_memory_read(memaddr, myaddr, length);
+ CPUDebug *s = container_of(info, CPUDebug, info);
+
+ address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
+ myaddr, length);
return 0;
}
diff --git a/disas/alpha.c b/disas/alpha.c
index b7b0ae0d92..a0c9ecd49d 100644
--- a/disas/alpha.c
+++ b/disas/alpha.c
@@ -672,7 +672,7 @@ extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
OPCODE is the instruction opcode.
MASK is the opcode mask; this is used to tell the disassembler
- which bits in the actual opcode must match OPCODE.
+ which bits in the actual opcode must match OPCODE.
OPERANDS is the list of operands.
@@ -699,10 +699,10 @@ extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
And two annotations:
EV56 BUT opcodes that are officially introduced as of the ev56,
- but with defined results on previous implementations.
+ but with defined results on previous implementations.
EV56 UNA opcodes that were introduced as of the ev56 with
- presumably undefined results on previous implementations
+ presumably undefined results on previous implementations
that were not assigned to a particular extension.
*/
@@ -832,7 +832,7 @@ const struct alpha_opcode alpha_opcodes[] = {
{ "cmovgt", OPR(0x11,0x66), BASE, ARG_OPR },
{ "cmovgt", OPRL(0x11,0x66), BASE, ARG_OPRL },
{ "implver", OPRL_(0x11,0x6C)|(31<<21)|(1<<13),
- 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */
+ 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */
{ "mskbl", OPR(0x12,0x02), BASE, ARG_OPR },
{ "mskbl", OPRL(0x12,0x02), BASE, ARG_OPRL },
diff --git a/disas/arm.c b/disas/arm.c
index dda7b2a943..17ea120b44 100644
--- a/disas/arm.c
+++ b/disas/arm.c
@@ -1077,7 +1077,7 @@ static const struct opcode32 arm_opcodes[] =
%S print Thumb register (bits 3..5 as high number if bit 6 set)
%D print Thumb register (bits 0..2 as high number if bit 7 set)
%<bitfield>I print bitfield as a signed decimal
- (top bit of range being the sign bit)
+ (top bit of range being the sign bit)
%N print Thumb register mask (with LR)
%O print Thumb register mask (with PC)
%M print Thumb register mask
diff --git a/disas/i386.c b/disas/i386.c
index a557e678ec..fc03b9f06a 100644
--- a/disas/i386.c
+++ b/disas/i386.c
@@ -6075,7 +6075,7 @@ OP_EM (int bytemode, int sizeflag)
{
bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
used_prefixes |= (prefixes & PREFIX_DATA);
- }
+ }
OP_E (bytemode, sizeflag);
return;
}
@@ -6112,7 +6112,7 @@ OP_EMC (int bytemode, int sizeflag)
{
bytemode = (prefixes & PREFIX_DATA) ? x_mode : q_mode;
used_prefixes |= (prefixes & PREFIX_DATA);
- }
+ }
OP_E (bytemode, sizeflag);
return;
}
diff --git a/disas/m68k.c b/disas/m68k.c
index 0dc8aa1a3c..e544c7137f 100644
--- a/disas/m68k.c
+++ b/disas/m68k.c
@@ -350,7 +350,7 @@ struct m68k_opcode_alias
* all (modes 0-6,7.0-4)
~ alterable memory (modes 2-6,7.0,7.1)
- (not 0,1,7.2-4)
+ (not 0,1,7.2-4)
% alterable (modes 0-6,7.0,7.1)
(not 7.2-4)
; data (modes 0,2-6,7.0-4)
@@ -1647,7 +1647,7 @@ print_insn_arg (const char *d,
case 0x15: name = "%val"; break;
case 0x16: name = "%scc"; break;
case 0x17: name = "%ac"; break;
- case 0x18: name = "%psr"; break;
+ case 0x18: name = "%psr"; break;
case 0x19: name = "%pcsr"; break;
case 0x1c:
case 0x1d:
diff --git a/disas/microblaze.c b/disas/microblaze.c
index 598ecbc89d..c23605043a 100644
--- a/disas/microblaze.c
+++ b/disas/microblaze.c
@@ -176,7 +176,6 @@ enum microblaze_instr_type {
#define REG_TLBSX 36869 /* MMU: TLB Search Index reg */
/* alternate names for gen purpose regs */
-#define REG_SP 1 /* stack pointer */
#define REG_ROSDP 2 /* read-only small data pointer */
#define REG_RWSDP 13 /* read-write small data pointer */
diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp
index 1238c2ff33..17f4c22d4f 100644
--- a/disas/nanomips.cpp
+++ b/disas/nanomips.cpp
@@ -1,13 +1,13 @@
/*
* Source file for nanoMIPS disassembler component of QEMU
*
- * Copyright (C) 2018 Wave Computing
+ * Copyright (C) 2018 Wave Computing, Inc.
* Copyright (C) 2018 Matthew Fortune <matthew.fortune@mips.com>
- * Copyright (C) 2018 Aleksandar Markovic <aleksandar.markovic@wavecomp.com>
+ * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com>
*
* 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, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
@@ -17,6 +17,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * Documentation used while implementing this component:
+ *
+ * [1] "MIPS® Architecture Base: nanoMIPS32(tm) Instruction Set Technical
+ * Reference Manual", Revision 01.01, April 27, 2018
*/
extern "C" {
@@ -258,7 +266,7 @@ namespace img
std::string to_string(img::address a)
{
char buffer[256];
- sprintf(buffer, "0x%08llx", a);
+ sprintf(buffer, "0x%" PRIx64, a);
return buffer;
}
@@ -284,69 +292,265 @@ uint64 NMD::renumber_registers(uint64 index, uint64 *register_list,
}
throw std::runtime_error(img::format(
- "Invalid register mapping index %d, size of list = %d",
+ "Invalid register mapping index %" PRIu64
+ ", size of list = %zu",
index, register_list_size));
}
/*
- * these functions should be decode functions but the json does not have
- * decode sections so they are based on the encode, the equivalent decode
- * functions need writing eventually.
+ * NMD::decode_gpr_gpr4() - decoder for 'gpr4' gpr encoding type
+ *
+ * Map a 4-bit code to the 5-bit register space according to this pattern:
+ *
+ * 1 0
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | └---------------┐
+ * | | | | | | | | | | └---------------┐ |
+ * | | | | | | | | | └---------------┐ | |
+ * | | | | | | | | └---------------┐ | | |
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * Used in handling following instructions:
+ *
+ * - ADDU[4X4]
+ * - LW[4X4]
+ * - MOVEP[REV]
+ * - MUL[4X4]
+ * - SW[4X4]
*/
-uint64 NMD::encode_gpr3(uint64 d)
+uint64 NMD::decode_gpr_gpr4(uint64 d)
{
- static uint64 register_list[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
+ static uint64 register_list[] = { 8, 9, 10, 11, 4, 5, 6, 7,
+ 16, 17, 18, 19, 20, 21, 22, 23 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_gpr3_store(uint64 d)
+/*
+ * NMD::decode_gpr_gpr4_zero() - decoder for 'gpr4.zero' gpr encoding type
+ *
+ * Map a 4-bit code to the 5-bit register space according to this pattern:
+ *
+ * 1 0
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | └---------------------┐
+ * | | | | | | | | | | | └---------------┐ |
+ * | | | | | | | | | | └---------------┐ | |
+ * | | | | | | | | | └---------------┐ | | |
+ * | | | | | | | | └---------------┐ | | | |
+ * | | | | | | | | | | | | | | | |
+ * | | | | | | | | | | | | | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * This pattern is the same one used for 'gpr4' gpr encoding type, except for
+ * the input value 3, that is mapped to the output value 0 instead of 11.
+ *
+ * Used in handling following instructions:
+ *
+ * - MOVE.BALC
+ * - MOVEP
+ * - SW[4X4]
+ */
+uint64 NMD::decode_gpr_gpr4_zero(uint64 d)
{
- static uint64 register_list[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
+ static uint64 register_list[] = { 8, 9, 10, 0, 4, 5, 6, 7,
+ 16, 17, 18, 19, 20, 21, 22, 23 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_rd1_from_rd(uint64 d)
+/*
+ * NMD::decode_gpr_gpr3() - decoder for 'gpr3' gpr encoding type
+ *
+ * Map a 3-bit code to the 5-bit register space according to this pattern:
+ *
+ * 7 6 5 4 3 2 1 0
+ * | | | | | | | |
+ * | | | | | | | |
+ * | | | └-----------------------┐
+ * | | └-----------------------┐ |
+ * | └-----------------------┐ | |
+ * └-----------------------┐ | | |
+ * | | | | | | | |
+ * ┌-------┘ | | | | | | |
+ * | ┌-------┘ | | | | | |
+ * | | ┌-------┘ | | | | |
+ * | | | ┌-------┘ | | | |
+ * | | | | | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * Used in handling following instructions:
+ *
+ * - ADDIU[R1.SP]
+ * - ADDIU[R2]
+ * - ADDU[16]
+ * - AND[16]
+ * - ANDI[16]
+ * - BEQC[16]
+ * - BEQZC[16]
+ * - BNEC[16]
+ * - BNEZC[16]
+ * - LB[16]
+ * - LBU[16]
+ * - LH[16]
+ * - LHU[16]
+ * - LI[16]
+ * - LW[16]
+ * - LW[GP16]
+ * - LWXS[16]
+ * - NOT[16]
+ * - OR[16]
+ * - SB[16]
+ * - SH[16]
+ * - SLL[16]
+ * - SRL[16]
+ * - SUBU[16]
+ * - SW[16]
+ * - XOR[16]
+ */
+uint64 NMD::decode_gpr_gpr3(uint64 d)
{
- static uint64 register_list[] = { 4, 5 };
+ static uint64 register_list[] = { 16, 17, 18, 19, 4, 5, 6, 7 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_gpr4_zero(uint64 d)
+/*
+ * NMD::decode_gpr_gpr3_src_store() - decoder for 'gpr3.src.store' gpr encoding
+ * type
+ *
+ * Map a 3-bit code to the 5-bit register space according to this pattern:
+ *
+ * 7 6 5 4 3 2 1 0
+ * | | | | | | | |
+ * | | | | | | | └-----------------------┐
+ * | | | └-----------------------┐ |
+ * | | └-----------------------┐ | |
+ * | └-----------------------┐ | | |
+ * └-----------------------┐ | | | |
+ * | | | | | | | |
+ * ┌-------┘ | | | | | | |
+ * | ┌-------┘ | | | | | |
+ * | | ┌-------┘ | | | | |
+ * | | | | | | | |
+ * | | | | | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * This pattern is the same one used for 'gpr3' gpr encoding type, except for
+ * the input value 0, that is mapped to the output value 0 instead of 16.
+ *
+ * Used in handling following instructions:
+ *
+ * - SB[16]
+ * - SH[16]
+ * - SW[16]
+ * - SW[GP16]
+ */
+uint64 NMD::decode_gpr_gpr3_src_store(uint64 d)
{
- static uint64 register_list[] = { 8, 9, 10, 0, 4, 5, 6, 7,
- 16, 17, 18, 19, 20, 21, 22, 23 };
+ static uint64 register_list[] = { 0, 17, 18, 19, 4, 5, 6, 7 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_gpr4(uint64 d)
+/*
+ * NMD::decode_gpr_gpr2_reg1() - decoder for 'gpr2.reg1' gpr encoding type
+ *
+ * Map a 2-bit code to the 5-bit register space according to this pattern:
+ *
+ * 3 2 1 0
+ * | | | |
+ * | | | |
+ * | | | └-------------------┐
+ * | | └-------------------┐ |
+ * | └-------------------┐ | |
+ * └-------------------┐ | | |
+ * | | | |
+ * | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * Used in handling following instructions:
+ *
+ * - MOVEP
+ * - MOVEP[REV]
+ */
+uint64 NMD::decode_gpr_gpr2_reg1(uint64 d)
{
- static uint64 register_list[] = { 8, 9, 10, 11, 4, 5, 6, 7,
- 16, 17, 18, 19, 20, 21, 22, 23 };
+ static uint64 register_list[] = { 4, 5, 6, 7 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_rd2_reg1(uint64 d)
+/*
+ * NMD::decode_gpr_gpr2_reg2() - decoder for 'gpr2.reg2' gpr encoding type
+ *
+ * Map a 2-bit code to the 5-bit register space according to this pattern:
+ *
+ * 3 2 1 0
+ * | | | |
+ * | | | |
+ * | | | └-----------------┐
+ * | | └-----------------┐ |
+ * | └-----------------┐ | |
+ * └-----------------┐ | | |
+ * | | | |
+ * | | | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * Used in handling following instructions:
+ *
+ * - MOVEP
+ * - MOVEP[REV]
+ */
+uint64 NMD::decode_gpr_gpr2_reg2(uint64 d)
{
- static uint64 register_list[] = { 4, 5, 6, 7 };
+ static uint64 register_list[] = { 5, 6, 7, 8 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
-uint64 NMD::encode_rd2_reg2(uint64 d)
+/*
+ * NMD::decode_gpr_gpr1() - decoder for 'gpr1' gpr encoding type
+ *
+ * Map a 1-bit code to the 5-bit register space according to this pattern:
+ *
+ * 1 0
+ * | |
+ * | |
+ * | └---------------------┐
+ * └---------------------┐ |
+ * | |
+ * | |
+ * | |
+ * | |
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * 3 2 1 0
+ *
+ * Used in handling following instruction:
+ *
+ * - MOVE.BALC
+ */
+uint64 NMD::decode_gpr_gpr1(uint64 d)
{
- static uint64 register_list[] = { 5, 6, 7, 8 };
+ static uint64 register_list[] = { 4, 5 };
return renumber_registers(d, register_list,
sizeof(register_list) / sizeof(register_list[0]));
}
@@ -379,14 +583,14 @@ int64 NMD::neg_copy(int64 d)
/* strange wrapper around gpr3 */
uint64 NMD::encode_rs3_and_check_rs3_ge_rt3(uint64 d)
{
-return encode_gpr3(d);
+return decode_gpr_gpr3(d);
}
/* strange wrapper around gpr3 */
uint64 NMD::encode_rs3_and_check_rs3_lt_rt3(uint64 d)
{
- return encode_gpr3(d);
+ return decode_gpr_gpr3(d);
}
@@ -501,7 +705,8 @@ std::string NMD::GPR(uint64 reg)
return gpr_reg[reg];
}
- throw std::runtime_error(img::format("Invalid GPR register index %d", reg));
+ throw std::runtime_error(img::format("Invalid GPR register index %" PRIu64,
+ reg));
}
@@ -518,7 +723,8 @@ std::string NMD::FPR(uint64 reg)
return fpr_reg[reg];
}
- throw std::runtime_error(img::format("Invalid FPR register index %d", reg));
+ throw std::runtime_error(img::format("Invalid FPR register index %" PRIu64,
+ reg));
}
@@ -532,26 +738,27 @@ std::string NMD::AC(uint64 reg)
return ac_reg[reg];
}
- throw std::runtime_error(img::format("Invalid AC register index %d", reg));
+ throw std::runtime_error(img::format("Invalid AC register index %" PRIu64,
+ reg));
}
std::string NMD::IMMEDIATE(uint64 value)
{
- return img::format("0x%x", value);
+ return img::format("0x%" PRIx64, value);
}
std::string NMD::IMMEDIATE(int64 value)
{
- return img::format("%d", value);
+ return img::format("%" PRId64, value);
}
std::string NMD::CPR(uint64 reg)
{
/* needs more work */
- return img::format("CP%d", reg);
+ return img::format("CP%" PRIu64, reg);
}
@@ -682,7 +889,7 @@ uint64 NMD::extract_shift3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_uil3il3bs9Fmsb11(uint64 instruction)
+uint64 NMD::extract_u_11_10_9_8_7_6_5_4_3__s3(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 3, 9) << 3;
@@ -706,7 +913,7 @@ uint64 NMD::extract_rtz3_9_8_7(uint64 instruction)
}
-uint64 NMD::extr_uil1il1bs17Fmsb17(uint64 instruction)
+uint64 NMD::extract_u_17_to_1__s1(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 1, 17) << 1;
@@ -714,7 +921,7 @@ uint64 NMD::extr_uil1il1bs17Fmsb17(uint64 instruction)
}
-int64 NMD::extr_sil11il0bs10Tmsb9(uint64 instruction)
+int64 NMD::extract_s__se9_20_19_18_17_16_15_14_13_12_11(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 11, 10);
@@ -723,7 +930,7 @@ int64 NMD::extr_sil11il0bs10Tmsb9(uint64 instruction)
}
-int64 NMD::extr_sil0il11bs1_il1il1bs10Tmsb11(uint64 instruction)
+int64 NMD::extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 11;
@@ -766,7 +973,7 @@ uint64 NMD::extract_shift_4_3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_shiftxil7il1bs4Fmsb4(uint64 instruction)
+uint64 NMD::extract_shiftx_10_9_8_7__s1(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 7, 4) << 1;
@@ -790,7 +997,7 @@ uint64 NMD::extract_count3_14_13_12(uint64 instruction)
}
-int64 NMD::extr_sil0il31bs1_il2il21bs10_il12il12bs9Tmsb31(uint64 instruction)
+int64 NMD::extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 31;
@@ -801,7 +1008,7 @@ int64 NMD::extr_sil0il31bs1_il2il21bs10_il12il12bs9Tmsb31(uint64 instruction)
}
-int64 NMD::extr_sil0il7bs1_il1il1bs6Tmsb7(uint64 instruction)
+int64 NMD::extract_s__se7_0_6_5_4_3_2_1_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 7;
@@ -835,7 +1042,7 @@ uint64 NMD::extract_rs_20_19_18_17_16(uint64 instruction)
}
-uint64 NMD::extr_uil1il1bs2Fmsb2(uint64 instruction)
+uint64 NMD::extract_u_2_1__s1(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 1, 2) << 1;
@@ -851,23 +1058,6 @@ uint64 NMD::extract_stripe_6(uint64 instruction)
}
-uint64 NMD::extr_xil17il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 17, 1);
- return value;
-}
-
-
-uint64 NMD::extr_xil2il0bs1_il15il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 2, 1);
- value |= extract_bits(instruction, 15, 1);
- return value;
-}
-
-
uint64 NMD::extract_ac_13_12(uint64 instruction)
{
uint64 value = 0;
@@ -892,7 +1082,7 @@ uint64 NMD::extract_rdl_25_24(uint64 instruction)
}
-int64 NMD::extr_sil0il10bs1_il1il1bs9Tmsb10(uint64 instruction)
+int64 NMD::extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 10;
@@ -918,14 +1108,6 @@ uint64 NMD::extract_shift_5_4_3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_xil10il0bs6Fmsb5(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 10, 6);
- return value;
-}
-
-
uint64 NMD::extract_count_19_18_17_16(uint64 instruction)
{
uint64 value = 0;
@@ -942,15 +1124,6 @@ uint64 NMD::extract_code_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_xil10il0bs4_il22il0bs4Fmsb3(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 10, 4);
- value |= extract_bits(instruction, 22, 4);
- return value;
-}
-
-
uint64 NMD::extract_u_11_10_9_8_7_6_5_4_3_2_1_0(uint64 instruction)
{
uint64 value = 0;
@@ -967,7 +1140,7 @@ uint64 NMD::extract_rs_4_3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_uil3il3bs18Fmsb20(uint64 instruction)
+uint64 NMD::extract_u_20_to_3__s3(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 3, 18) << 3;
@@ -975,15 +1148,7 @@ uint64 NMD::extr_uil3il3bs18Fmsb20(uint64 instruction)
}
-uint64 NMD::extr_xil12il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 12, 1);
- return value;
-}
-
-
-uint64 NMD::extr_uil0il2bs4Fmsb5(uint64 instruction)
+uint64 NMD::extract_u_3_2_1_0__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 4) << 2;
@@ -999,7 +1164,7 @@ uint64 NMD::extract_cofun_25_24_23(uint64 instruction)
}
-uint64 NMD::extr_uil0il2bs3Fmsb4(uint64 instruction)
+uint64 NMD::extract_u_2_1_0__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 3) << 2;
@@ -1007,14 +1172,6 @@ uint64 NMD::extr_uil0il2bs3Fmsb4(uint64 instruction)
}
-uint64 NMD::extr_xil10il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 10, 1);
- return value;
-}
-
-
uint64 NMD::extract_rd3_3_2_1(uint64 instruction)
{
uint64 value = 0;
@@ -1047,22 +1204,6 @@ uint64 NMD::extract_ru_7_6_5_4_3(uint64 instruction)
}
-uint64 NMD::extr_xil21il0bs5Fmsb4(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 21, 5);
- return value;
-}
-
-
-uint64 NMD::extr_xil9il0bs3Fmsb2(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 9, 3);
- return value;
-}
-
-
uint64 NMD::extract_u_17_to_0(uint64 instruction)
{
uint64 value = 0;
@@ -1071,15 +1212,6 @@ uint64 NMD::extract_u_17_to_0(uint64 instruction)
}
-uint64 NMD::extr_xil14il0bs1_il15il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 14, 1);
- value |= extract_bits(instruction, 15, 1);
- return value;
-}
-
-
uint64 NMD::extract_rsz4_4_2_1_0(uint64 instruction)
{
uint64 value = 0;
@@ -1089,15 +1221,7 @@ uint64 NMD::extract_rsz4_4_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_xil24il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 24, 1);
- return value;
-}
-
-
-int64 NMD::extr_sil0il21bs1_il1il1bs20Tmsb21(uint64 instruction)
+int64 NMD::extract_s__se21_0_20_to_1_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 21;
@@ -1140,7 +1264,7 @@ uint64 NMD::extract_rt_41_40_39_38_37(uint64 instruction)
}
-int64 NMD::extract_shift_21_20_19_18_17_16(uint64 instruction)
+int64 NMD::extract_shift__se5_21_20_19_18_17_16(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 16, 6);
@@ -1149,15 +1273,6 @@ int64 NMD::extract_shift_21_20_19_18_17_16(uint64 instruction)
}
-uint64 NMD::extr_xil6il0bs3_il10il0bs1Fmsb2(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 6, 3);
- value |= extract_bits(instruction, 10, 1);
- return value;
-}
-
-
uint64 NMD::extract_rd2_3_8(uint64 instruction)
{
uint64 value = 0;
@@ -1167,14 +1282,6 @@ uint64 NMD::extract_rd2_3_8(uint64 instruction)
}
-uint64 NMD::extr_xil16il0bs5Fmsb4(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 16, 5);
- return value;
-}
-
-
uint64 NMD::extract_code_17_to_0(uint64 instruction)
{
uint64 value = 0;
@@ -1183,14 +1290,6 @@ uint64 NMD::extract_code_17_to_0(uint64 instruction)
}
-uint64 NMD::extr_xil0il0bs12Fmsb11(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 0, 12);
- return value;
-}
-
-
uint64 NMD::extract_size_20_19_18_17_16(uint64 instruction)
{
uint64 value = 0;
@@ -1199,7 +1298,7 @@ uint64 NMD::extract_size_20_19_18_17_16(uint64 instruction)
}
-int64 NMD::extr_sil2il2bs6_il15il8bs1Tmsb8(uint64 instruction)
+int64 NMD::extract_s__se8_15_7_6_5_4_3_2_s2(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 2, 6) << 2;
@@ -1217,7 +1316,7 @@ uint64 NMD::extract_u_15_to_0(uint64 instruction)
}
-uint64 NMD::extract_fs_15_14_13_12_11(uint64 instruction)
+uint64 NMD::extract_fs_20_19_18_17_16(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 16, 5);
@@ -1225,7 +1324,7 @@ uint64 NMD::extract_fs_15_14_13_12_11(uint64 instruction)
}
-int64 NMD::extr_sil0il0bs8_il15il8bs1Tmsb8(uint64 instruction)
+int64 NMD::extract_s__se8_15_7_6_5_4_3_2_1_0(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 8);
@@ -1259,15 +1358,6 @@ uint64 NMD::extract_hs_20_19_18_17_16(uint64 instruction)
}
-uint64 NMD::extr_xil10il0bs1_il14il0bs2Fmsb1(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 10, 1);
- value |= extract_bits(instruction, 14, 2);
- return value;
-}
-
-
uint64 NMD::extract_sel_13_12_11(uint64 instruction)
{
uint64 value = 0;
@@ -1284,14 +1374,6 @@ uint64 NMD::extract_lsb_4_3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_xil14il0bs2Fmsb1(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 14, 2);
- return value;
-}
-
-
uint64 NMD::extract_gp_2(uint64 instruction)
{
uint64 value = 0;
@@ -1308,7 +1390,7 @@ uint64 NMD::extract_rt3_9_8_7(uint64 instruction)
}
-uint64 NMD::extract_ft_20_19_18_17_16(uint64 instruction)
+uint64 NMD::extract_ft_25_24_23_22_21(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 21, 5);
@@ -1332,14 +1414,6 @@ uint64 NMD::extract_cs_20_19_18_17_16(uint64 instruction)
}
-uint64 NMD::extr_xil16il0bs10Fmsb9(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 16, 10);
- return value;
-}
-
-
uint64 NMD::extract_rt4_9_7_6_5(uint64 instruction)
{
uint64 value = 0;
@@ -1357,7 +1431,7 @@ uint64 NMD::extract_msbt_10_9_8_7_6(uint64 instruction)
}
-uint64 NMD::extr_uil0il2bs6Fmsb7(uint64 instruction)
+uint64 NMD::extract_u_5_4_3_2_1_0__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 6) << 2;
@@ -1365,14 +1439,6 @@ uint64 NMD::extr_uil0il2bs6Fmsb7(uint64 instruction)
}
-uint64 NMD::extr_xil17il0bs9Fmsb8(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 17, 9);
- return value;
-}
-
-
uint64 NMD::extract_sa_15_14_13(uint64 instruction)
{
uint64 value = 0;
@@ -1381,7 +1447,7 @@ uint64 NMD::extract_sa_15_14_13(uint64 instruction)
}
-int64 NMD::extr_sil0il14bs1_il1il1bs13Tmsb14(uint64 instruction)
+int64 NMD::extract_s__se14_0_13_to_1_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 14;
@@ -1399,7 +1465,7 @@ uint64 NMD::extract_rs3_6_5_4(uint64 instruction)
}
-uint64 NMD::extr_uil0il32bs32Fmsb63(uint64 instruction)
+uint64 NMD::extract_u_31_to_0__s32(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 32) << 32;
@@ -1447,7 +1513,7 @@ uint64 NMD::extract_op_25_24_23_22_21(uint64 instruction)
}
-uint64 NMD::extr_uil0il2bs7Fmsb8(uint64 instruction)
+uint64 NMD::extract_u_6_5_4_3_2_1_0__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 7) << 2;
@@ -1463,15 +1529,6 @@ uint64 NMD::extract_bit_16_15_14_13_12_11(uint64 instruction)
}
-uint64 NMD::extr_xil10il0bs1_il11il0bs5Fmsb4(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 10, 1);
- value |= extract_bits(instruction, 11, 5);
- return value;
-}
-
-
uint64 NMD::extract_mask_20_19_18_17_16_15_14(uint64 instruction)
{
uint64 value = 0;
@@ -1488,7 +1545,7 @@ uint64 NMD::extract_eu_3_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_uil4il4bs4Fmsb7(uint64 instruction)
+uint64 NMD::extract_u_7_6_5_4__s4(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 4, 4) << 4;
@@ -1496,7 +1553,7 @@ uint64 NMD::extr_uil4il4bs4Fmsb7(uint64 instruction)
}
-int64 NMD::extr_sil3il3bs5_il15il8bs1Tmsb8(uint64 instruction)
+int64 NMD::extract_s__se8_15_7_6_5_4_3_s3(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 3, 5) << 3;
@@ -1514,7 +1571,7 @@ uint64 NMD::extract_ft_15_14_13_12_11(uint64 instruction)
}
-int64 NMD::extr_sil0il16bs16_il16il0bs16Tmsb31(uint64 instruction)
+int64 NMD::extract_s__se31_15_to_0_31_to_16(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 16) << 16;
@@ -1532,23 +1589,7 @@ uint64 NMD::extract_u_20_19_18_17_16_15_14_13(uint64 instruction)
}
-uint64 NMD::extr_xil15il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 15, 1);
- return value;
-}
-
-
-uint64 NMD::extr_xil11il0bs5Fmsb4(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 11, 5);
- return value;
-}
-
-
-uint64 NMD::extr_uil2il2bs16Fmsb17(uint64 instruction)
+uint64 NMD::extract_u_17_to_2__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 2, 16) << 2;
@@ -1556,7 +1597,7 @@ uint64 NMD::extr_uil2il2bs16Fmsb17(uint64 instruction)
}
-uint64 NMD::extract_rd_20_19_18_17_16(uint64 instruction)
+uint64 NMD::extract_rd_15_14_13_12_11(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 11, 5);
@@ -1580,7 +1621,7 @@ uint64 NMD::extract_code_1_0(uint64 instruction)
}
-int64 NMD::extr_sil0il25bs1_il1il1bs24Tmsb25(uint64 instruction)
+int64 NMD::extract_s__se25_0_24_to_1_s1(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 1) << 25;
@@ -1590,15 +1631,6 @@ int64 NMD::extr_sil0il25bs1_il1il1bs24Tmsb25(uint64 instruction)
}
-uint64 NMD::extr_xil0il0bs3_il4il0bs1Fmsb2(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 0, 3);
- value |= extract_bits(instruction, 4, 1);
- return value;
-}
-
-
uint64 NMD::extract_u_1_0(uint64 instruction)
{
uint64 value = 0;
@@ -1607,7 +1639,7 @@ uint64 NMD::extract_u_1_0(uint64 instruction)
}
-uint64 NMD::extr_uil3il3bs1_il8il2bs1Fmsb3(uint64 instruction)
+uint64 NMD::extract_u_3_8__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 3, 1) << 3;
@@ -1616,16 +1648,7 @@ uint64 NMD::extr_uil3il3bs1_il8il2bs1Fmsb3(uint64 instruction)
}
-uint64 NMD::extr_xil9il0bs3_il16il0bs5Fmsb4(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 9, 3);
- value |= extract_bits(instruction, 16, 5);
- return value;
-}
-
-
-uint64 NMD::extract_fd_10_9_8_7_6(uint64 instruction)
+uint64 NMD::extract_fd_15_14_13_12_11(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 11, 5);
@@ -1633,15 +1656,7 @@ uint64 NMD::extract_fd_10_9_8_7_6(uint64 instruction)
}
-uint64 NMD::extr_xil6il0bs3Fmsb2(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 6, 3);
- return value;
-}
-
-
-uint64 NMD::extr_uil0il2bs5Fmsb6(uint64 instruction)
+uint64 NMD::extract_u_4_3_2_1_0__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 5) << 2;
@@ -1674,15 +1689,7 @@ uint64 NMD::extract_ct_25_24_23_22_21(uint64 instruction)
}
-uint64 NMD::extr_xil11il0bs1Fmsb0(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 11, 1);
- return value;
-}
-
-
-uint64 NMD::extr_uil2il2bs19Fmsb20(uint64 instruction)
+uint64 NMD::extract_u_20_to_2__s2(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 2, 19) << 2;
@@ -1690,7 +1697,7 @@ uint64 NMD::extr_uil2il2bs19Fmsb20(uint64 instruction)
}
-int64 NMD::extract_s_4_2_1_0(uint64 instruction)
+int64 NMD::extract_s__se3_4_2_1_0(uint64 instruction)
{
int64 value = 0;
value |= extract_bits(instruction, 0, 3);
@@ -1700,7 +1707,7 @@ int64 NMD::extract_s_4_2_1_0(uint64 instruction)
}
-uint64 NMD::extr_uil0il1bs4Fmsb4(uint64 instruction)
+uint64 NMD::extract_u_3_2_1_0__s1(uint64 instruction)
{
uint64 value = 0;
value |= extract_bits(instruction, 0, 4) << 1;
@@ -1708,14 +1715,6 @@ uint64 NMD::extr_uil0il1bs4Fmsb4(uint64 instruction)
}
-uint64 NMD::extr_xil9il0bs2Fmsb1(uint64 instruction)
-{
- uint64 value = 0;
- value |= extract_bits(instruction, 9, 2);
- return value;
-}
-
-
bool NMD::ADDIU_32__cond(uint64 instruction)
{
@@ -1742,7 +1741,7 @@ bool NMD::BEQC_16__cond(uint64 instruction)
{
uint64 rs3 = extract_rs3_6_5_4(instruction);
uint64 rt3 = extract_rt3_9_8_7(instruction);
- uint64 u = extr_uil0il1bs4Fmsb4(instruction);
+ uint64 u = extract_u_3_2_1_0__s1(instruction);
return rs3 < rt3 && u != 0;
}
@@ -1751,7 +1750,7 @@ bool NMD::BNEC_16__cond(uint64 instruction)
{
uint64 rs3 = extract_rs3_6_5_4(instruction);
uint64 rt3 = extract_rt3_9_8_7(instruction);
- uint64 u = extr_uil0il1bs4Fmsb4(instruction);
+ uint64 u = extract_u_3_2_1_0__s1(instruction);
return rs3 >= rt3 && u != 0;
}
@@ -1765,7 +1764,7 @@ bool NMD::MOVE_cond(uint64 instruction)
bool NMD::P16_BR1_cond(uint64 instruction)
{
- uint64 u = extr_uil0il1bs4Fmsb4(instruction);
+ uint64 u = extract_u_3_2_1_0__s1(instruction);
return u != 0;
}
@@ -1786,7 +1785,7 @@ bool NMD::PREFE_cond(uint64 instruction)
bool NMD::SLTU_cond(uint64 instruction)
{
- uint64 rd = extract_rd_20_19_18_17_16(instruction);
+ uint64 rd = extract_rd_15_14_13_12_11(instruction);
return rd != 0;
}
@@ -1804,8 +1803,8 @@ bool NMD::SLTU_cond(uint64 instruction)
*/
std::string NMD::ABS_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 fd_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string fs = FPR(copy(fs_value));
std::string fd = FPR(copy(fd_value));
@@ -1826,8 +1825,8 @@ std::string NMD::ABS_D(uint64 instruction)
*/
std::string NMD::ABS_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 fd_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string fs = FPR(copy(fs_value));
std::string fd = FPR(copy(fd_value));
@@ -1911,8 +1910,8 @@ std::string NMD::ABSQ_S_W(uint64 instruction)
std::string NMD::ACLR(uint64 instruction)
{
uint64 bit_value = extract_bit_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string bit = IMMEDIATE(copy(bit_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -1934,8 +1933,8 @@ std::string NMD::ACLR(uint64 instruction)
std::string NMD::ADD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -1958,9 +1957,9 @@ std::string NMD::ADD(uint64 instruction)
*/
std::string NMD::ADD_D(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -1983,9 +1982,9 @@ std::string NMD::ADD_D(uint64 instruction)
*/
std::string NMD::ADD_S(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -2007,8 +2006,8 @@ std::string NMD::ADD_S(uint64 instruction)
std::string NMD::ADDIU_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_15_to_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_15_to_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -2030,7 +2029,7 @@ std::string NMD::ADDIU_32_(uint64 instruction)
std::string NMD::ADDIU_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -2051,7 +2050,7 @@ std::string NMD::ADDIU_48_(uint64 instruction)
std::string NMD::ADDIU_GP48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -2093,7 +2092,7 @@ std::string NMD::ADDIU_GP_B_(uint64 instruction)
std::string NMD::ADDIU_GP_W_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil2il2bs19Fmsb20(instruction);
+ uint64 u_value = extract_u_20_to_2__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -2114,8 +2113,8 @@ std::string NMD::ADDIU_GP_W_(uint64 instruction)
std::string NMD::ADDIU_NEG_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -2136,10 +2135,10 @@ std::string NMD::ADDIU_NEG_(uint64 instruction)
*/
std::string NMD::ADDIU_R1_SP_(uint64 instruction)
{
- uint64 u_value = extr_uil0il2bs6Fmsb7(instruction);
+ uint64 u_value = extract_u_5_4_3_2_1_0__s2(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
return img::format("ADDIU %s, $%d, %s", rt3, 29, u);
@@ -2157,12 +2156,12 @@ std::string NMD::ADDIU_R1_SP_(uint64 instruction)
*/
std::string NMD::ADDIU_R2_(uint64 instruction)
{
- uint64 u_value = extr_uil0il2bs3Fmsb4(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_2_1_0__s2(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
std::string u = IMMEDIATE(copy(u_value));
return img::format("ADDIU %s, %s, %s", rt3, rs3, u);
@@ -2180,7 +2179,7 @@ std::string NMD::ADDIU_R2_(uint64 instruction)
std::string NMD::ADDIU_RS5_(uint64 instruction)
{
uint64 rt_value = extract_rt_9_8_7_6_5(instruction);
- int64 s_value = extract_s_4_2_1_0(instruction);
+ int64 s_value = extract_s__se3_4_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -2202,7 +2201,7 @@ std::string NMD::ADDIU_RS5_(uint64 instruction)
std::string NMD::ADDIUPC_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il21bs1_il1il1bs20Tmsb21(instruction);
+ int64 s_value = extract_s__se21_0_20_to_1_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -2224,7 +2223,7 @@ std::string NMD::ADDIUPC_32_(uint64 instruction)
std::string NMD::ADDIUPC_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 6);
@@ -2246,8 +2245,8 @@ std::string NMD::ADDIUPC_48_(uint64 instruction)
std::string NMD::ADDQ_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2270,8 +2269,8 @@ std::string NMD::ADDQ_PH(uint64 instruction)
std::string NMD::ADDQ_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2294,8 +2293,8 @@ std::string NMD::ADDQ_S_PH(uint64 instruction)
std::string NMD::ADDQ_S_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2319,8 +2318,8 @@ std::string NMD::ADDQ_S_W(uint64 instruction)
std::string NMD::ADDQH_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2344,8 +2343,8 @@ std::string NMD::ADDQH_PH(uint64 instruction)
std::string NMD::ADDQH_R_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2368,8 +2367,8 @@ std::string NMD::ADDQH_R_PH(uint64 instruction)
std::string NMD::ADDQH_R_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2392,8 +2391,8 @@ std::string NMD::ADDQH_R_W(uint64 instruction)
std::string NMD::ADDQH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2416,8 +2415,8 @@ std::string NMD::ADDQH_W(uint64 instruction)
std::string NMD::ADDSC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2442,9 +2441,9 @@ std::string NMD::ADDU_16_(uint64 instruction)
uint64 rs3_value = extract_rs3_6_5_4(instruction);
uint64 rd3_value = extract_rd3_3_2_1(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
- std::string rd3 = GPR(encode_gpr3(rd3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
+ std::string rd3 = GPR(decode_gpr_gpr3(rd3_value));
return img::format("ADDU %s, %s, %s", rd3, rs3, rt3);
}
@@ -2463,8 +2462,8 @@ std::string NMD::ADDU_16_(uint64 instruction)
std::string NMD::ADDU_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2486,11 +2485,11 @@ std::string NMD::ADDU_32_(uint64 instruction)
*/
std::string NMD::ADDU_4X4_(uint64 instruction)
{
- uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
uint64 rt4_value = extract_rt4_9_7_6_5(instruction);
+ uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
- std::string rs4 = GPR(encode_gpr4(rs4_value));
- std::string rt4 = GPR(encode_gpr4(rt4_value));
+ std::string rs4 = GPR(decode_gpr_gpr4(rs4_value));
+ std::string rt4 = GPR(decode_gpr_gpr4(rt4_value));
return img::format("ADDU %s, %s", rs4, rt4);
}
@@ -2509,8 +2508,8 @@ std::string NMD::ADDU_4X4_(uint64 instruction)
std::string NMD::ADDU_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2533,8 +2532,8 @@ std::string NMD::ADDU_PH(uint64 instruction)
std::string NMD::ADDU_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2557,8 +2556,8 @@ std::string NMD::ADDU_QB(uint64 instruction)
std::string NMD::ADDU_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2581,8 +2580,8 @@ std::string NMD::ADDU_S_PH(uint64 instruction)
std::string NMD::ADDU_S_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2606,8 +2605,8 @@ std::string NMD::ADDU_S_QB(uint64 instruction)
std::string NMD::ADDUH_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2631,8 +2630,8 @@ std::string NMD::ADDUH_QB(uint64 instruction)
std::string NMD::ADDUH_R_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2654,8 +2653,8 @@ std::string NMD::ADDUH_R_QB(uint64 instruction)
std::string NMD::ADDWC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2678,7 +2677,7 @@ std::string NMD::ADDWC(uint64 instruction)
std::string NMD::ALUIPC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il31bs1_il2il21bs10_il12il12bs9Tmsb31(instruction);
+ int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -2701,8 +2700,8 @@ std::string NMD::AND_16_(uint64 instruction)
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("AND %s, %s", rs3, rt3);
}
@@ -2721,8 +2720,8 @@ std::string NMD::AND_16_(uint64 instruction)
std::string NMD::AND_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -2747,8 +2746,8 @@ std::string NMD::ANDI_16_(uint64 instruction)
uint64 rs3_value = extract_rs3_6_5_4(instruction);
uint64 eu_value = extract_eu_3_2_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
std::string eu = IMMEDIATE(encode_eu_from_u_andi16(eu_value));
return img::format("ANDI %s, %s, %s", rt3, rs3, eu);
@@ -2768,8 +2767,8 @@ std::string NMD::ANDI_16_(uint64 instruction)
std::string NMD::ANDI_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -2792,8 +2791,8 @@ std::string NMD::ANDI_32_(uint64 instruction)
std::string NMD::APPEND(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -2816,8 +2815,8 @@ std::string NMD::APPEND(uint64 instruction)
std::string NMD::ASET(uint64 instruction)
{
uint64 bit_value = extract_bit_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string bit = IMMEDIATE(copy(bit_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -2839,7 +2838,7 @@ std::string NMD::ASET(uint64 instruction)
*/
std::string NMD::BALC_16_(uint64 instruction)
{
- int64 s_value = extr_sil0il10bs1_il1il1bs9Tmsb10(instruction);
+ int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction);
std::string s = ADDRESS(encode_s_from_address(s_value), 2);
@@ -2859,7 +2858,7 @@ std::string NMD::BALC_16_(uint64 instruction)
*/
std::string NMD::BALC_32_(uint64 instruction)
{
- int64 s_value = extr_sil0il25bs1_il1il1bs24Tmsb25(instruction);
+ int64 s_value = extract_s__se25_0_24_to_1_s1(instruction);
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -2903,7 +2902,7 @@ std::string NMD::BBEQZC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string bit = IMMEDIATE(copy(bit_value));
@@ -2927,7 +2926,7 @@ std::string NMD::BBNEZC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
uint64 bit_value = extract_bit_16_15_14_13_12_11(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string bit = IMMEDIATE(copy(bit_value));
@@ -2949,7 +2948,7 @@ std::string NMD::BBNEZC(uint64 instruction)
*/
std::string NMD::BC_16_(uint64 instruction)
{
- int64 s_value = extr_sil0il10bs1_il1il1bs9Tmsb10(instruction);
+ int64 s_value = extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(instruction);
std::string s = ADDRESS(encode_s_from_address(s_value), 2);
@@ -2969,7 +2968,7 @@ std::string NMD::BC_16_(uint64 instruction)
*/
std::string NMD::BC_32_(uint64 instruction)
{
- int64 s_value = extr_sil0il25bs1_il1il1bs24Tmsb25(instruction);
+ int64 s_value = extract_s__se25_0_24_to_1_s1(instruction);
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -2989,8 +2988,8 @@ std::string NMD::BC_32_(uint64 instruction)
*/
std::string NMD::BC1EQZC(uint64 instruction)
{
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -3011,8 +3010,8 @@ std::string NMD::BC1EQZC(uint64 instruction)
*/
std::string NMD::BC1NEZC(uint64 instruction)
{
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -3033,8 +3032,8 @@ std::string NMD::BC1NEZC(uint64 instruction)
*/
std::string NMD::BC2EQZC(uint64 instruction)
{
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 ct_value = extract_ct_25_24_23_22_21(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string ct = CPR(copy(ct_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -3055,8 +3054,8 @@ std::string NMD::BC2EQZC(uint64 instruction)
*/
std::string NMD::BC2NEZC(uint64 instruction)
{
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 ct_value = extract_ct_25_24_23_22_21(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string ct = CPR(copy(ct_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -3077,12 +3076,12 @@ std::string NMD::BC2NEZC(uint64 instruction)
*/
std::string NMD::BEQC_16_(uint64 instruction)
{
- uint64 u_value = extr_uil0il1bs4Fmsb4(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_3_2_1_0__s1(instruction);
std::string rs3 = GPR(encode_rs3_and_check_rs3_lt_rt3(rs3_value));
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = ADDRESS(encode_u_from_address(u_value), 2);
return img::format("BEQC %s, %s, %s", rs3, rt3, u);
@@ -3102,8 +3101,8 @@ std::string NMD::BEQC_16_(uint64 instruction)
std::string NMD::BEQC_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3126,8 +3125,8 @@ std::string NMD::BEQC_32_(uint64 instruction)
std::string NMD::BEQIC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3149,10 +3148,10 @@ std::string NMD::BEQIC(uint64 instruction)
*/
std::string NMD::BEQZC_16_(uint64 instruction)
{
- int64 s_value = extr_sil0il7bs1_il1il1bs6Tmsb7(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
+ int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 2);
return img::format("BEQZC %s, %s", rt3, s);
@@ -3172,8 +3171,8 @@ std::string NMD::BEQZC_16_(uint64 instruction)
std::string NMD::BGEC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3196,8 +3195,8 @@ std::string NMD::BGEC(uint64 instruction)
std::string NMD::BGEIC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3220,8 +3219,8 @@ std::string NMD::BGEIC(uint64 instruction)
std::string NMD::BGEIUC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3244,8 +3243,8 @@ std::string NMD::BGEIUC(uint64 instruction)
std::string NMD::BGEUC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3268,8 +3267,8 @@ std::string NMD::BGEUC(uint64 instruction)
std::string NMD::BLTC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3292,8 +3291,8 @@ std::string NMD::BLTC(uint64 instruction)
std::string NMD::BLTIC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3316,8 +3315,8 @@ std::string NMD::BLTIC(uint64 instruction)
std::string NMD::BLTIUC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3340,8 +3339,8 @@ std::string NMD::BLTIUC(uint64 instruction)
std::string NMD::BLTUC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3363,12 +3362,12 @@ std::string NMD::BLTUC(uint64 instruction)
*/
std::string NMD::BNEC_16_(uint64 instruction)
{
- uint64 u_value = extr_uil0il1bs4Fmsb4(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_3_2_1_0__s1(instruction);
std::string rs3 = GPR(encode_rs3_and_check_rs3_ge_rt3(rs3_value));
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = ADDRESS(encode_u_from_address(u_value), 2);
return img::format("BNEC %s, %s, %s", rs3, rt3, u);
@@ -3388,8 +3387,8 @@ std::string NMD::BNEC_16_(uint64 instruction)
std::string NMD::BNEC_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string rs = GPR(copy(rs_value));
std::string rt = GPR(copy(rt_value));
@@ -3412,8 +3411,8 @@ std::string NMD::BNEC_32_(uint64 instruction)
std::string NMD::BNEIC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il11bs1_il1il1bs10Tmsb11(instruction);
uint64 u_value = extract_u_17_16_15_14_13_12_11(instruction);
+ int64 s_value = extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -3435,10 +3434,10 @@ std::string NMD::BNEIC(uint64 instruction)
*/
std::string NMD::BNEZC_16_(uint64 instruction)
{
- int64 s_value = extr_sil0il7bs1_il1il1bs6Tmsb7(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
+ int64 s_value = extract_s__se7_0_6_5_4_3_2_1_s1(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 2);
return img::format("BNEZC %s, %s", rt3, s);
@@ -3457,7 +3456,7 @@ std::string NMD::BNEZC_16_(uint64 instruction)
*/
std::string NMD::BPOSGE32C(uint64 instruction)
{
- int64 s_value = extr_sil0il14bs1_il1il1bs13Tmsb14(instruction);
+ int64 s_value = extract_s__se14_0_13_to_1_s1(instruction);
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
@@ -3537,9 +3536,9 @@ std::string NMD::BRSC(uint64 instruction)
*/
std::string NMD::CACHE(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 op_value = extract_op_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string op = IMMEDIATE(copy(op_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -3561,9 +3560,9 @@ std::string NMD::CACHE(uint64 instruction)
*/
std::string NMD::CACHEE(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 op_value = extract_op_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string op = IMMEDIATE(copy(op_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -3585,8 +3584,8 @@ std::string NMD::CACHEE(uint64 instruction)
*/
std::string NMD::CEIL_L_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3607,8 +3606,8 @@ std::string NMD::CEIL_L_D(uint64 instruction)
*/
std::string NMD::CEIL_L_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3629,8 +3628,8 @@ std::string NMD::CEIL_L_S(uint64 instruction)
*/
std::string NMD::CEIL_W_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3651,8 +3650,8 @@ std::string NMD::CEIL_W_D(uint64 instruction)
*/
std::string NMD::CEIL_W_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3673,8 +3672,8 @@ std::string NMD::CEIL_W_S(uint64 instruction)
*/
std::string NMD::CFC1(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -3695,8 +3694,8 @@ std::string NMD::CFC1(uint64 instruction)
*/
std::string NMD::CFC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -3717,8 +3716,8 @@ std::string NMD::CFC2(uint64 instruction)
*/
std::string NMD::CLASS_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3739,8 +3738,8 @@ std::string NMD::CLASS_D(uint64 instruction)
*/
std::string NMD::CLASS_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -3805,9 +3804,9 @@ std::string NMD::CLZ(uint64 instruction)
*/
std::string NMD::CMP_AF_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3829,9 +3828,9 @@ std::string NMD::CMP_AF_D(uint64 instruction)
*/
std::string NMD::CMP_AF_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3853,9 +3852,9 @@ std::string NMD::CMP_AF_S(uint64 instruction)
*/
std::string NMD::CMP_EQ_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3899,9 +3898,9 @@ std::string NMD::CMP_EQ_PH(uint64 instruction)
*/
std::string NMD::CMP_EQ_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3923,9 +3922,9 @@ std::string NMD::CMP_EQ_S(uint64 instruction)
*/
std::string NMD::CMP_LE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3969,9 +3968,9 @@ std::string NMD::CMP_LE_PH(uint64 instruction)
*/
std::string NMD::CMP_LE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -3993,9 +3992,9 @@ std::string NMD::CMP_LE_S(uint64 instruction)
*/
std::string NMD::CMP_LT_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4039,9 +4038,9 @@ std::string NMD::CMP_LT_PH(uint64 instruction)
*/
std::string NMD::CMP_LT_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4063,9 +4062,9 @@ std::string NMD::CMP_LT_S(uint64 instruction)
*/
std::string NMD::CMP_NE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4087,9 +4086,9 @@ std::string NMD::CMP_NE_D(uint64 instruction)
*/
std::string NMD::CMP_NE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4111,9 +4110,9 @@ std::string NMD::CMP_NE_S(uint64 instruction)
*/
std::string NMD::CMP_OR_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4135,9 +4134,9 @@ std::string NMD::CMP_OR_D(uint64 instruction)
*/
std::string NMD::CMP_OR_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4159,9 +4158,9 @@ std::string NMD::CMP_OR_S(uint64 instruction)
*/
std::string NMD::CMP_SAF_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4183,9 +4182,9 @@ std::string NMD::CMP_SAF_D(uint64 instruction)
*/
std::string NMD::CMP_SAF_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4207,9 +4206,9 @@ std::string NMD::CMP_SAF_S(uint64 instruction)
*/
std::string NMD::CMP_SEQ_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4231,9 +4230,9 @@ std::string NMD::CMP_SEQ_D(uint64 instruction)
*/
std::string NMD::CMP_SEQ_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4255,9 +4254,9 @@ std::string NMD::CMP_SEQ_S(uint64 instruction)
*/
std::string NMD::CMP_SLE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4279,9 +4278,9 @@ std::string NMD::CMP_SLE_D(uint64 instruction)
*/
std::string NMD::CMP_SLE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4303,9 +4302,9 @@ std::string NMD::CMP_SLE_S(uint64 instruction)
*/
std::string NMD::CMP_SLT_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4327,9 +4326,9 @@ std::string NMD::CMP_SLT_D(uint64 instruction)
*/
std::string NMD::CMP_SLT_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4351,9 +4350,9 @@ std::string NMD::CMP_SLT_S(uint64 instruction)
*/
std::string NMD::CMP_SNE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4375,9 +4374,9 @@ std::string NMD::CMP_SNE_D(uint64 instruction)
*/
std::string NMD::CMP_SNE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4399,9 +4398,9 @@ std::string NMD::CMP_SNE_S(uint64 instruction)
*/
std::string NMD::CMP_SOR_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4423,9 +4422,9 @@ std::string NMD::CMP_SOR_D(uint64 instruction)
*/
std::string NMD::CMP_SOR_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4447,9 +4446,9 @@ std::string NMD::CMP_SOR_S(uint64 instruction)
*/
std::string NMD::CMP_SUEQ_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4471,9 +4470,9 @@ std::string NMD::CMP_SUEQ_D(uint64 instruction)
*/
std::string NMD::CMP_SUEQ_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4495,9 +4494,9 @@ std::string NMD::CMP_SUEQ_S(uint64 instruction)
*/
std::string NMD::CMP_SULE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4519,9 +4518,9 @@ std::string NMD::CMP_SULE_D(uint64 instruction)
*/
std::string NMD::CMP_SULE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4543,9 +4542,9 @@ std::string NMD::CMP_SULE_S(uint64 instruction)
*/
std::string NMD::CMP_SULT_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4567,9 +4566,9 @@ std::string NMD::CMP_SULT_D(uint64 instruction)
*/
std::string NMD::CMP_SULT_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4591,9 +4590,9 @@ std::string NMD::CMP_SULT_S(uint64 instruction)
*/
std::string NMD::CMP_SUN_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4615,9 +4614,9 @@ std::string NMD::CMP_SUN_D(uint64 instruction)
*/
std::string NMD::CMP_SUNE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4639,9 +4638,9 @@ std::string NMD::CMP_SUNE_D(uint64 instruction)
*/
std::string NMD::CMP_SUNE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4663,9 +4662,9 @@ std::string NMD::CMP_SUNE_S(uint64 instruction)
*/
std::string NMD::CMP_SUN_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4687,9 +4686,9 @@ std::string NMD::CMP_SUN_S(uint64 instruction)
*/
std::string NMD::CMP_UEQ_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4711,9 +4710,9 @@ std::string NMD::CMP_UEQ_D(uint64 instruction)
*/
std::string NMD::CMP_UEQ_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4735,9 +4734,9 @@ std::string NMD::CMP_UEQ_S(uint64 instruction)
*/
std::string NMD::CMP_ULE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4759,9 +4758,9 @@ std::string NMD::CMP_ULE_D(uint64 instruction)
*/
std::string NMD::CMP_ULE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4783,9 +4782,9 @@ std::string NMD::CMP_ULE_S(uint64 instruction)
*/
std::string NMD::CMP_ULT_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4807,9 +4806,9 @@ std::string NMD::CMP_ULT_D(uint64 instruction)
*/
std::string NMD::CMP_ULT_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4831,9 +4830,9 @@ std::string NMD::CMP_ULT_S(uint64 instruction)
*/
std::string NMD::CMP_UN_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4855,9 +4854,9 @@ std::string NMD::CMP_UN_D(uint64 instruction)
*/
std::string NMD::CMP_UNE_D(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4879,9 +4878,9 @@ std::string NMD::CMP_UNE_D(uint64 instruction)
*/
std::string NMD::CMP_UNE_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4903,9 +4902,9 @@ std::string NMD::CMP_UNE_S(uint64 instruction)
*/
std::string NMD::CMP_UN_S(uint64 instruction)
{
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -4928,8 +4927,8 @@ std::string NMD::CMP_UN_S(uint64 instruction)
std::string NMD::CMPGDU_EQ_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -4952,8 +4951,8 @@ std::string NMD::CMPGDU_EQ_QB(uint64 instruction)
std::string NMD::CMPGDU_LE_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -4976,8 +4975,8 @@ std::string NMD::CMPGDU_LE_QB(uint64 instruction)
std::string NMD::CMPGDU_LT_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5000,8 +4999,8 @@ std::string NMD::CMPGDU_LT_QB(uint64 instruction)
std::string NMD::CMPGU_EQ_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5024,8 +5023,8 @@ std::string NMD::CMPGU_EQ_QB(uint64 instruction)
std::string NMD::CMPGU_LE_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5048,8 +5047,8 @@ std::string NMD::CMPGU_LE_QB(uint64 instruction)
std::string NMD::CMPGU_LT_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5157,8 +5156,8 @@ std::string NMD::COP2_1(uint64 instruction)
*/
std::string NMD::CTC1(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -5179,8 +5178,8 @@ std::string NMD::CTC1(uint64 instruction)
*/
std::string NMD::CTC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -5201,8 +5200,8 @@ std::string NMD::CTC2(uint64 instruction)
*/
std::string NMD::CVT_D_L(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5223,8 +5222,8 @@ std::string NMD::CVT_D_L(uint64 instruction)
*/
std::string NMD::CVT_D_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5245,8 +5244,8 @@ std::string NMD::CVT_D_S(uint64 instruction)
*/
std::string NMD::CVT_D_W(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5267,8 +5266,8 @@ std::string NMD::CVT_D_W(uint64 instruction)
*/
std::string NMD::CVT_L_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5289,8 +5288,8 @@ std::string NMD::CVT_L_D(uint64 instruction)
*/
std::string NMD::CVT_L_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5311,8 +5310,8 @@ std::string NMD::CVT_L_S(uint64 instruction)
*/
std::string NMD::CVT_S_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5333,8 +5332,8 @@ std::string NMD::CVT_S_D(uint64 instruction)
*/
std::string NMD::CVT_S_L(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5355,8 +5354,8 @@ std::string NMD::CVT_S_L(uint64 instruction)
*/
std::string NMD::CVT_S_PL(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5377,8 +5376,8 @@ std::string NMD::CVT_S_PL(uint64 instruction)
*/
std::string NMD::CVT_S_PU(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5399,8 +5398,8 @@ std::string NMD::CVT_S_PU(uint64 instruction)
*/
std::string NMD::CVT_S_W(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5421,8 +5420,8 @@ std::string NMD::CVT_S_W(uint64 instruction)
*/
std::string NMD::CVT_W_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5443,8 +5442,8 @@ std::string NMD::CVT_W_D(uint64 instruction)
*/
std::string NMD::CVT_W_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -5466,7 +5465,7 @@ std::string NMD::CVT_W_S(uint64 instruction)
std::string NMD::DADDIU_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -5488,8 +5487,8 @@ std::string NMD::DADDIU_48_(uint64 instruction)
std::string NMD::DADDIU_NEG_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5512,8 +5511,8 @@ std::string NMD::DADDIU_NEG_(uint64 instruction)
std::string NMD::DADDIU_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5536,8 +5535,8 @@ std::string NMD::DADDIU_U12_(uint64 instruction)
std::string NMD::DADD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5560,8 +5559,8 @@ std::string NMD::DADD(uint64 instruction)
std::string NMD::DADDU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5628,8 +5627,8 @@ std::string NMD::DCLZ(uint64 instruction)
std::string NMD::DDIV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5652,8 +5651,8 @@ std::string NMD::DDIV(uint64 instruction)
std::string NMD::DDIVU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5694,9 +5693,9 @@ std::string NMD::DERET(uint64 instruction)
std::string NMD::DEXTM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5720,9 +5719,9 @@ std::string NMD::DEXTM(uint64 instruction)
std::string NMD::DEXT(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5746,9 +5745,9 @@ std::string NMD::DEXT(uint64 instruction)
std::string NMD::DEXTU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5772,9 +5771,9 @@ std::string NMD::DEXTU(uint64 instruction)
std::string NMD::DINSM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5800,9 +5799,9 @@ std::string NMD::DINSM(uint64 instruction)
std::string NMD::DINS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5828,9 +5827,9 @@ std::string NMD::DINS(uint64 instruction)
std::string NMD::DINSU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -5876,8 +5875,8 @@ std::string NMD::DI(uint64 instruction)
std::string NMD::DIV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5899,9 +5898,9 @@ std::string NMD::DIV(uint64 instruction)
*/
std::string NMD::DIV_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -5923,9 +5922,9 @@ std::string NMD::DIV_D(uint64 instruction)
*/
std::string NMD::DIV_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -5948,8 +5947,8 @@ std::string NMD::DIV_S(uint64 instruction)
std::string NMD::DIVU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5972,9 +5971,9 @@ std::string NMD::DIVU(uint64 instruction)
std::string NMD::DLSA(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
- uint64 u2_value = extract_u2_10_9(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
+ uint64 u2_value = extract_u2_10_9(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -5998,7 +5997,7 @@ std::string NMD::DLSA(uint64 instruction)
std::string NMD::DLUI_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- uint64 u_value = extr_uil0il32bs32Fmsb63(instruction);
+ uint64 u_value = extract_u_31_to_0__s32(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -6044,7 +6043,7 @@ std::string NMD::DMFC0(uint64 instruction)
std::string NMD::DMFC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -6065,8 +6064,8 @@ std::string NMD::DMFC1(uint64 instruction)
*/
std::string NMD::DMFC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -6112,8 +6111,8 @@ std::string NMD::DMFGC0(uint64 instruction)
std::string NMD::DMOD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6136,8 +6135,8 @@ std::string NMD::DMOD(uint64 instruction)
std::string NMD::DMODU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6184,7 +6183,7 @@ std::string NMD::DMTC0(uint64 instruction)
std::string NMD::DMTC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -6205,8 +6204,8 @@ std::string NMD::DMTC1(uint64 instruction)
*/
std::string NMD::DMTC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -6272,8 +6271,8 @@ std::string NMD::DMT(uint64 instruction)
std::string NMD::DMUH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6296,8 +6295,8 @@ std::string NMD::DMUH(uint64 instruction)
std::string NMD::DMUHU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6320,8 +6319,8 @@ std::string NMD::DMUHU(uint64 instruction)
std::string NMD::DMUL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6344,8 +6343,8 @@ std::string NMD::DMUL(uint64 instruction)
std::string NMD::DMULU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6368,8 +6367,8 @@ std::string NMD::DMULU(uint64 instruction)
std::string NMD::DPA_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6392,8 +6391,8 @@ std::string NMD::DPA_W_PH(uint64 instruction)
std::string NMD::DPAQ_SA_L_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6416,8 +6415,8 @@ std::string NMD::DPAQ_SA_L_W(uint64 instruction)
std::string NMD::DPAQ_S_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6440,8 +6439,8 @@ std::string NMD::DPAQ_S_W_PH(uint64 instruction)
std::string NMD::DPAQX_SA_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6464,8 +6463,8 @@ std::string NMD::DPAQX_SA_W_PH(uint64 instruction)
std::string NMD::DPAQX_S_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6488,8 +6487,8 @@ std::string NMD::DPAQX_S_W_PH(uint64 instruction)
std::string NMD::DPAU_H_QBL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6512,8 +6511,8 @@ std::string NMD::DPAU_H_QBL(uint64 instruction)
std::string NMD::DPAU_H_QBR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6536,8 +6535,8 @@ std::string NMD::DPAU_H_QBR(uint64 instruction)
std::string NMD::DPAX_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6560,8 +6559,8 @@ std::string NMD::DPAX_W_PH(uint64 instruction)
std::string NMD::DPS_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6584,8 +6583,8 @@ std::string NMD::DPS_W_PH(uint64 instruction)
std::string NMD::DPSQ_SA_L_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6608,8 +6607,8 @@ std::string NMD::DPSQ_SA_L_W(uint64 instruction)
std::string NMD::DPSQ_S_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6632,8 +6631,8 @@ std::string NMD::DPSQ_S_W_PH(uint64 instruction)
std::string NMD::DPSQX_SA_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6656,8 +6655,8 @@ std::string NMD::DPSQX_SA_W_PH(uint64 instruction)
std::string NMD::DPSQX_S_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6680,8 +6679,8 @@ std::string NMD::DPSQX_S_W_PH(uint64 instruction)
std::string NMD::DPSU_H_QBL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6704,8 +6703,8 @@ std::string NMD::DPSU_H_QBL(uint64 instruction)
std::string NMD::DPSU_H_QBR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6728,8 +6727,8 @@ std::string NMD::DPSU_H_QBR(uint64 instruction)
std::string NMD::DPSX_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -6752,8 +6751,8 @@ std::string NMD::DPSX_W_PH(uint64 instruction)
std::string NMD::DROTR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6776,8 +6775,8 @@ std::string NMD::DROTR(uint64 instruction)
std::string NMD::DROTR32(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6800,8 +6799,8 @@ std::string NMD::DROTR32(uint64 instruction)
std::string NMD::DROTRV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6824,9 +6823,9 @@ std::string NMD::DROTRV(uint64 instruction)
std::string NMD::DROTX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_5_4_3_2_1_0(instruction);
- uint64 shiftx_value = extract_shiftx_11_10_9_8_7_6(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shiftx_value = extract_shiftx_11_10_9_8_7_6(instruction);
+ uint64 shift_value = extract_shift_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6850,8 +6849,8 @@ std::string NMD::DROTX(uint64 instruction)
std::string NMD::DSLL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6874,8 +6873,8 @@ std::string NMD::DSLL(uint64 instruction)
std::string NMD::DSLL32(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6898,8 +6897,8 @@ std::string NMD::DSLL32(uint64 instruction)
std::string NMD::DSLLV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6922,8 +6921,8 @@ std::string NMD::DSLLV(uint64 instruction)
std::string NMD::DSRA(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6946,8 +6945,8 @@ std::string NMD::DSRA(uint64 instruction)
std::string NMD::DSRA32(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -6970,8 +6969,8 @@ std::string NMD::DSRA32(uint64 instruction)
std::string NMD::DSRAV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -6994,8 +6993,8 @@ std::string NMD::DSRAV(uint64 instruction)
std::string NMD::DSRL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -7018,8 +7017,8 @@ std::string NMD::DSRL(uint64 instruction)
std::string NMD::DSRL32(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -7042,8 +7041,8 @@ std::string NMD::DSRL32(uint64 instruction)
std::string NMD::DSRLV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7066,8 +7065,8 @@ std::string NMD::DSRLV(uint64 instruction)
std::string NMD::DSUB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7090,8 +7089,8 @@ std::string NMD::DSUB(uint64 instruction)
std::string NMD::DSUBU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7288,9 +7287,9 @@ std::string NMD::EVPE(uint64 instruction)
std::string NMD::EXT(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -7314,9 +7313,9 @@ std::string NMD::EXT(uint64 instruction)
std::string NMD::EXTD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
+ uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7340,9 +7339,9 @@ std::string NMD::EXTD(uint64 instruction)
std::string NMD::EXTD32(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
+ uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7366,8 +7365,8 @@ std::string NMD::EXTD32(uint64 instruction)
std::string NMD::EXTPDP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 size_value = extract_size_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7390,8 +7389,8 @@ std::string NMD::EXTPDP(uint64 instruction)
std::string NMD::EXTPDPV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7414,8 +7413,8 @@ std::string NMD::EXTPDPV(uint64 instruction)
std::string NMD::EXTP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 size_value = extract_size_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7438,8 +7437,8 @@ std::string NMD::EXTP(uint64 instruction)
std::string NMD::EXTPV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7558,8 +7557,8 @@ std::string NMD::EXTR_W(uint64 instruction)
std::string NMD::EXTRV_RS_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7582,8 +7581,8 @@ std::string NMD::EXTRV_RS_W(uint64 instruction)
std::string NMD::EXTRV_R_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7606,8 +7605,8 @@ std::string NMD::EXTRV_R_W(uint64 instruction)
std::string NMD::EXTRV_S_H(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7630,8 +7629,8 @@ std::string NMD::EXTRV_S_H(uint64 instruction)
std::string NMD::EXTRV_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string ac = AC(copy(ac_value));
@@ -7655,9 +7654,9 @@ std::string NMD::EXTRV_W(uint64 instruction)
std::string NMD::EXTW(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
+ uint64 shift_value = extract_shift_10_9_8_7_6(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7680,8 +7679,8 @@ std::string NMD::EXTW(uint64 instruction)
*/
std::string NMD::FLOOR_L_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -7702,8 +7701,8 @@ std::string NMD::FLOOR_L_D(uint64 instruction)
*/
std::string NMD::FLOOR_L_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -7724,8 +7723,8 @@ std::string NMD::FLOOR_L_S(uint64 instruction)
*/
std::string NMD::FLOOR_W_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -7746,8 +7745,8 @@ std::string NMD::FLOOR_W_D(uint64 instruction)
*/
std::string NMD::FLOOR_W_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -7769,8 +7768,8 @@ std::string NMD::FLOOR_W_S(uint64 instruction)
std::string NMD::FORK(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -7833,9 +7832,9 @@ std::string NMD::HYPCALL_16_(uint64 instruction)
std::string NMD::INS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
uint64 msbd_value = extract_msbt_10_9_8_7_6(instruction);
uint64 lsb_value = extract_lsb_4_3_2_1_0(instruction);
- uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -7984,13 +7983,13 @@ std::string NMD::JRC(uint64 instruction)
*/
std::string NMD::LB_16_(uint64 instruction)
{
- uint64 u_value = extract_u_1_0(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("LB %s, %s(%s)", rt3, u, rs3);
}
@@ -8031,8 +8030,8 @@ std::string NMD::LB_GP_(uint64 instruction)
std::string NMD::LB_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8055,8 +8054,8 @@ std::string NMD::LB_S9_(uint64 instruction)
std::string NMD::LB_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8079,8 +8078,8 @@ std::string NMD::LB_U12_(uint64 instruction)
std::string NMD::LBE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8102,13 +8101,13 @@ std::string NMD::LBE(uint64 instruction)
*/
std::string NMD::LBU_16_(uint64 instruction)
{
- uint64 u_value = extract_u_1_0(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("LBU %s, %s(%s)", rt3, u, rs3);
}
@@ -8149,8 +8148,8 @@ std::string NMD::LBU_GP_(uint64 instruction)
std::string NMD::LBU_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8173,8 +8172,8 @@ std::string NMD::LBU_S9_(uint64 instruction)
std::string NMD::LBU_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8197,8 +8196,8 @@ std::string NMD::LBU_U12_(uint64 instruction)
std::string NMD::LBUE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8221,8 +8220,8 @@ std::string NMD::LBUE(uint64 instruction)
std::string NMD::LBUX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8245,8 +8244,8 @@ std::string NMD::LBUX(uint64 instruction)
std::string NMD::LBX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8269,7 +8268,7 @@ std::string NMD::LBX(uint64 instruction)
std::string NMD::LD_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil3il3bs18Fmsb20(instruction);
+ uint64 u_value = extract_u_20_to_3__s3(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8291,8 +8290,8 @@ std::string NMD::LD_GP_(uint64 instruction)
std::string NMD::LD_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8315,8 +8314,8 @@ std::string NMD::LD_S9_(uint64 instruction)
std::string NMD::LD_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8338,8 +8337,8 @@ std::string NMD::LD_U12_(uint64 instruction)
*/
std::string NMD::LDC1_GP_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extr_uil2il2bs16Fmsb17(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 u_value = extract_u_17_to_2__s2(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8360,9 +8359,9 @@ std::string NMD::LDC1_GP_(uint64 instruction)
*/
std::string NMD::LDC1_S9_(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8384,9 +8383,9 @@ std::string NMD::LDC1_S9_(uint64 instruction)
*/
std::string NMD::LDC1_U12_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8409,8 +8408,8 @@ std::string NMD::LDC1_U12_(uint64 instruction)
std::string NMD::LDC1XS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -8433,8 +8432,8 @@ std::string NMD::LDC1XS(uint64 instruction)
std::string NMD::LDC1X(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -8456,9 +8455,9 @@ std::string NMD::LDC1X(uint64 instruction)
*/
std::string NMD::LDC2(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 ct_value = extract_ct_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ct = CPR(copy(ct_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8481,9 +8480,9 @@ std::string NMD::LDC2(uint64 instruction)
std::string NMD::LDM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8507,7 +8506,7 @@ std::string NMD::LDM(uint64 instruction)
std::string NMD::LDPC_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 6);
@@ -8529,8 +8528,8 @@ std::string NMD::LDPC_48_(uint64 instruction)
std::string NMD::LDX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8553,8 +8552,8 @@ std::string NMD::LDX(uint64 instruction)
std::string NMD::LDXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8576,13 +8575,13 @@ std::string NMD::LDXS(uint64 instruction)
*/
std::string NMD::LH_16_(uint64 instruction)
{
- uint64 u_value = extr_uil1il1bs2Fmsb2(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_2_1__s1(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("LH %s, %s(%s)", rt3, u, rs3);
}
@@ -8601,7 +8600,7 @@ std::string NMD::LH_16_(uint64 instruction)
std::string NMD::LH_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil1il1bs17Fmsb17(instruction);
+ uint64 u_value = extract_u_17_to_1__s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8623,8 +8622,8 @@ std::string NMD::LH_GP_(uint64 instruction)
std::string NMD::LH_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8647,8 +8646,8 @@ std::string NMD::LH_S9_(uint64 instruction)
std::string NMD::LH_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8671,8 +8670,8 @@ std::string NMD::LH_U12_(uint64 instruction)
std::string NMD::LHE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8694,13 +8693,13 @@ std::string NMD::LHE(uint64 instruction)
*/
std::string NMD::LHU_16_(uint64 instruction)
{
- uint64 u_value = extr_uil1il1bs2Fmsb2(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_2_1__s1(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("LHU %s, %s(%s)", rt3, u, rs3);
}
@@ -8719,7 +8718,7 @@ std::string NMD::LHU_16_(uint64 instruction)
std::string NMD::LHU_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil1il1bs17Fmsb17(instruction);
+ uint64 u_value = extract_u_17_to_1__s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8741,8 +8740,8 @@ std::string NMD::LHU_GP_(uint64 instruction)
std::string NMD::LHU_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8765,8 +8764,8 @@ std::string NMD::LHU_S9_(uint64 instruction)
std::string NMD::LHU_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -8789,8 +8788,8 @@ std::string NMD::LHU_U12_(uint64 instruction)
std::string NMD::LHUE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8813,8 +8812,8 @@ std::string NMD::LHUE(uint64 instruction)
std::string NMD::LHUX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8837,8 +8836,8 @@ std::string NMD::LHUX(uint64 instruction)
std::string NMD::LHUXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8861,8 +8860,8 @@ std::string NMD::LHUXS(uint64 instruction)
std::string NMD::LHXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8885,8 +8884,8 @@ std::string NMD::LHXS(uint64 instruction)
std::string NMD::LHX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -8908,10 +8907,10 @@ std::string NMD::LHX(uint64 instruction)
*/
std::string NMD::LI_16_(uint64 instruction)
{
- uint64 eu_value = extract_eu_6_5_4_3_2_1_0(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
+ uint64 eu_value = extract_eu_6_5_4_3_2_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string eu = IMMEDIATE(encode_eu_from_s_li16(eu_value));
return img::format("LI %s, %s", rt3, eu);
@@ -8931,7 +8930,7 @@ std::string NMD::LI_16_(uint64 instruction)
std::string NMD::LI_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8953,8 +8952,8 @@ std::string NMD::LI_48_(uint64 instruction)
std::string NMD::LL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil2il2bs6_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -8977,8 +8976,8 @@ std::string NMD::LL(uint64 instruction)
std::string NMD::LLD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil3il3bs5_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9001,8 +9000,8 @@ std::string NMD::LLD(uint64 instruction)
std::string NMD::LLDP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -9025,8 +9024,8 @@ std::string NMD::LLDP(uint64 instruction)
std::string NMD::LLE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil2il2bs6_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9049,8 +9048,8 @@ std::string NMD::LLE(uint64 instruction)
std::string NMD::LLWP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -9073,8 +9072,8 @@ std::string NMD::LLWP(uint64 instruction)
std::string NMD::LLWPE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -9097,9 +9096,9 @@ std::string NMD::LLWPE(uint64 instruction)
std::string NMD::LSA(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
- uint64 u2_value = extract_u2_10_9(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
+ uint64 u2_value = extract_u2_10_9(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -9123,7 +9122,7 @@ std::string NMD::LSA(uint64 instruction)
std::string NMD::LUI(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il31bs1_il2il21bs10_il12il12bs9Tmsb31(instruction);
+ int64 s_value = extract_s__se31_0_11_to_2_20_to_12_s12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9144,13 +9143,13 @@ std::string NMD::LUI(uint64 instruction)
*/
std::string NMD::LW_16_(uint64 instruction)
{
- uint64 u_value = extr_uil0il2bs4Fmsb5(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_3_2_1_0__s2(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("LW %s, %s(%s)", rt3, u, rs3);
}
@@ -9168,13 +9167,13 @@ std::string NMD::LW_16_(uint64 instruction)
*/
std::string NMD::LW_4X4_(uint64 instruction)
{
- uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
uint64 rt4_value = extract_rt4_9_7_6_5(instruction);
- uint64 u_value = extr_uil3il3bs1_il8il2bs1Fmsb3(instruction);
+ uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
+ uint64 u_value = extract_u_3_8__s2(instruction);
- std::string rt4 = GPR(encode_gpr4(rt4_value));
+ std::string rt4 = GPR(decode_gpr_gpr4(rt4_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs4 = GPR(encode_gpr4(rs4_value));
+ std::string rs4 = GPR(decode_gpr_gpr4(rs4_value));
return img::format("LW %s, %s(%s)", rt4, u, rs4);
}
@@ -9193,7 +9192,7 @@ std::string NMD::LW_4X4_(uint64 instruction)
std::string NMD::LW_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil2il2bs19Fmsb20(instruction);
+ uint64 u_value = extract_u_20_to_2__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9214,10 +9213,10 @@ std::string NMD::LW_GP_(uint64 instruction)
*/
std::string NMD::LW_GP16_(uint64 instruction)
{
- uint64 u_value = extr_uil0il2bs7Fmsb8(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
+ uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
std::string u = IMMEDIATE(copy(u_value));
return img::format("LW %s, %s($%d)", rt3, u, 28);
@@ -9237,8 +9236,8 @@ std::string NMD::LW_GP16_(uint64 instruction)
std::string NMD::LW_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9261,7 +9260,7 @@ std::string NMD::LW_S9_(uint64 instruction)
std::string NMD::LW_SP_(uint64 instruction)
{
uint64 rt_value = extract_rt_9_8_7_6_5(instruction);
- uint64 u_value = extr_uil0il2bs5Fmsb6(instruction);
+ uint64 u_value = extract_u_4_3_2_1_0__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9283,8 +9282,8 @@ std::string NMD::LW_SP_(uint64 instruction)
std::string NMD::LW_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9306,8 +9305,8 @@ std::string NMD::LW_U12_(uint64 instruction)
*/
std::string NMD::LWC1_GP_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extr_uil2il2bs16Fmsb17(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 u_value = extract_u_17_to_2__s2(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9328,9 +9327,9 @@ std::string NMD::LWC1_GP_(uint64 instruction)
*/
std::string NMD::LWC1_S9_(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9352,9 +9351,9 @@ std::string NMD::LWC1_S9_(uint64 instruction)
*/
std::string NMD::LWC1_U12_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9377,8 +9376,8 @@ std::string NMD::LWC1_U12_(uint64 instruction)
std::string NMD::LWC1X(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -9401,8 +9400,8 @@ std::string NMD::LWC1X(uint64 instruction)
std::string NMD::LWC1XS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -9424,9 +9423,9 @@ std::string NMD::LWC1XS(uint64 instruction)
*/
std::string NMD::LWC2(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 ct_value = extract_ct_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ct = CPR(copy(ct_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9449,8 +9448,8 @@ std::string NMD::LWC2(uint64 instruction)
std::string NMD::LWE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9473,9 +9472,9 @@ std::string NMD::LWE(uint64 instruction)
std::string NMD::LWM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9499,7 +9498,7 @@ std::string NMD::LWM(uint64 instruction)
std::string NMD::LWPC_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 6);
@@ -9521,7 +9520,7 @@ std::string NMD::LWPC_48_(uint64 instruction)
std::string NMD::LWU_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil2il2bs16Fmsb17(instruction);
+ uint64 u_value = extract_u_17_to_2__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9543,8 +9542,8 @@ std::string NMD::LWU_GP_(uint64 instruction)
std::string NMD::LWU_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -9567,8 +9566,8 @@ std::string NMD::LWU_S9_(uint64 instruction)
std::string NMD::LWU_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -9591,8 +9590,8 @@ std::string NMD::LWU_U12_(uint64 instruction)
std::string NMD::LWUX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -9615,8 +9614,8 @@ std::string NMD::LWUX(uint64 instruction)
std::string NMD::LWUXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -9639,8 +9638,8 @@ std::string NMD::LWUXS(uint64 instruction)
std::string NMD::LWX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -9662,13 +9661,13 @@ std::string NMD::LWX(uint64 instruction)
*/
std::string NMD::LWXS_16_(uint64 instruction)
{
- uint64 rd3_value = extract_rd3_3_2_1(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 rd3_value = extract_rd3_3_2_1(instruction);
- std::string rd3 = GPR(encode_gpr3(rd3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
- std::string rt3 = IMMEDIATE(encode_gpr3(rt3_value));
+ std::string rd3 = GPR(decode_gpr_gpr3(rd3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
+ std::string rt3 = IMMEDIATE(decode_gpr_gpr3(rt3_value));
return img::format("LWXS %s, %s(%s)", rd3, rs3, rt3);
}
@@ -9687,8 +9686,8 @@ std::string NMD::LWXS_16_(uint64 instruction)
std::string NMD::LWXS_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -9711,8 +9710,8 @@ std::string NMD::LWXS_32_(uint64 instruction)
std::string NMD::MADD_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9734,9 +9733,9 @@ std::string NMD::MADD_DSP_(uint64 instruction)
*/
std::string NMD::MADDF_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -9758,9 +9757,9 @@ std::string NMD::MADDF_D(uint64 instruction)
*/
std::string NMD::MADDF_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -9783,8 +9782,8 @@ std::string NMD::MADDF_S(uint64 instruction)
std::string NMD::MADDU_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9807,8 +9806,8 @@ std::string NMD::MADDU_DSP_(uint64 instruction)
std::string NMD::MAQ_S_W_PHL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9831,8 +9830,8 @@ std::string NMD::MAQ_S_W_PHL(uint64 instruction)
std::string NMD::MAQ_S_W_PHR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9855,8 +9854,8 @@ std::string NMD::MAQ_S_W_PHR(uint64 instruction)
std::string NMD::MAQ_SA_W_PHL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9879,8 +9878,8 @@ std::string NMD::MAQ_SA_W_PHL(uint64 instruction)
std::string NMD::MAQ_SA_W_PHR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -9902,9 +9901,9 @@ std::string NMD::MAQ_SA_W_PHR(uint64 instruction)
*/
std::string NMD::MAX_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -9926,9 +9925,9 @@ std::string NMD::MAX_D(uint64 instruction)
*/
std::string NMD::MAX_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -9950,9 +9949,9 @@ std::string NMD::MAX_S(uint64 instruction)
*/
std::string NMD::MAXA_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -9974,9 +9973,9 @@ std::string NMD::MAXA_D(uint64 instruction)
*/
std::string NMD::MAXA_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10023,7 +10022,7 @@ std::string NMD::MFC0(uint64 instruction)
std::string NMD::MFC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -10044,8 +10043,8 @@ std::string NMD::MFC1(uint64 instruction)
*/
std::string NMD::MFC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -10115,7 +10114,7 @@ std::string NMD::MFHC0(uint64 instruction)
std::string NMD::MFHC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -10136,8 +10135,8 @@ std::string NMD::MFHC1(uint64 instruction)
*/
std::string NMD::MFHC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -10278,9 +10277,9 @@ std::string NMD::MFTR(uint64 instruction)
*/
std::string NMD::MIN_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10302,9 +10301,9 @@ std::string NMD::MIN_D(uint64 instruction)
*/
std::string NMD::MIN_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10326,9 +10325,9 @@ std::string NMD::MIN_S(uint64 instruction)
*/
std::string NMD::MINA_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10350,9 +10349,9 @@ std::string NMD::MINA_D(uint64 instruction)
*/
std::string NMD::MINA_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10375,8 +10374,8 @@ std::string NMD::MINA_S(uint64 instruction)
std::string NMD::MOD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -10399,8 +10398,8 @@ std::string NMD::MOD(uint64 instruction)
std::string NMD::MODSUB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -10423,8 +10422,8 @@ std::string NMD::MODSUB(uint64 instruction)
std::string NMD::MODU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -10446,8 +10445,8 @@ std::string NMD::MODU(uint64 instruction)
*/
std::string NMD::MOV_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -10468,8 +10467,8 @@ std::string NMD::MOV_D(uint64 instruction)
*/
std::string NMD::MOV_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -10490,12 +10489,12 @@ std::string NMD::MOV_S(uint64 instruction)
*/
std::string NMD::MOVE_BALC(uint64 instruction)
{
- uint64 rd1_value = extract_rdl_25_24(instruction);
- int64 s_value = extr_sil0il21bs1_il1il1bs20Tmsb21(instruction);
uint64 rtz4_value = extract_rtz4_27_26_25_23_22_21(instruction);
+ uint64 rd1_value = extract_rdl_25_24(instruction);
+ int64 s_value = extract_s__se21_0_20_to_1_s1(instruction);
- std::string rd1 = GPR(encode_rd1_from_rd(rd1_value));
- std::string rtz4 = GPR(encode_gpr4_zero(rtz4_value));
+ std::string rd1 = GPR(decode_gpr_gpr1(rd1_value));
+ std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 4);
return img::format("MOVE.BALC %s, %s, %s", rd1, rtz4, s);
@@ -10514,15 +10513,15 @@ std::string NMD::MOVE_BALC(uint64 instruction)
*/
std::string NMD::MOVEP(uint64 instruction)
{
- uint64 rsz4_value = extract_rsz4_4_2_1_0(instruction);
uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction);
uint64 rd2_value = extract_rd2_3_8(instruction);
+ uint64 rsz4_value = extract_rsz4_4_2_1_0(instruction);
- std::string rd2 = GPR(encode_rd2_reg1(rd2_value));
- std::string re2 = GPR(encode_rd2_reg2(rd2_value));
+ std::string rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value));
+ std::string re2 = GPR(decode_gpr_gpr2_reg2(rd2_value));
/* !!!!!!!!!! - no conversion function */
- std::string rsz4 = GPR(encode_gpr4_zero(rsz4_value));
- std::string rtz4 = GPR(encode_gpr4_zero(rtz4_value));
+ std::string rsz4 = GPR(decode_gpr_gpr4_zero(rsz4_value));
+ std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value));
return img::format("MOVEP %s, %s, %s, %s", rd2, re2, rsz4, rtz4);
/* hand edited */
@@ -10541,14 +10540,14 @@ std::string NMD::MOVEP(uint64 instruction)
*/
std::string NMD::MOVEP_REV_(uint64 instruction)
{
- uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
uint64 rt4_value = extract_rt4_9_7_6_5(instruction);
uint64 rd2_value = extract_rd2_3_8(instruction);
+ uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
- std::string rs4 = GPR(encode_gpr4(rs4_value));
- std::string rt4 = GPR(encode_gpr4(rt4_value));
- std::string rd2 = GPR(encode_rd2_reg1(rd2_value));
- std::string rs2 = GPR(encode_rd2_reg2(rd2_value));
+ std::string rs4 = GPR(decode_gpr_gpr4(rs4_value));
+ std::string rt4 = GPR(decode_gpr_gpr4(rt4_value));
+ std::string rd2 = GPR(decode_gpr_gpr2_reg1(rd2_value));
+ std::string rs2 = GPR(decode_gpr_gpr2_reg2(rd2_value));
/* !!!!!!!!!! - no conversion function */
return img::format("MOVEP %s, %s, %s, %s", rs4, rt4, rd2, rs2);
@@ -10591,8 +10590,8 @@ std::string NMD::MOVE(uint64 instruction)
std::string NMD::MOVN(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -10615,8 +10614,8 @@ std::string NMD::MOVN(uint64 instruction)
std::string NMD::MOVZ(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -10639,8 +10638,8 @@ std::string NMD::MOVZ(uint64 instruction)
std::string NMD::MSUB_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -10662,9 +10661,9 @@ std::string NMD::MSUB_DSP_(uint64 instruction)
*/
std::string NMD::MSUBF_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10686,9 +10685,9 @@ std::string NMD::MSUBF_D(uint64 instruction)
*/
std::string NMD::MSUBF_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -10711,8 +10710,8 @@ std::string NMD::MSUBF_S(uint64 instruction)
std::string NMD::MSUBU_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -10759,7 +10758,7 @@ std::string NMD::MTC0(uint64 instruction)
std::string NMD::MTC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -10780,8 +10779,8 @@ std::string NMD::MTC1(uint64 instruction)
*/
std::string NMD::MTC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -10851,7 +10850,7 @@ std::string NMD::MTHC0(uint64 instruction)
std::string NMD::MTHC1(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string fs = FPR(copy(fs_value));
@@ -10872,8 +10871,8 @@ std::string NMD::MTHC1(uint64 instruction)
*/
std::string NMD::MTHC2(uint64 instruction)
{
- uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
+ uint64 cs_value = extract_cs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string cs = CPR(copy(cs_value));
@@ -10918,8 +10917,8 @@ std::string NMD::MTHGC0(uint64 instruction)
*/
std::string NMD::MTHI_DSP_(uint64 instruction)
{
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rs = GPR(copy(rs_value));
std::string ac = AC(copy(ac_value));
@@ -10940,8 +10939,8 @@ std::string NMD::MTHI_DSP_(uint64 instruction)
*/
std::string NMD::MTHLIP(uint64 instruction)
{
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rs = GPR(copy(rs_value));
std::string ac = AC(copy(ac_value));
@@ -10988,8 +10987,8 @@ std::string NMD::MTHTR(uint64 instruction)
*/
std::string NMD::MTLO_DSP_(uint64 instruction)
{
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string rs = GPR(copy(rs_value));
std::string ac = AC(copy(ac_value));
@@ -11037,8 +11036,8 @@ std::string NMD::MTTR(uint64 instruction)
std::string NMD::MUH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11061,8 +11060,8 @@ std::string NMD::MUH(uint64 instruction)
std::string NMD::MUHU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11085,8 +11084,8 @@ std::string NMD::MUHU(uint64 instruction)
std::string NMD::MUL_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11108,11 +11107,11 @@ std::string NMD::MUL_32_(uint64 instruction)
*/
std::string NMD::MUL_4X4_(uint64 instruction)
{
- uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
uint64 rt4_value = extract_rt4_9_7_6_5(instruction);
+ uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
- std::string rs4 = GPR(encode_gpr4(rs4_value));
- std::string rt4 = GPR(encode_gpr4(rt4_value));
+ std::string rs4 = GPR(decode_gpr_gpr4(rs4_value));
+ std::string rt4 = GPR(decode_gpr_gpr4(rt4_value));
return img::format("MUL %s, %s", rs4, rt4);
}
@@ -11130,9 +11129,9 @@ std::string NMD::MUL_4X4_(uint64 instruction)
*/
std::string NMD::MUL_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -11155,8 +11154,8 @@ std::string NMD::MUL_D(uint64 instruction)
std::string NMD::MUL_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11179,8 +11178,8 @@ std::string NMD::MUL_PH(uint64 instruction)
std::string NMD::MUL_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11202,9 +11201,9 @@ std::string NMD::MUL_S_PH(uint64 instruction)
*/
std::string NMD::MUL_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -11227,8 +11226,8 @@ std::string NMD::MUL_S(uint64 instruction)
std::string NMD::MULEQ_S_W_PHL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11251,8 +11250,8 @@ std::string NMD::MULEQ_S_W_PHL(uint64 instruction)
std::string NMD::MULEQ_S_W_PHR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11275,8 +11274,8 @@ std::string NMD::MULEQ_S_W_PHR(uint64 instruction)
std::string NMD::MULEU_S_PH_QBL(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11299,8 +11298,8 @@ std::string NMD::MULEU_S_PH_QBL(uint64 instruction)
std::string NMD::MULEU_S_PH_QBR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11323,8 +11322,8 @@ std::string NMD::MULEU_S_PH_QBR(uint64 instruction)
std::string NMD::MULQ_RS_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11347,8 +11346,8 @@ std::string NMD::MULQ_RS_PH(uint64 instruction)
std::string NMD::MULQ_RS_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11371,8 +11370,8 @@ std::string NMD::MULQ_RS_W(uint64 instruction)
std::string NMD::MULQ_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11395,8 +11394,8 @@ std::string NMD::MULQ_S_PH(uint64 instruction)
std::string NMD::MULQ_S_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11419,8 +11418,8 @@ std::string NMD::MULQ_S_W(uint64 instruction)
std::string NMD::MULSA_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -11443,8 +11442,8 @@ std::string NMD::MULSA_W_PH(uint64 instruction)
std::string NMD::MULSAQ_S_W_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -11467,8 +11466,8 @@ std::string NMD::MULSAQ_S_W_PH(uint64 instruction)
std::string NMD::MULT_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -11491,8 +11490,8 @@ std::string NMD::MULT_DSP_(uint64 instruction)
std::string NMD::MULTU_DSP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ac_value = extract_ac_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ac_value = extract_ac_13_12(instruction);
std::string ac = AC(copy(ac_value));
std::string rs = GPR(copy(rs_value));
@@ -11515,8 +11514,8 @@ std::string NMD::MULTU_DSP_(uint64 instruction)
std::string NMD::MULU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11538,8 +11537,8 @@ std::string NMD::MULU(uint64 instruction)
*/
std::string NMD::NEG_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -11560,8 +11559,8 @@ std::string NMD::NEG_D(uint64 instruction)
*/
std::string NMD::NEG_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -11619,8 +11618,8 @@ std::string NMD::NOP_32_(uint64 instruction)
std::string NMD::NOR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11645,8 +11644,8 @@ std::string NMD::NOT_16_(uint64 instruction)
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("NOT %s, %s", rt3, rs3);
}
@@ -11667,8 +11666,8 @@ std::string NMD::OR_16_(uint64 instruction)
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
- std::string rs3 = GPR(encode_gpr3(rs3_value));
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
return img::format("OR %s, %s", rs3, rt3);
}
@@ -11687,8 +11686,8 @@ std::string NMD::OR_16_(uint64 instruction)
std::string NMD::OR_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11711,8 +11710,8 @@ std::string NMD::OR_32_(uint64 instruction)
std::string NMD::ORI(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -11735,8 +11734,8 @@ std::string NMD::ORI(uint64 instruction)
std::string NMD::PACKRL_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11777,8 +11776,8 @@ std::string NMD::PAUSE(uint64 instruction)
std::string NMD::PICK_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -11801,8 +11800,8 @@ std::string NMD::PICK_PH(uint64 instruction)
std::string NMD::PICK_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12045,8 +12044,8 @@ std::string NMD::PRECEU_PH_QBR(uint64 instruction)
std::string NMD::PRECR_QB_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12069,8 +12068,8 @@ std::string NMD::PRECR_QB_PH(uint64 instruction)
std::string NMD::PRECR_SRA_PH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -12093,8 +12092,8 @@ std::string NMD::PRECR_SRA_PH_W(uint64 instruction)
std::string NMD::PRECR_SRA_R_PH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -12117,8 +12116,8 @@ std::string NMD::PRECR_SRA_R_PH_W(uint64 instruction)
std::string NMD::PRECRQ_PH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12141,8 +12140,8 @@ std::string NMD::PRECRQ_PH_W(uint64 instruction)
std::string NMD::PRECRQ_QB_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12165,8 +12164,8 @@ std::string NMD::PRECRQ_QB_PH(uint64 instruction)
std::string NMD::PRECRQ_RS_PH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12189,8 +12188,8 @@ std::string NMD::PRECRQ_RS_PH_W(uint64 instruction)
std::string NMD::PRECRQU_S_QB_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12212,9 +12211,9 @@ std::string NMD::PRECRQU_S_QB_PH(uint64 instruction)
*/
std::string NMD::PREF_S9_(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 hint_value = extract_hint_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string hint = IMMEDIATE(copy(hint_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -12237,8 +12236,8 @@ std::string NMD::PREF_S9_(uint64 instruction)
std::string NMD::PREF_U12_(uint64 instruction)
{
uint64 hint_value = extract_hint_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string hint = IMMEDIATE(copy(hint_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -12260,9 +12259,9 @@ std::string NMD::PREF_U12_(uint64 instruction)
*/
std::string NMD::PREFE(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 hint_value = extract_hint_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string hint = IMMEDIATE(copy(hint_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -12285,8 +12284,8 @@ std::string NMD::PREFE(uint64 instruction)
std::string NMD::PREPEND(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -12398,8 +12397,8 @@ std::string NMD::RDPGPR(uint64 instruction)
*/
std::string NMD::RECIP_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12420,8 +12419,8 @@ std::string NMD::RECIP_D(uint64 instruction)
*/
std::string NMD::RECIP_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12443,7 +12442,7 @@ std::string NMD::RECIP_S(uint64 instruction)
std::string NMD::REPL_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil11il0bs10Tmsb9(instruction);
+ int64 s_value = extract_s__se9_20_19_18_17_16_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -12530,9 +12529,9 @@ std::string NMD::REPLV_QB(uint64 instruction)
*/
std::string NMD::RESTORE_32_(uint64 instruction)
{
- uint64 count_value = extract_count_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil3il3bs9Fmsb11(instruction);
+ uint64 count_value = extract_count_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction);
uint64 gp_value = extract_gp_2(instruction);
std::string u = IMMEDIATE(copy(u_value));
@@ -12553,9 +12552,9 @@ std::string NMD::RESTORE_32_(uint64 instruction)
*/
std::string NMD::RESTORE_JRC_16_(uint64 instruction)
{
- uint64 count_value = extract_count_3_2_1_0(instruction);
uint64 rt1_value = extract_rtl_11(instruction);
- uint64 u_value = extr_uil4il4bs4Fmsb7(instruction);
+ uint64 u_value = extract_u_7_6_5_4__s4(instruction);
+ uint64 count_value = extract_count_3_2_1_0(instruction);
std::string u = IMMEDIATE(copy(u_value));
return img::format("RESTORE.JRC %s%s", u,
@@ -12575,9 +12574,9 @@ std::string NMD::RESTORE_JRC_16_(uint64 instruction)
*/
std::string NMD::RESTORE_JRC_32_(uint64 instruction)
{
- uint64 count_value = extract_count_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil3il3bs9Fmsb11(instruction);
+ uint64 count_value = extract_count_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction);
uint64 gp_value = extract_gp_2(instruction);
std::string u = IMMEDIATE(copy(u_value));
@@ -12599,7 +12598,7 @@ std::string NMD::RESTORE_JRC_32_(uint64 instruction)
std::string NMD::RESTOREF(uint64 instruction)
{
uint64 count_value = extract_count_19_18_17_16(instruction);
- uint64 u_value = extr_uil3il3bs9Fmsb11(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction);
std::string u = IMMEDIATE(copy(u_value));
std::string count = IMMEDIATE(copy(count_value));
@@ -12620,8 +12619,8 @@ std::string NMD::RESTOREF(uint64 instruction)
*/
std::string NMD::RINT_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12642,8 +12641,8 @@ std::string NMD::RINT_D(uint64 instruction)
*/
std::string NMD::RINT_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12665,8 +12664,8 @@ std::string NMD::RINT_S(uint64 instruction)
std::string NMD::ROTR(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -12689,8 +12688,8 @@ std::string NMD::ROTR(uint64 instruction)
std::string NMD::ROTRV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -12713,10 +12712,10 @@ std::string NMD::ROTRV(uint64 instruction)
std::string NMD::ROTX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
- uint64 shiftx_value = extr_shiftxil7il1bs4Fmsb4(instruction);
- uint64 stripe_value = extract_stripe_6(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shiftx_value = extract_shiftx_10_9_8_7__s1(instruction);
+ uint64 stripe_value = extract_stripe_6(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -12741,8 +12740,8 @@ std::string NMD::ROTX(uint64 instruction)
*/
std::string NMD::ROUND_L_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12763,8 +12762,8 @@ std::string NMD::ROUND_L_D(uint64 instruction)
*/
std::string NMD::ROUND_L_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12785,8 +12784,8 @@ std::string NMD::ROUND_L_S(uint64 instruction)
*/
std::string NMD::ROUND_W_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12807,8 +12806,8 @@ std::string NMD::ROUND_W_D(uint64 instruction)
*/
std::string NMD::ROUND_W_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12829,8 +12828,8 @@ std::string NMD::ROUND_W_S(uint64 instruction)
*/
std::string NMD::RSQRT_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12851,8 +12850,8 @@ std::string NMD::RSQRT_D(uint64 instruction)
*/
std::string NMD::RSQRT_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -12873,9 +12872,9 @@ std::string NMD::RSQRT_S(uint64 instruction)
*/
std::string NMD::SAVE_16_(uint64 instruction)
{
- uint64 count_value = extract_count_3_2_1_0(instruction);
uint64 rt1_value = extract_rtl_11(instruction);
- uint64 u_value = extr_uil4il4bs4Fmsb7(instruction);
+ uint64 u_value = extract_u_7_6_5_4__s4(instruction);
+ uint64 count_value = extract_count_3_2_1_0(instruction);
std::string u = IMMEDIATE(copy(u_value));
return img::format("SAVE %s%s", u,
@@ -12897,7 +12896,7 @@ std::string NMD::SAVE_32_(uint64 instruction)
{
uint64 count_value = extract_count_19_18_17_16(instruction);
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil3il3bs9Fmsb11(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction);
uint64 gp_value = extract_gp_2(instruction);
std::string u = IMMEDIATE(copy(u_value));
@@ -12919,7 +12918,7 @@ std::string NMD::SAVE_32_(uint64 instruction)
std::string NMD::SAVEF(uint64 instruction)
{
uint64 count_value = extract_count_19_18_17_16(instruction);
- uint64 u_value = extr_uil3il3bs9Fmsb11(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3__s3(instruction);
std::string u = IMMEDIATE(copy(u_value));
std::string count = IMMEDIATE(copy(count_value));
@@ -12941,12 +12940,12 @@ std::string NMD::SAVEF(uint64 instruction)
std::string NMD::SB_16_(uint64 instruction)
{
uint64 rtz3_value = extract_rtz3_9_8_7(instruction);
- uint64 u_value = extract_u_1_0(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_1_0(instruction);
- std::string rtz3 = GPR(encode_gpr3_store(rtz3_value));
+ std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("SB %s, %s(%s)", rtz3, u, rs3);
}
@@ -12987,8 +12986,8 @@ std::string NMD::SB_GP_(uint64 instruction)
std::string NMD::SB_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13011,8 +13010,8 @@ std::string NMD::SB_S9_(uint64 instruction)
std::string NMD::SB_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13035,8 +13034,8 @@ std::string NMD::SB_U12_(uint64 instruction)
std::string NMD::SBE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13059,8 +13058,8 @@ std::string NMD::SBE(uint64 instruction)
std::string NMD::SBX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -13083,8 +13082,8 @@ std::string NMD::SBX(uint64 instruction)
std::string NMD::SC(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil2il2bs6_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13107,8 +13106,8 @@ std::string NMD::SC(uint64 instruction)
std::string NMD::SCD(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil3il3bs5_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_s3(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13131,8 +13130,8 @@ std::string NMD::SCD(uint64 instruction)
std::string NMD::SCDP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -13155,8 +13154,8 @@ std::string NMD::SCDP(uint64 instruction)
std::string NMD::SCE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil2il2bs6_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13179,8 +13178,8 @@ std::string NMD::SCE(uint64 instruction)
std::string NMD::SCWP(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -13203,8 +13202,8 @@ std::string NMD::SCWP(uint64 instruction)
std::string NMD::SCWPE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ru_value = extract_ru_7_6_5_4_3(instruction);
std::string rt = GPR(copy(rt_value));
std::string ru = GPR(copy(ru_value));
@@ -13227,7 +13226,7 @@ std::string NMD::SCWPE(uint64 instruction)
std::string NMD::SD_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil3il3bs18Fmsb20(instruction);
+ uint64 u_value = extract_u_20_to_3__s3(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13249,8 +13248,8 @@ std::string NMD::SD_GP_(uint64 instruction)
std::string NMD::SD_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13273,8 +13272,8 @@ std::string NMD::SD_S9_(uint64 instruction)
std::string NMD::SD_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13336,8 +13335,8 @@ std::string NMD::SDBBP_32_(uint64 instruction)
*/
std::string NMD::SDC1_GP_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extr_uil2il2bs16Fmsb17(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 u_value = extract_u_17_to_2__s2(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13358,9 +13357,9 @@ std::string NMD::SDC1_GP_(uint64 instruction)
*/
std::string NMD::SDC1_S9_(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13382,9 +13381,9 @@ std::string NMD::SDC1_S9_(uint64 instruction)
*/
std::string NMD::SDC1_U12_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13407,8 +13406,8 @@ std::string NMD::SDC1_U12_(uint64 instruction)
std::string NMD::SDC1X(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -13431,8 +13430,8 @@ std::string NMD::SDC1X(uint64 instruction)
std::string NMD::SDC1XS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -13455,8 +13454,8 @@ std::string NMD::SDC1XS(uint64 instruction)
std::string NMD::SDC2(uint64 instruction)
{
uint64 cs_value = extract_cs_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string cs = CPR(copy(cs_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13479,9 +13478,9 @@ std::string NMD::SDC2(uint64 instruction)
std::string NMD::SDM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13505,7 +13504,7 @@ std::string NMD::SDM(uint64 instruction)
std::string NMD::SDPC_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 6);
@@ -13527,8 +13526,8 @@ std::string NMD::SDPC_48_(uint64 instruction)
std::string NMD::SDXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -13551,8 +13550,8 @@ std::string NMD::SDXS(uint64 instruction)
std::string NMD::SDX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -13618,9 +13617,9 @@ std::string NMD::SEH(uint64 instruction)
*/
std::string NMD::SEL_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13642,9 +13641,9 @@ std::string NMD::SEL_D(uint64 instruction)
*/
std::string NMD::SEL_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13666,9 +13665,9 @@ std::string NMD::SEL_S(uint64 instruction)
*/
std::string NMD::SELEQZ_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13690,9 +13689,9 @@ std::string NMD::SELEQZ_D(uint64 instruction)
*/
std::string NMD::SELEQZ_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13714,9 +13713,9 @@ std::string NMD::SELEQZ_S(uint64 instruction)
*/
std::string NMD::SELNEZ_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13738,9 +13737,9 @@ std::string NMD::SELNEZ_D(uint64 instruction)
*/
std::string NMD::SELNEZ_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -13763,8 +13762,8 @@ std::string NMD::SELNEZ_S(uint64 instruction)
std::string NMD::SEQI(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -13787,12 +13786,12 @@ std::string NMD::SEQI(uint64 instruction)
std::string NMD::SH_16_(uint64 instruction)
{
uint64 rtz3_value = extract_rtz3_9_8_7(instruction);
- uint64 u_value = extr_uil1il1bs2Fmsb2(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_2_1__s1(instruction);
- std::string rtz3 = GPR(encode_gpr3_store(rtz3_value));
+ std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("SH %s, %s(%s)", rtz3, u, rs3);
}
@@ -13811,7 +13810,7 @@ std::string NMD::SH_16_(uint64 instruction)
std::string NMD::SH_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil1il1bs17Fmsb17(instruction);
+ uint64 u_value = extract_u_17_to_1__s1(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13833,8 +13832,8 @@ std::string NMD::SH_GP_(uint64 instruction)
std::string NMD::SH_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13857,8 +13856,8 @@ std::string NMD::SH_S9_(uint64 instruction)
std::string NMD::SH_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -13881,8 +13880,8 @@ std::string NMD::SH_U12_(uint64 instruction)
std::string NMD::SHE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -13904,7 +13903,7 @@ std::string NMD::SHE(uint64 instruction)
*/
std::string NMD::SHILO(uint64 instruction)
{
- int64 shift_value = extract_shift_21_20_19_18_17_16(instruction);
+ int64 shift_value = extract_shift__se5_21_20_19_18_17_16(instruction);
uint64 ac_value = extract_ac_13_12(instruction);
std::string shift = IMMEDIATE(copy(shift_value));
@@ -14021,8 +14020,8 @@ std::string NMD::SHLL_S_PH(uint64 instruction)
std::string NMD::SHLL_S_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14045,8 +14044,8 @@ std::string NMD::SHLL_S_W(uint64 instruction)
std::string NMD::SHLLV_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14069,8 +14068,8 @@ std::string NMD::SHLLV_PH(uint64 instruction)
std::string NMD::SHLLV_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14093,8 +14092,8 @@ std::string NMD::SHLLV_QB(uint64 instruction)
std::string NMD::SHLLV_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14117,8 +14116,8 @@ std::string NMD::SHLLV_S_PH(uint64 instruction)
std::string NMD::SHLLV_S_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14141,8 +14140,8 @@ std::string NMD::SHLLV_S_W(uint64 instruction)
std::string NMD::SHRA_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14165,8 +14164,8 @@ std::string NMD::SHRA_PH(uint64 instruction)
std::string NMD::SHRA_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14189,8 +14188,8 @@ std::string NMD::SHRA_QB(uint64 instruction)
std::string NMD::SHRA_R_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14213,8 +14212,8 @@ std::string NMD::SHRA_R_PH(uint64 instruction)
std::string NMD::SHRA_R_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14237,8 +14236,8 @@ std::string NMD::SHRA_R_QB(uint64 instruction)
std::string NMD::SHRA_R_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12_11(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14261,8 +14260,8 @@ std::string NMD::SHRA_R_W(uint64 instruction)
std::string NMD::SHRAV_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14285,8 +14284,8 @@ std::string NMD::SHRAV_PH(uint64 instruction)
std::string NMD::SHRAV_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14309,8 +14308,8 @@ std::string NMD::SHRAV_QB(uint64 instruction)
std::string NMD::SHRAV_R_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14333,8 +14332,8 @@ std::string NMD::SHRAV_R_PH(uint64 instruction)
std::string NMD::SHRAV_R_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14357,8 +14356,8 @@ std::string NMD::SHRAV_R_QB(uint64 instruction)
std::string NMD::SHRAV_R_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14381,8 +14380,8 @@ std::string NMD::SHRAV_R_W(uint64 instruction)
std::string NMD::SHRL_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13_12(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14405,8 +14404,8 @@ std::string NMD::SHRL_PH(uint64 instruction)
std::string NMD::SHRL_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 sa_value = extract_sa_15_14_13(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 sa_value = extract_sa_15_14_13(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14429,8 +14428,8 @@ std::string NMD::SHRL_QB(uint64 instruction)
std::string NMD::SHRLV_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14453,8 +14452,8 @@ std::string NMD::SHRLV_PH(uint64 instruction)
std::string NMD::SHRLV_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rt = GPR(copy(rt_value));
@@ -14477,8 +14476,8 @@ std::string NMD::SHRLV_QB(uint64 instruction)
std::string NMD::SHX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14501,8 +14500,8 @@ std::string NMD::SHX(uint64 instruction)
std::string NMD::SHXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14544,12 +14543,12 @@ std::string NMD::SIGRIE(uint64 instruction)
*/
std::string NMD::SLL_16_(uint64 instruction)
{
- uint64 shift3_value = extract_shift3_2_1_0(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 shift3_value = extract_shift3_2_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
std::string shift3 = IMMEDIATE(encode_shift3_from_shift(shift3_value));
return img::format("SLL %s, %s, %s", rt3, rs3, shift3);
@@ -14569,8 +14568,8 @@ std::string NMD::SLL_16_(uint64 instruction)
std::string NMD::SLL_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14593,8 +14592,8 @@ std::string NMD::SLL_32_(uint64 instruction)
std::string NMD::SLLV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14617,8 +14616,8 @@ std::string NMD::SLLV(uint64 instruction)
std::string NMD::SLT(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14641,8 +14640,8 @@ std::string NMD::SLT(uint64 instruction)
std::string NMD::SLTI(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14665,8 +14664,8 @@ std::string NMD::SLTI(uint64 instruction)
std::string NMD::SLTIU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14689,8 +14688,8 @@ std::string NMD::SLTIU(uint64 instruction)
std::string NMD::SLTU(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14713,8 +14712,8 @@ std::string NMD::SLTU(uint64 instruction)
std::string NMD::SOV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14756,8 +14755,8 @@ std::string NMD::SPECIAL2(uint64 instruction)
*/
std::string NMD::SQRT_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -14778,8 +14777,8 @@ std::string NMD::SQRT_D(uint64 instruction)
*/
std::string NMD::SQRT_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -14825,8 +14824,8 @@ std::string NMD::SRA(uint64 instruction)
std::string NMD::SRAV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14848,12 +14847,12 @@ std::string NMD::SRAV(uint64 instruction)
*/
std::string NMD::SRL_16_(uint64 instruction)
{
- uint64 shift3_value = extract_shift3_2_1_0(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 shift3_value = extract_shift3_2_1_0(instruction);
- std::string rt3 = GPR(encode_gpr3(rt3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
std::string shift3 = IMMEDIATE(encode_shift3_from_shift(shift3_value));
return img::format("SRL %s, %s, %s", rt3, rs3, shift3);
@@ -14873,8 +14872,8 @@ std::string NMD::SRL_16_(uint64 instruction)
std::string NMD::SRL_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 shift_value = extract_shift_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
@@ -14897,8 +14896,8 @@ std::string NMD::SRL_32_(uint64 instruction)
std::string NMD::SRLV(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14921,8 +14920,8 @@ std::string NMD::SRLV(uint64 instruction)
std::string NMD::SUB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -14944,9 +14943,9 @@ std::string NMD::SUB(uint64 instruction)
*/
std::string NMD::SUB_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -14968,9 +14967,9 @@ std::string NMD::SUB_D(uint64 instruction)
*/
std::string NMD::SUB_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 fd_value = extract_fd_10_9_8_7_6(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
+ uint64 fd_value = extract_fd_15_14_13_12_11(instruction);
std::string fd = FPR(copy(fd_value));
std::string fs = FPR(copy(fs_value));
@@ -14993,8 +14992,8 @@ std::string NMD::SUB_S(uint64 instruction)
std::string NMD::SUBQ_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15018,8 +15017,8 @@ std::string NMD::SUBQ_PH(uint64 instruction)
std::string NMD::SUBQ_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15043,8 +15042,8 @@ std::string NMD::SUBQ_S_PH(uint64 instruction)
std::string NMD::SUBQ_S_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15068,8 +15067,8 @@ std::string NMD::SUBQ_S_W(uint64 instruction)
std::string NMD::SUBQH_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15093,8 +15092,8 @@ std::string NMD::SUBQH_PH(uint64 instruction)
std::string NMD::SUBQH_R_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15118,8 +15117,8 @@ std::string NMD::SUBQH_R_PH(uint64 instruction)
std::string NMD::SUBQH_R_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15143,8 +15142,8 @@ std::string NMD::SUBQH_R_W(uint64 instruction)
std::string NMD::SUBQH_W(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15166,13 +15165,13 @@ std::string NMD::SUBQH_W(uint64 instruction)
*/
std::string NMD::SUBU_16_(uint64 instruction)
{
- uint64 rd3_value = extract_rd3_3_2_1(instruction);
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 rd3_value = extract_rd3_3_2_1(instruction);
- std::string rd3 = GPR(encode_gpr3(rd3_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rd3 = GPR(decode_gpr_gpr3(rd3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
return img::format("SUBU %s, %s, %s", rd3, rs3, rt3);
}
@@ -15191,8 +15190,8 @@ std::string NMD::SUBU_16_(uint64 instruction)
std::string NMD::SUBU_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15215,8 +15214,8 @@ std::string NMD::SUBU_32_(uint64 instruction)
std::string NMD::SUBU_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15239,8 +15238,8 @@ std::string NMD::SUBU_PH(uint64 instruction)
std::string NMD::SUBU_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15263,8 +15262,8 @@ std::string NMD::SUBU_QB(uint64 instruction)
std::string NMD::SUBU_S_PH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15287,8 +15286,8 @@ std::string NMD::SUBU_S_PH(uint64 instruction)
std::string NMD::SUBU_S_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15312,8 +15311,8 @@ std::string NMD::SUBU_S_QB(uint64 instruction)
std::string NMD::SUBUH_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15337,8 +15336,8 @@ std::string NMD::SUBUH_QB(uint64 instruction)
std::string NMD::SUBUH_R_QB(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15361,12 +15360,12 @@ std::string NMD::SUBUH_R_QB(uint64 instruction)
std::string NMD::SW_16_(uint64 instruction)
{
uint64 rtz3_value = extract_rtz3_9_8_7(instruction);
- uint64 u_value = extr_uil0il2bs4Fmsb5(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
+ uint64 u_value = extract_u_3_2_1_0__s2(instruction);
- std::string rtz3 = GPR(encode_gpr3_store(rtz3_value));
+ std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs3 = GPR(encode_gpr3(rs3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
return img::format("SW %s, %s(%s)", rtz3, u, rs3);
}
@@ -15384,13 +15383,13 @@ std::string NMD::SW_16_(uint64 instruction)
*/
std::string NMD::SW_4X4_(uint64 instruction)
{
- uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
uint64 rtz4_value = extract_rtz4_9_7_6_5(instruction);
- uint64 u_value = extr_uil3il3bs1_il8il2bs1Fmsb3(instruction);
+ uint64 rs4_value = extract_rs4_4_2_1_0(instruction);
+ uint64 u_value = extract_u_3_8__s2(instruction);
- std::string rtz4 = GPR(encode_gpr4_zero(rtz4_value));
+ std::string rtz4 = GPR(decode_gpr_gpr4_zero(rtz4_value));
std::string u = IMMEDIATE(copy(u_value));
- std::string rs4 = GPR(encode_gpr4(rs4_value));
+ std::string rs4 = GPR(decode_gpr_gpr4(rs4_value));
return img::format("SW %s, %s(%s)", rtz4, u, rs4);
}
@@ -15408,10 +15407,10 @@ std::string NMD::SW_4X4_(uint64 instruction)
*/
std::string NMD::SW_GP16_(uint64 instruction)
{
+ uint64 u_value = extract_u_6_5_4_3_2_1_0__s2(instruction);
uint64 rtz3_value = extract_rtz3_9_8_7(instruction);
- uint64 u_value = extr_uil0il2bs7Fmsb8(instruction);
- std::string rtz3 = GPR(encode_gpr3_store(rtz3_value));
+ std::string rtz3 = GPR(decode_gpr_gpr3_src_store(rtz3_value));
std::string u = IMMEDIATE(copy(u_value));
return img::format("SW %s, %s($%d)", rtz3, u, 28);
@@ -15431,7 +15430,7 @@ std::string NMD::SW_GP16_(uint64 instruction)
std::string NMD::SW_GP_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extr_uil2il2bs19Fmsb20(instruction);
+ uint64 u_value = extract_u_20_to_2__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -15453,7 +15452,7 @@ std::string NMD::SW_GP_(uint64 instruction)
std::string NMD::SW_S9_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
std::string rt = GPR(copy(rt_value));
@@ -15477,7 +15476,7 @@ std::string NMD::SW_S9_(uint64 instruction)
std::string NMD::SW_SP_(uint64 instruction)
{
uint64 rt_value = extract_rt_9_8_7_6_5(instruction);
- uint64 u_value = extr_uil0il2bs5Fmsb6(instruction);
+ uint64 u_value = extract_u_4_3_2_1_0__s2(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -15499,8 +15498,8 @@ std::string NMD::SW_SP_(uint64 instruction)
std::string NMD::SW_U12_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -15522,8 +15521,8 @@ std::string NMD::SW_U12_(uint64 instruction)
*/
std::string NMD::SWC1_GP_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extr_uil2il2bs16Fmsb17(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 u_value = extract_u_17_to_2__s2(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -15544,9 +15543,9 @@ std::string NMD::SWC1_GP_(uint64 instruction)
*/
std::string NMD::SWC1_S9_(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -15568,9 +15567,9 @@ std::string NMD::SWC1_S9_(uint64 instruction)
*/
std::string NMD::SWC1_U12_(uint64 instruction)
{
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string ft = FPR(copy(ft_value));
std::string u = IMMEDIATE(copy(u_value));
@@ -15593,8 +15592,8 @@ std::string NMD::SWC1_U12_(uint64 instruction)
std::string NMD::SWC1X(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -15617,8 +15616,8 @@ std::string NMD::SWC1X(uint64 instruction)
std::string NMD::SWC1XS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_15_14_13_12_11(instruction);
std::string ft = FPR(copy(ft_value));
std::string rs = GPR(copy(rs_value));
@@ -15641,8 +15640,8 @@ std::string NMD::SWC1XS(uint64 instruction)
std::string NMD::SWC2(uint64 instruction)
{
uint64 cs_value = extract_cs_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string cs = CPR(copy(cs_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -15665,8 +15664,8 @@ std::string NMD::SWC2(uint64 instruction)
std::string NMD::SWE(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -15689,9 +15688,9 @@ std::string NMD::SWE(uint64 instruction)
std::string NMD::SWM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -15715,7 +15714,7 @@ std::string NMD::SWM(uint64 instruction)
std::string NMD::SWPC_48_(uint64 instruction)
{
uint64 rt_value = extract_rt_41_40_39_38_37(instruction);
- int64 s_value = extr_sil0il16bs16_il16il0bs16Tmsb31(instruction);
+ int64 s_value = extract_s__se31_15_to_0_31_to_16(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = ADDRESS(encode_s_from_address(s_value), 6);
@@ -15737,8 +15736,8 @@ std::string NMD::SWPC_48_(uint64 instruction)
std::string NMD::SWX(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15761,8 +15760,8 @@ std::string NMD::SWX(uint64 instruction)
std::string NMD::SWXS(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -15804,8 +15803,8 @@ std::string NMD::SYNC(uint64 instruction)
*/
std::string NMD::SYNCI(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string s = IMMEDIATE(copy(s_value));
std::string rs = GPR(copy(rs_value));
@@ -15826,8 +15825,8 @@ std::string NMD::SYNCI(uint64 instruction)
*/
std::string NMD::SYNCIE(uint64 instruction)
{
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string s = IMMEDIATE(copy(s_value));
std::string rs = GPR(copy(rs_value));
@@ -16146,8 +16145,8 @@ std::string NMD::TNE(uint64 instruction)
*/
std::string NMD::TRUNC_L_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -16168,8 +16167,8 @@ std::string NMD::TRUNC_L_D(uint64 instruction)
*/
std::string NMD::TRUNC_L_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -16190,8 +16189,8 @@ std::string NMD::TRUNC_L_S(uint64 instruction)
*/
std::string NMD::TRUNC_W_D(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -16212,8 +16211,8 @@ std::string NMD::TRUNC_W_D(uint64 instruction)
*/
std::string NMD::TRUNC_W_S(uint64 instruction)
{
- uint64 fs_value = extract_fs_15_14_13_12_11(instruction);
- uint64 ft_value = extract_ft_20_19_18_17_16(instruction);
+ uint64 ft_value = extract_ft_25_24_23_22_21(instruction);
+ uint64 fs_value = extract_fs_20_19_18_17_16(instruction);
std::string ft = FPR(copy(ft_value));
std::string fs = FPR(copy(fs_value));
@@ -16235,9 +16234,9 @@ std::string NMD::TRUNC_W_S(uint64 instruction)
std::string NMD::UALDM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16261,8 +16260,8 @@ std::string NMD::UALDM(uint64 instruction)
std::string NMD::UALH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16285,9 +16284,9 @@ std::string NMD::UALH(uint64 instruction)
std::string NMD::UALWM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16311,9 +16310,9 @@ std::string NMD::UALWM(uint64 instruction)
std::string NMD::UASDM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16337,8 +16336,8 @@ std::string NMD::UASDM(uint64 instruction)
std::string NMD::UASH(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16361,9 +16360,9 @@ std::string NMD::UASH(uint64 instruction)
std::string NMD::UASWM(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 count3_value = extract_count3_14_13_12(instruction);
- int64 s_value = extr_sil0il0bs8_il15il8bs1Tmsb8(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ int64 s_value = extract_s__se8_15_7_6_5_4_3_2_1_0(instruction);
+ uint64 count3_value = extract_count3_14_13_12(instruction);
std::string rt = GPR(copy(rt_value));
std::string s = IMMEDIATE(copy(s_value));
@@ -16470,8 +16469,8 @@ std::string NMD::XOR_16_(uint64 instruction)
uint64 rt3_value = extract_rt3_9_8_7(instruction);
uint64 rs3_value = extract_rs3_6_5_4(instruction);
- std::string rs3 = GPR(encode_gpr3(rs3_value));
- std::string rt3 = GPR(encode_gpr3(rt3_value));
+ std::string rs3 = GPR(decode_gpr_gpr3(rs3_value));
+ std::string rt3 = GPR(decode_gpr_gpr3(rt3_value));
return img::format("XOR %s, %s", rs3, rt3);
}
@@ -16490,8 +16489,8 @@ std::string NMD::XOR_16_(uint64 instruction)
std::string NMD::XOR_32_(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 rd_value = extract_rd_20_19_18_17_16(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 rd_value = extract_rd_15_14_13_12_11(instruction);
std::string rd = GPR(copy(rd_value));
std::string rs = GPR(copy(rs_value));
@@ -16514,8 +16513,8 @@ std::string NMD::XOR_32_(uint64 instruction)
std::string NMD::XORI(uint64 instruction)
{
uint64 rt_value = extract_rt_25_24_23_22_21(instruction);
- uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
uint64 rs_value = extract_rs_20_19_18_17_16(instruction);
+ uint64 u_value = extract_u_11_10_9_8_7_6_5_4_3_2_1_0(instruction);
std::string rt = GPR(copy(rt_value));
std::string rs = GPR(copy(rs_value));
diff --git a/disas/nanomips.h b/disas/nanomips.h
index 84cc9a6dfc..6482edafe3 100644
--- a/disas/nanomips.h
+++ b/disas/nanomips.h
@@ -1,13 +1,13 @@
/*
* Header file for nanoMIPS disassembler component of QEMU
*
- * Copyright (C) 2018 Wave Computing
+ * Copyright (C) 2018 Wave Computing, Inc.
* Copyright (C) 2018 Matthew Fortune <matthew.fortune@mips.com>
- * Copyright (C) 2018 Aleksandar Markovic <aleksandar.markovic@wavecomp.com>
+ * Copyright (C) 2018 Aleksandar Markovic <amarkovic@wavecomp.com>
*
* 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, either version 3 of the License, or
+ * the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
@@ -17,6 +17,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
*/
#ifndef NANOMIPS_DISASSEMBLER_H
@@ -24,14 +25,14 @@
#include <string>
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-typedef long long int64;
-typedef unsigned long long uint64;
+typedef int64_t int64;
+typedef uint64_t uint64;
+typedef uint32_t uint32;
+typedef uint16_t uint16;
namespace img
{
- typedef unsigned long long address;
+ typedef uint64_t address;
}
@@ -104,13 +105,14 @@ private:
uint64 renumber_registers(uint64 index, uint64 *register_list,
size_t register_list_size);
- uint64 encode_gpr3(uint64 d);
- uint64 encode_gpr3_store(uint64 d);
- uint64 encode_rd1_from_rd(uint64 d);
- uint64 encode_gpr4_zero(uint64 d);
- uint64 encode_gpr4(uint64 d);
- uint64 encode_rd2_reg1(uint64 d);
- uint64 encode_rd2_reg2(uint64 d);
+
+ uint64 decode_gpr_gpr4(uint64 d);
+ uint64 decode_gpr_gpr4_zero(uint64 d);
+ uint64 decode_gpr_gpr3(uint64 d);
+ uint64 decode_gpr_gpr3_src_store(uint64 d);
+ uint64 decode_gpr_gpr2_reg1(uint64 d);
+ uint64 decode_gpr_gpr2_reg2(uint64 d);
+ uint64 decode_gpr_gpr1(uint64 d);
uint64 copy(uint64 d);
int64 copy(int64 d);
@@ -142,20 +144,20 @@ private:
std::string CPR(uint64 reg);
std::string ADDRESS(uint64 value, int instruction_size);
- int64 extract_s_4_2_1_0(uint64 instruction);
- int64 extr_sil0il0bs8_il15il8bs1Tmsb8(uint64 instruction);
- int64 extr_sil0il10bs1_il1il1bs9Tmsb10(uint64 instruction);
- int64 extr_sil0il11bs1_il1il1bs10Tmsb11(uint64 instruction);
- int64 extr_sil0il14bs1_il1il1bs13Tmsb14(uint64 instruction);
- int64 extr_sil0il16bs16_il16il0bs16Tmsb31(uint64 instruction);
- int64 extr_sil0il21bs1_il1il1bs20Tmsb21(uint64 instruction);
- int64 extr_sil0il25bs1_il1il1bs24Tmsb25(uint64 instruction);
- int64 extr_sil0il31bs1_il2il21bs10_il12il12bs9Tmsb31(uint64 instruction);
- int64 extr_sil0il7bs1_il1il1bs6Tmsb7(uint64 instruction);
- int64 extr_sil11il0bs10Tmsb9(uint64 instruction);
- int64 extract_shift_21_20_19_18_17_16(uint64 instruction);
- int64 extr_sil2il2bs6_il15il8bs1Tmsb8(uint64 instruction);
- int64 extr_sil3il3bs5_il15il8bs1Tmsb8(uint64 instruction);
+ int64 extract_s__se3_4_2_1_0(uint64 instruction);
+ int64 extract_s__se7_0_6_5_4_3_2_1_s1(uint64 instruction);
+ int64 extract_s__se8_15_7_6_5_4_3_s3(uint64 instruction);
+ int64 extract_s__se8_15_7_6_5_4_3_2_s2(uint64 instruction);
+ int64 extract_s__se8_15_7_6_5_4_3_2_1_0(uint64 instruction);
+ int64 extract_s__se9_20_19_18_17_16_15_14_13_12_11(uint64 instruction);
+ int64 extract_s__se10_0_9_8_7_6_5_4_3_2_1_s1(uint64 instruction);
+ int64 extract_s__se11_0_10_9_8_7_6_5_4_3_2_1_0_s1(uint64 instruction);
+ int64 extract_s__se14_0_13_to_1_s1(uint64 instruction);
+ int64 extract_s__se21_0_20_to_1_s1(uint64 instruction);
+ int64 extract_s__se25_0_24_to_1_s1(uint64 instruction);
+ int64 extract_s__se31_15_to_0_31_to_16(uint64 instruction);
+ int64 extract_s__se31_0_11_to_2_20_to_12_s12(uint64 instruction);
+ int64 extract_shift__se5_21_20_19_18_17_16(uint64 instruction);
uint64 extract_ac_13_12(uint64 instruction);
uint64 extract_bit_16_15_14_13_12_11(uint64 instruction);
@@ -175,10 +177,10 @@ private:
uint64 extract_ct_25_24_23_22_21(uint64 instruction);
uint64 extract_eu_3_2_1_0(uint64 instruction);
uint64 extract_eu_6_5_4_3_2_1_0(uint64 instruction);
- uint64 extract_fd_10_9_8_7_6(uint64 instruction);
- uint64 extract_fs_15_14_13_12_11(uint64 instruction);
+ uint64 extract_fd_15_14_13_12_11(uint64 instruction);
+ uint64 extract_fs_20_19_18_17_16(uint64 instruction);
uint64 extract_ft_15_14_13_12_11(uint64 instruction);
- uint64 extract_ft_20_19_18_17_16(uint64 instruction);
+ uint64 extract_ft_25_24_23_22_21(uint64 instruction);
uint64 extract_gp_2(uint64 instruction);
uint64 extract_hint_25_24_23_22_21(uint64 instruction);
uint64 extract_hs_20_19_18_17_16(uint64 instruction);
@@ -190,7 +192,7 @@ private:
uint64 extract_rdl_25_24(uint64 instruction);
uint64 extract_rd2_3_8(uint64 instruction);
uint64 extract_rd3_3_2_1(uint64 instruction);
- uint64 extract_rd_20_19_18_17_16(uint64 instruction);
+ uint64 extract_rd_15_14_13_12_11(uint64 instruction);
uint64 extract_rs3_6_5_4(uint64 instruction);
uint64 extract_rs4_4_2_1_0(uint64 instruction);
uint64 extract_rs_4_3_2_1_0(uint64 instruction);
@@ -217,7 +219,7 @@ private:
uint64 extract_shift_20_19_18_17_16(uint64 instruction);
uint64 extract_shift_10_9_8_7_6(uint64 instruction);
uint64 extract_shiftx_11_10_9_8_7_6(uint64 instruction);
- uint64 extr_shiftxil7il1bs4Fmsb4(uint64 instruction);
+ uint64 extract_shiftx_10_9_8_7__s1(uint64 instruction);
uint64 extract_size_20_19_18_17_16(uint64 instruction);
uint64 extract_stripe_6(uint64 instruction);
uint64 extract_stype_20_19_18_17_16(uint64 instruction);
@@ -226,49 +228,24 @@ private:
uint64 extract_u_15_to_0(uint64 instruction);
uint64 extract_u_17_to_0(uint64 instruction);
uint64 extract_u_1_0(uint64 instruction);
- uint64 extr_uil0il1bs4Fmsb4(uint64 instruction);
- uint64 extr_uil0il2bs3Fmsb4(uint64 instruction);
- uint64 extr_uil0il2bs4Fmsb5(uint64 instruction);
- uint64 extr_uil0il2bs5Fmsb6(uint64 instruction);
- uint64 extr_uil0il2bs6Fmsb7(uint64 instruction);
- uint64 extr_uil0il2bs7Fmsb8(uint64 instruction);
- uint64 extr_uil0il32bs32Fmsb63(uint64 instruction);
+ uint64 extract_u_3_2_1_0__s1(uint64 instruction);
+ uint64 extract_u_2_1_0__s2(uint64 instruction);
+ uint64 extract_u_3_2_1_0__s2(uint64 instruction);
+ uint64 extract_u_4_3_2_1_0__s2(uint64 instruction);
+ uint64 extract_u_5_4_3_2_1_0__s2(uint64 instruction);
+ uint64 extract_u_6_5_4_3_2_1_0__s2(uint64 instruction);
+ uint64 extract_u_31_to_0__s32(uint64 instruction);
uint64 extract_u_10(uint64 instruction);
uint64 extract_u_17_16_15_14_13_12_11(uint64 instruction);
uint64 extract_u_20_19_18_17_16_15_14_13(uint64 instruction);
- uint64 extr_uil1il1bs17Fmsb17(uint64 instruction);
- uint64 extr_uil1il1bs2Fmsb2(uint64 instruction);
- uint64 extr_uil2il2bs16Fmsb17(uint64 instruction);
- uint64 extr_uil2il2bs19Fmsb20(uint64 instruction);
- uint64 extr_uil3il3bs18Fmsb20(uint64 instruction);
- uint64 extr_uil3il3bs1_il8il2bs1Fmsb3(uint64 instruction);
- uint64 extr_uil3il3bs9Fmsb11(uint64 instruction);
- uint64 extr_uil4il4bs4Fmsb7(uint64 instruction);
- uint64 extr_xil0il0bs12Fmsb11(uint64 instruction);
- uint64 extr_xil0il0bs3_il4il0bs1Fmsb2(uint64 instruction);
- uint64 extr_xil10il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil10il0bs1_il11il0bs5Fmsb4(uint64 instruction);
- uint64 extr_xil10il0bs1_il14il0bs2Fmsb1(uint64 instruction);
- uint64 extr_xil10il0bs4_il22il0bs4Fmsb3(uint64 instruction);
- uint64 extr_xil10il0bs6Fmsb5(uint64 instruction);
- uint64 extr_xil11il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil11il0bs5Fmsb4(uint64 instruction);
- uint64 extr_xil12il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil14il0bs1_il15il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil14il0bs2Fmsb1(uint64 instruction);
- uint64 extr_xil15il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil16il0bs10Fmsb9(uint64 instruction);
- uint64 extr_xil16il0bs5Fmsb4(uint64 instruction);
- uint64 extr_xil17il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil17il0bs9Fmsb8(uint64 instruction);
- uint64 extr_xil21il0bs5Fmsb4(uint64 instruction);
- uint64 extr_xil24il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil2il0bs1_il15il0bs1Fmsb0(uint64 instruction);
- uint64 extr_xil6il0bs3Fmsb2(uint64 instruction);
- uint64 extr_xil6il0bs3_il10il0bs1Fmsb2(uint64 instruction);
- uint64 extr_xil9il0bs2Fmsb1(uint64 instruction);
- uint64 extr_xil9il0bs3Fmsb2(uint64 instruction);
- uint64 extr_xil9il0bs3_il16il0bs5Fmsb4(uint64 instruction);
+ uint64 extract_u_17_to_1__s1(uint64 instruction);
+ uint64 extract_u_2_1__s1(uint64 instruction);
+ uint64 extract_u_17_to_2__s2(uint64 instruction);
+ uint64 extract_u_20_to_2__s2(uint64 instruction);
+ uint64 extract_u_20_to_3__s3(uint64 instruction);
+ uint64 extract_u_3_8__s2(uint64 instruction);
+ uint64 extract_u_11_10_9_8_7_6_5_4_3__s3(uint64 instruction);
+ uint64 extract_u_7_6_5_4__s4(uint64 instruction);
bool ADDIU_32__cond(uint64 instruction);
bool ADDIU_RS5__cond(uint64 instruction);
diff --git a/disas/ppc.c b/disas/ppc.c
index 5ab9c35a84..da1140ba2b 100644
--- a/disas/ppc.c
+++ b/disas/ppc.c
@@ -3734,6 +3734,8 @@ const struct powerpc_opcode powerpc_opcodes[] = {
{ "addmeo.", XO(31,234,1,1), XORB_MASK, PPCCOM, { RT, RA } },
{ "ameo.", XO(31,234,1,1), XORB_MASK, PWRCOM, { RT, RA } },
+{ "addex", XO(31,170,0,0), XO_MASK, POWER9, { RT, RA, RB } },
+
{ "mullw", XO(31,235,0,0), XO_MASK, PPCCOM, { RT, RA, RB } },
{ "muls", XO(31,235,0,0), XO_MASK, PWRCOM, { RT, RA, RB } },
{ "mullw.", XO(31,235,0,1), XO_MASK, PPCCOM, { RT, RA, RB } },
diff --git a/docs/cpu-hotplug.rst b/docs/cpu-hotplug.rst
new file mode 100644
index 0000000000..1c268e00b4
--- /dev/null
+++ b/docs/cpu-hotplug.rst
@@ -0,0 +1,142 @@
+===================
+Virtual CPU hotplug
+===================
+
+A complete example of vCPU hotplug (and hot-unplug) using QMP
+``device_add`` and ``device_del``.
+
+vCPU hotplug
+------------
+
+(1) Launch QEMU as follows (note that the "maxcpus" is mandatory to
+ allow vCPU hotplug)::
+
+ $ qemu-system-x86_64 -display none -no-user-config -m 2048 \
+ -nodefaults -monitor stdio -machine pc,accel=kvm,usb=off \
+ -smp 1,maxcpus=2 -cpu IvyBridge-IBRS \
+ -qmp unix:/tmp/qmp-sock,server,nowait
+
+(2) Run 'qmp-shell' (located in the source tree, under: "scripts/qmp/)
+ to connect to the just-launched QEMU::
+
+ $> ./qmp-shell -p -v /tmp/qmp-sock
+ [...]
+ (QEMU)
+
+(3) Find out which CPU types could be plugged, and into which sockets::
+
+ (QEMU) query-hotpluggable-cpus
+ {
+ "execute": "query-hotpluggable-cpus",
+ "arguments": {}
+ }
+ {
+ "return": [
+ {
+ "type": "IvyBridge-IBRS-x86_64-cpu",
+ "vcpus-count": 1,
+ "props": {
+ "socket-id": 1,
+ "core-id": 0,
+ "thread-id": 0
+ }
+ },
+ {
+ "qom-path": "/machine/unattached/device[0]",
+ "type": "IvyBridge-IBRS-x86_64-cpu",
+ "vcpus-count": 1,
+ "props": {
+ "socket-id": 0,
+ "core-id": 0,
+ "thread-id": 0
+ }
+ }
+ ]
+ }
+ (QEMU)
+
+(4) The ``query-hotpluggable-cpus`` command returns an object for CPUs
+ that are present (containing a "qom-path" member) or which may be
+ hot-plugged (no "qom-path" member). From its output in step (3), we
+ can see that ``IvyBridge-IBRS-x86_64-cpu`` is present in socket 0,
+ while hot-plugging a CPU into socket 1 requires passing the listed
+ properties to QMP ``device_add``:
+
+ (QEMU) device_add id=cpu-2 driver=IvyBridge-IBRS-x86_64-cpu socket-id=1 core-id=0 thread-id=0
+ {
+ "execute": "device_add",
+ "arguments": {
+ "socket-id": 1,
+ "driver": "IvyBridge-IBRS-x86_64-cpu",
+ "id": "cpu-2",
+ "core-id": 0,
+ "thread-id": 0
+ }
+ }
+ {
+ "return": {}
+ }
+ (QEMU)
+
+(5) Optionally, run QMP `query-cpus-fast` for some details about the
+ vCPUs::
+
+ (QEMU) query-cpus-fast
+ {
+ "execute": "query-cpus-fast",
+ "arguments": {}
+ }
+ {
+ "return": [
+ {
+ "qom-path": "/machine/unattached/device[0]",
+ "target": "x86_64",
+ "thread-id": 11534,
+ "cpu-index": 0,
+ "props": {
+ "socket-id": 0,
+ "core-id": 0,
+ "thread-id": 0
+ },
+ "arch": "x86"
+ },
+ {
+ "qom-path": "/machine/peripheral/cpu-2",
+ "target": "x86_64",
+ "thread-id": 12106,
+ "cpu-index": 1,
+ "props": {
+ "socket-id": 1,
+ "core-id": 0,
+ "thread-id": 0
+ },
+ "arch": "x86"
+ }
+ ]
+ }
+ (QEMU)
+
+vCPU hot-unplug
+---------------
+
+From the 'qmp-shell', invoke the QMP ``device_del`` command::
+
+ (QEMU) device_del id=cpu-2
+ {
+ "execute": "device_del",
+ "arguments": {
+ "id": "cpu-2"
+ }
+ }
+ {
+ "return": {}
+ }
+ (QEMU)
+
+.. note::
+ vCPU hot-unplug requires guest cooperation; so the ``device_del``
+ command above does not guarantee vCPU removal -- it's a "request to
+ unplug". At this point, the guest will get a System Control
+ Interupt (SCI) and calls the ACPI handler for the affected vCPU
+ device. Then the guest kernel will bring the vCPU offline and tell
+ QEMU to unplug it.
diff --git a/docs/devel/build-system.txt b/docs/devel/build-system.txt
index 52501f2ad9..f9fd27fab0 100644
--- a/docs/devel/build-system.txt
+++ b/docs/devel/build-system.txt
@@ -393,7 +393,7 @@ all use $(obj) as a prefix to the target, e.g.
This file provides the entry point used to build each individual system
or userspace emulator target. Each enabled target has its own
subdirectory. For example if configure is run with the argument
-'--target-list=x86_64-softmmu', then a sub-directory 'x86_64-softmu'
+'--target-list=x86_64-softmmu', then a sub-directory 'x86_64-softmmu'
will be created, containing a 'Makefile' which symlinks back to
Makefile.target
diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst
index 57d8c524bf..c74cd090e6 100644
--- a/docs/devel/loads-stores.rst
+++ b/docs/devel/loads-stores.rst
@@ -253,6 +253,22 @@ Regexes for git grep
- ``\<address_space_ldu\?[bwql]\(_[lb]e\)\?\>``
- ``\<address_space_st[bwql]\(_[lb]e\)\?\>``
+``address_space_write_rom``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This function performs a write by physical address like
+``address_space_write``, except that if the write is to a ROM then
+the ROM contents will be modified, even though a write by the guest
+CPU to the ROM would be ignored. This is used for non-guest writes
+like writes from the gdb debug stub or initial loading of ROM contents.
+
+Note that portions of the write which attempt to write data to a
+device will be silently ignored -- only real RAM and ROM will
+be written to.
+
+Regexes for git grep
+ - ``address_space_write_rom``
+
``{ld,st}*_phys``
~~~~~~~~~~~~~~~~~
@@ -315,25 +331,6 @@ For new code they are better avoided:
Regexes for git grep
- ``\<cpu_physical_memory_\(read\|write\|rw\)\>``
-``cpu_physical_memory_write_rom``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This function performs a write by physical address like
-``address_space_write``, except that if the write is to a ROM then
-the ROM contents will be modified, even though a write by the guest
-CPU to the ROM would be ignored.
-
-Note that unlike ``cpu_physical_memory_write()`` this function takes
-an AddressSpace argument, but unlike ``address_space_write()`` this
-function does not take a ``MemTxAttrs`` or return a ``MemTxResult``.
-
-**TODO**: we should probably clean up this inconsistency and
-turn the function into ``address_space_write_rom`` with an API
-matching ``address_space_write``.
-
-``cpu_physical_memory_write_rom``
-
-
``cpu_memory_rw_debug``
~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/devel/migration.rst b/docs/devel/migration.rst
index e7658ab050..220059679a 100644
--- a/docs/devel/migration.rst
+++ b/docs/devel/migration.rst
@@ -419,8 +419,13 @@ The functions to do that are inside a vmstate definition, and are called:
This function is called before we save the state of one device.
-Example: You can look at hpet.c, that uses the three function to
-massage the state that is transferred.
+- ``int (*post_save)(void *opaque);``
+
+ This function is called after we save the state of one device
+ (even upon failure, unless the call to pre_save returned an error).
+
+Example: You can look at hpet.c, that uses the first three functions
+to massage the state that is transferred.
The ``VMSTATE_WITH_TMP`` macro may be useful when the migration
data doesn't match the stored device data well; it allows an
diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt
index 53eaf01f34..43bd853e69 100644
--- a/docs/devel/qapi-code-gen.txt
+++ b/docs/devel/qapi-code-gen.txt
@@ -26,7 +26,7 @@ how the schemas, scripts, and resulting code are used.
== QMP/Guest agent schema ==
A QAPI schema file is designed to be loosely based on JSON
-(http://www.ietf.org/rfc/rfc7159.txt) with changes for quoting style
+(http://www.ietf.org/rfc/rfc8259.txt) with changes for quoting style
and the use of comments; a QAPI schema file is then parsed by a python
code generation program. A valid QAPI schema consists of a series of
top-level expressions, with no commas between them. Where
@@ -752,6 +752,25 @@ gets its generated code guarded like this:
#endif /* defined(HAVE_BAR) */
#endif /* defined(CONFIG_FOO) */
+Where a member can be defined with a single string value for its type,
+it is also possible to supply a dictionary instead with both 'type'
+and 'if' keys.
+
+Example: a conditional 'bar' member
+
+{ 'struct': 'IfStruct', 'data':
+ { 'foo': 'int',
+ 'bar': { 'type': 'int', 'if': 'defined(IFCOND)'} } }
+
+An enum value can be replaced by a dictionary with a 'name' and a 'if'
+key.
+
+Example: a conditional 'bar' enum member.
+
+{ 'enum': 'IfEnum', 'data':
+ [ 'foo',
+ { 'name' : 'bar', 'if': 'defined(IFCOND)' } ] }
+
Please note that you are responsible to ensure that the C code will
compile with an arbitrary combination of conditions, since the
generators are unable to check it at this point.
diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt
index 77b5f45911..fc64473e02 100644
--- a/docs/interop/nbd.txt
+++ b/docs/interop/nbd.txt
@@ -15,7 +15,6 @@ Qemu supports the "base:allocation" metadata context as defined in the
NBD protocol specification, and also defines an additional metadata
namespace "qemu".
-
== "qemu" namespace ==
The "qemu" namespace currently contains only one type of context,
@@ -36,3 +35,21 @@ in addition to "qemu:dirty-bitmap:<dirty-bitmap-export-name>":
namespace.
* "qemu:dirty-bitmap:" - returns list of all available dirty-bitmap
metadata contexts.
+
+= Features by version =
+
+The following list documents which qemu version first implemented
+various features (both as a server exposing the feature, and as a
+client taking advantage of the feature when present), to make it
+easier to plan for cross-version interoperability. Note that in
+several cases, the initial release containing a feature may require
+additional patches from the corresponding stable branch to fix bugs in
+the operation of that feature.
+
+* 2.6: NBD_OPT_STARTTLS with TLS X.509 Certificates
+* 2.8: NBD_CMD_WRITE_ZEROES
+* 2.10: NBD_OPT_GO, NBD_INFO_BLOCK
+* 2.11: NBD_OPT_STRUCTURED_REPLY
+* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation"
+* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK),
+NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE
diff --git a/docs/interop/qmp-spec.txt b/docs/interop/qmp-spec.txt
index 8f7da0245d..adcf86754d 100644
--- a/docs/interop/qmp-spec.txt
+++ b/docs/interop/qmp-spec.txt
@@ -32,7 +32,7 @@ following format:
Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined
by the JSON standard:
-http://www.ietf.org/rfc/rfc7159.txt
+http://www.ietf.org/rfc/rfc8259.txt
The server expects its input to be encoded in UTF-8, and sends its
output encoded in ASCII.
@@ -130,8 +130,9 @@ to pass "id" with out-of-band commands. Passing it with all commands
is recommended for clients that accept capability "oob".
If the client sends in-band commands faster than the server can
-execute them, the server will eventually drop commands to limit the
-queue length. The sever sends event COMMAND_DROPPED then.
+execute them, the server will stop reading the requests from the QMP
+channel until the request queue length is reduced to an acceptable
+range.
Only a few commands support out-of-band execution. The ones that do
have "allow-oob": true in output of query-qmp-schema.
diff --git a/docs/pvrdma.txt b/docs/pvrdma.txt
index 5599318159..0f0dd8a7e5 100644
--- a/docs/pvrdma.txt
+++ b/docs/pvrdma.txt
@@ -9,8 +9,9 @@ It works with its Linux Kernel driver AS IS, no need for any special guest
modifications.
While it complies with the VMware device, it can also communicate with bare
-metal RDMA-enabled machines and does not require an RDMA HCA in the host, it
-can work with Soft-RoCE (rxe).
+metal RDMA-enabled machines as peers.
+
+It does not require an RDMA HCA in the host, it can work with Soft-RoCE (rxe).
It does not require the whole guest RAM to be pinned allowing memory
over-commit and, even if not implemented yet, migration support will be
@@ -78,29 +79,118 @@ the required RDMA libraries.
3. Usage
========
+
+
+3.1 VM Memory settings
+======================
Currently the device is working only with memory backed RAM
and it must be mark as "shared":
-m 1G \
-object memory-backend-ram,id=mb1,size=1G,share \
-numa node,memdev=mb1 \
-The pvrdma device is composed of two functions:
- - Function 0 is a vmxnet Ethernet Device which is redundant in Guest
- but is required to pass the ibdevice GID using its MAC.
- Examples:
- For an rxe backend using eth0 interface it will use its mac:
- -device vmxnet3,addr=<slot>.0,multifunction=on,mac=<eth0 MAC>
- For an SRIOV VF, we take the Ethernet Interface exposed by it:
- -device vmxnet3,multifunction=on,mac=<RoCE eth MAC>
- - Function 1 is the actual device:
- -device pvrdma,addr=<slot>.1,backend-dev=<ibdevice>,backend-gid-idx=<gid>,backend-port=<port>
- where the ibdevice can be rxe or RDMA VF (e.g. mlx5_4)
- Note: Pay special attention that the GID at backend-gid-idx matches vmxnet's MAC.
- The rules of conversion are part of the RoCE spec, but since manual conversion
- is not required, spotting problems is not hard:
- Example: GID: fe80:0000:0000:0000:7efe:90ff:fecb:743a
- MAC: 7c:fe:90:cb:74:3a
- Note the difference between the first byte of the MAC and the GID.
+
+3.2 MAD Multiplexer
+===================
+MAD Multiplexer is a service that exposes MAD-like interface for VMs in
+order to overcome the limitation where only single entity can register with
+MAD layer to send and receive RDMA-CM MAD packets.
+
+To build rdmacm-mux run
+# make rdmacm-mux
+
+Before running the rdmacm-mux make sure that both ib_cm and rdma_cm kernel
+modules aren't loaded, otherwise the rdmacm-mux service will fail to start.
+
+The application accepts 3 command line arguments and exposes a UNIX socket
+to pass control and data to it.
+-d rdma-device-name Name of RDMA device to register with
+-s unix-socket-path Path to unix socket to listen (default /var/run/rdmacm-mux)
+-p rdma-device-port Port number of RDMA device to register with (default 1)
+The final UNIX socket file name is a concatenation of the 3 arguments so
+for example for device mlx5_0 on port 2 this /var/run/rdmacm-mux-mlx5_0-2
+will be created.
+
+pvrdma requires this service.
+
+Please refer to contrib/rdmacm-mux for more details.
+
+
+3.3 Service exposed by libvirt daemon
+=====================================
+The control over the RDMA device's GID table is done by updating the
+device's Ethernet function addresses.
+Usually the first GID entry is determined by the MAC address, the second by
+the first IPv6 address and the third by the IPv4 address. Other entries can
+be added by adding more IP addresses. The opposite is the same, i.e.
+whenever an address is removed, the corresponding GID entry is removed.
+The process is done by the network and RDMA stacks. Whenever an address is
+added the ib_core driver is notified and calls the device driver add_gid
+function which in turn update the device.
+To support this in pvrdma device the device hooks into the create_bind and
+destroy_bind HW commands triggered by pvrdma driver in guest.
+
+Whenever changed is made to the pvrdma port's GID table a special QMP
+messages is sent to be processed by libvirt to update the address of the
+backend Ethernet device.
+
+pvrdma requires that libvirt service will be up.
+
+
+3.4 PCI devices settings
+========================
+RoCE device exposes two functions - an Ethernet and RDMA.
+To support it, pvrdma device is composed of two PCI functions, an Ethernet
+device of type vmxnet3 on PCI slot 0 and a PVRDMA device on PCI slot 1. The
+Ethernet function can be used for other Ethernet purposes such as IP.
+
+
+3.5 Device parameters
+=====================
+- netdev: Specifies the Ethernet device function name on the host for
+ example enp175s0f0. For Soft-RoCE device (rxe) this would be the Ethernet
+ device used to create it.
+- ibdev: The IB device name on host for example rxe0, mlx5_0 etc.
+- mad-chardev: The name of the MAD multiplexer char device.
+- ibport: In case of multi-port device (such as Mellanox's HCA) this
+ specify the port to use. If not set 1 will be used.
+- dev-caps-max-mr-size: The maximum size of MR.
+- dev-caps-max-qp: Maximum number of QPs.
+- dev-caps-max-cq: Maximum number of CQs.
+- dev-caps-max-mr: Maximum number of MRs.
+- dev-caps-max-pd: Maximum number of PDs.
+- dev-caps-max-ah: Maximum number of AHs.
+
+Notes:
+- The first 3 parameters are mandatory settings, the rest have their
+ defaults.
+- The last 8 parameters (the ones that prefixed by dev-caps) defines the top
+ limits but the final values is adjusted by the backend device limitations.
+- netdev can be extracted from ibdev's sysfs
+ (/sys/class/infiniband/<ibdev>/device/net/)
+
+
+3.6 Example
+===========
+Define bridge device with vmxnet3 network backend:
+<interface type='bridge'>
+ <mac address='56:b4:44:e9:62:dc'/>
+ <source bridge='bridge1'/>
+ <model type='vmxnet3'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0' multifunction='on'/>
+</interface>
+
+Define pvrdma device:
+<qemu:commandline>
+ <qemu:arg value='-object'/>
+ <qemu:arg value='memory-backend-ram,id=mb1,size=1G,share'/>
+ <qemu:arg value='-numa'/>
+ <qemu:arg value='node,memdev=mb1'/>
+ <qemu:arg value='-chardev'/>
+ <qemu:arg value='socket,path=/var/run/rdmacm-mux-rxe0-1,id=mads'/>
+ <qemu:arg value='-device'/>
+ <qemu:arg value='pvrdma,addr=10.1,ibdev=rxe0,netdev=bridge0,mad-chardev=mads'/>
+</qemu:commandline>
diff --git a/docs/specs/ivshmem-spec.txt b/docs/specs/ivshmem-spec.txt
index a1f5499796..042f7eae22 100644
--- a/docs/specs/ivshmem-spec.txt
+++ b/docs/specs/ivshmem-spec.txt
@@ -17,12 +17,16 @@ get interrupted by its peers.
There are two basic configurations:
-- Just shared memory: -device ivshmem-plain,memdev=HMB,...
+- Just shared memory:
+
+ -device ivshmem-plain,memdev=HMB,...
This uses host memory backend HMB. It should have option "share"
set.
-- Shared memory plus interrupts: -device ivshmem,chardev=CHR,vectors=N,...
+- Shared memory plus interrupts:
+
+ -device ivshmem-doorbell,chardev=CHR,vectors=N,...
An ivshmem server must already be running on the host. The device
connects to the server's UNIX domain socket via character device
diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
index 1af82bba86..5d8c26b1ad 100644
--- a/docs/specs/tpm.txt
+++ b/docs/specs/tpm.txt
@@ -34,6 +34,25 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 -
QEMU files related to TPM CRB interface:
- hw/tpm/tpm_crb.c
+= fw_cfg interface =
+
+The bios/firmware may read the "etc/tpm/config" fw_cfg entry for
+configuring the guest appropriately.
+
+The entry of 6 bytes has the following content, in little-endian:
+
+ #define TPM_VERSION_UNSPEC 0
+ #define TPM_VERSION_1_2 1
+ #define TPM_VERSION_2_0 2
+
+ #define TPM_PPI_VERSION_NONE 0
+ #define TPM_PPI_VERSION_1_30 1
+
+ struct FwCfgTPMConfig {
+ uint32_t tpmppi_address; /* PPI memory location */
+ uint8_t tpm_version; /* TPM version */
+ uint8_t tpmppi_version; /* PPI version */
+ };
= ACPI Interface =
@@ -57,6 +76,91 @@ URL:
https://trustedcomputinggroup.org/tcg-acpi-specification/
+== ACPI PPI Interface ==
+
+QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This
+interface requires ACPI and firmware support. The specification can be found at
+the following URL:
+
+https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/
+
+PPI enables a system administrator (root) to request a modification to the
+TPM upon reboot. The PPI specification defines the operation requests and the
+actions the firmware has to take. The system administrator passes the operation
+request number to the firmware through an ACPI interface which writes this
+number to a memory location that the firmware knows. Upon reboot, the firmware
+finds the number and sends commands to the the TPM. The firmware writes the TPM
+result code and the operation request number to a memory location that ACPI can
+read from and pass the result on to the administrator.
+
+The PPI specification defines a set of mandatory and optional operations for
+the firmware to implement. The ACPI interface also allows an administrator to
+list the supported operations. In QEMU the ACPI code is generated by QEMU, yet
+the firmware needs to implement support on a per-operations basis, and
+different firmwares may support a different subset. Therefore, QEMU introduces
+the virtual memory device for PPI where the firmware can indicate which
+operations it supports and ACPI can enable the ones that are supported and
+disable all others. This interface lies in main memory and has the following
+layout:
+
+ +----------+--------+--------+-------------------------------------------+
+ | Field | Length | Offset | Description |
+ +----------+--------+--------+-------------------------------------------+
+ | func | 0x100 | 0x000 | Firmware sets values for each supported |
+ | | | | operation. See defined values below. |
+ +----------+--------+--------+-------------------------------------------+
+ | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. |
+ | | | | Not supported. |
+ +----------+--------+--------+-------------------------------------------+
+ | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. |
+ | | | | Set by ACPI. Not supported. |
+ +----------+--------+--------+-------------------------------------------+
+ | pprp | 0x4 | 0x105 | Result of last executed operation. Set by |
+ | | | | firmware. See function index 5 for values.|
+ +----------+--------+--------+-------------------------------------------+
+ | pprq | 0x4 | 0x109 | Operation request number to execute. See |
+ | | | | 'Physical Presence Interface Operation |
+ | | | | Summary' tables in specs. Set by ACPI. |
+ +----------+--------+--------+-------------------------------------------+
+ | pprm | 0x4 | 0x10d | Operation request optional parameter. |
+ | | | | Values depend on operation. Set by ACPI. |
+ +----------+--------+--------+-------------------------------------------+
+ | lppr | 0x4 | 0x111 | Last executed operation request number. |
+ | | | | Copied from pprq field by firmware. |
+ +----------+--------+--------+-------------------------------------------+
+ | fret | 0x4 | 0x115 | Result code from SMM function. |
+ | | | | Not supported. |
+ +----------+--------+--------+-------------------------------------------+
+ | res1 | 0x40 | 0x119 | Reserved for future use |
+ +----------+--------+--------+-------------------------------------------+
+ | next_step| 0x1 | 0x159 | Operation to execute after reboot by |
+ | | | | firmware. Used by firmware. |
+ +----------+--------+--------+-------------------------------------------+
+ | movv | 0x1 | 0x15a | Memory overwrite variable |
+ +----------+--------+--------+-------------------------------------------+
+
+ The following values are supported for the 'func' field. They correspond
+ to the values used by ACPI function index 8.
+
+ +----------+-------------------------------------------------------------+
+ | value | Description |
+ +----------+-------------------------------------------------------------+
+ | 0 | Operation is not implemented. |
+ +----------+-------------------------------------------------------------+
+ | 1 | Operation is only accessible through firmware. |
+ +----------+-------------------------------------------------------------+
+ | 2 | Operation is blocked for OS by firmware configuration. |
+ +----------+-------------------------------------------------------------+
+ | 3 | Operation is allowed and physically present user required. |
+ +----------+-------------------------------------------------------------+
+ | 4 | Operation is allowed and physically present user is not |
+ | | required. |
+ +----------+-------------------------------------------------------------+
+
+The location of the table is given by the fw_cfg tpmppi_address field.
+The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave
+enough room for future updates.
+
QEMU files related to TPM ACPI tables:
- hw/i386/acpi-build.c
diff --git a/dump.c b/dump.c
index 4ec94c5e25..ef1d8025c9 100644
--- a/dump.c
+++ b/dump.c
@@ -1557,7 +1557,7 @@ static void get_max_mapnr(DumpState *s)
{
GuestPhysBlock *last_block;
- last_block = QTAILQ_LAST(&s->guest_phys_blocks.head, GuestPhysBlockHead);
+ last_block = QTAILQ_LAST(&s->guest_phys_blocks.head);
s->max_mapnr = dump_paddr_to_pfn(s, last_block->target_end);
}
diff --git a/exec.c b/exec.c
index bb6170dbff..895449f926 100644
--- a/exec.c
+++ b/exec.c
@@ -94,7 +94,8 @@ int target_page_bits;
bool target_page_bits_decided;
#endif
-struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
+CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
+
/* current CPU in the current thread. It is only valid inside
cpu_exec() */
__thread CPUState *current_cpu;
@@ -3388,8 +3389,12 @@ enum write_rom_type {
FLUSH_CACHE,
};
-static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
- hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
+static inline MemTxResult address_space_write_rom_internal(AddressSpace *as,
+ hwaddr addr,
+ MemTxAttrs attrs,
+ const uint8_t *buf,
+ int len,
+ enum write_rom_type type)
{
hwaddr l;
uint8_t *ptr;
@@ -3399,8 +3404,7 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
rcu_read_lock();
while (len > 0) {
l = len;
- mr = address_space_translate(as, addr, &addr1, &l, true,
- MEMTXATTRS_UNSPECIFIED);
+ mr = address_space_translate(as, addr, &addr1, &l, true, attrs);
if (!(memory_region_is_ram(mr) ||
memory_region_is_romd(mr))) {
@@ -3423,13 +3427,16 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
addr += l;
}
rcu_read_unlock();
+ return MEMTX_OK;
}
/* used for ROM loading : can write in RAM and ROM */
-void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
- const uint8_t *buf, int len)
+MemTxResult address_space_write_rom(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs,
+ const uint8_t *buf, int len)
{
- cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
+ return address_space_write_rom_internal(as, addr, attrs,
+ buf, len, WRITE_DATA);
}
void cpu_flush_icache_range(hwaddr start, int len)
@@ -3444,8 +3451,9 @@ void cpu_flush_icache_range(hwaddr start, int len)
return;
}
- cpu_physical_memory_write_rom_internal(&address_space_memory,
- start, NULL, len, FLUSH_CACHE);
+ address_space_write_rom_internal(&address_space_memory,
+ start, MEMTXATTRS_UNSPECIFIED,
+ NULL, len, FLUSH_CACHE);
}
typedef struct {
@@ -3464,7 +3472,7 @@ typedef struct MapClient {
} MapClient;
QemuMutex map_client_list_lock;
-static QLIST_HEAD(map_client_list, MapClient) map_client_list
+static QLIST_HEAD(, MapClient) map_client_list
= QLIST_HEAD_INITIALIZER(map_client_list);
static void cpu_unregister_map_client_do(MapClient *client)
@@ -3873,8 +3881,9 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
l = len;
phys_addr += (addr & ~TARGET_PAGE_MASK);
if (is_write) {
- cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
- phys_addr, buf, l);
+ address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ buf, l);
} else {
address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
MEMTXATTRS_UNSPECIFIED,
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index e1eef954e6..59eac97d10 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -83,6 +83,7 @@ this code that are retained.
* target-dependent and needs the TARGET_* macros.
*/
#include "qemu/osdep.h"
+#include <math.h>
#include "qemu/bitops.h"
#include "fpu/softfloat.h"
@@ -95,6 +96,324 @@ this code that are retained.
*----------------------------------------------------------------------------*/
#include "fpu/softfloat-macros.h"
+/*
+ * Hardfloat
+ *
+ * Fast emulation of guest FP instructions is challenging for two reasons.
+ * First, FP instruction semantics are similar but not identical, particularly
+ * when handling NaNs. Second, emulating at reasonable speed the guest FP
+ * exception flags is not trivial: reading the host's flags register with a
+ * feclearexcept & fetestexcept pair is slow [slightly slower than soft-fp],
+ * and trapping on every FP exception is not fast nor pleasant to work with.
+ *
+ * We address these challenges by leveraging the host FPU for a subset of the
+ * operations. To do this we expand on the idea presented in this paper:
+ *
+ * Guo, Yu-Chuan, et al. "Translating the ARM Neon and VFP instructions in a
+ * binary translator." Software: Practice and Experience 46.12 (2016):1591-1615.
+ *
+ * The idea is thus to leverage the host FPU to (1) compute FP operations
+ * and (2) identify whether FP exceptions occurred while avoiding
+ * expensive exception flag register accesses.
+ *
+ * An important optimization shown in the paper is that given that exception
+ * flags are rarely cleared by the guest, we can avoid recomputing some flags.
+ * This is particularly useful for the inexact flag, which is very frequently
+ * raised in floating-point workloads.
+ *
+ * We optimize the code further by deferring to soft-fp whenever FP exception
+ * detection might get hairy. Two examples: (1) when at least one operand is
+ * denormal/inf/NaN; (2) when operands are not guaranteed to lead to a 0 result
+ * and the result is < the minimum normal.
+ */
+#define GEN_INPUT_FLUSH__NOCHECK(name, soft_t) \
+ static inline void name(soft_t *a, float_status *s) \
+ { \
+ if (unlikely(soft_t ## _is_denormal(*a))) { \
+ *a = soft_t ## _set_sign(soft_t ## _zero, \
+ soft_t ## _is_neg(*a)); \
+ s->float_exception_flags |= float_flag_input_denormal; \
+ } \
+ }
+
+GEN_INPUT_FLUSH__NOCHECK(float32_input_flush__nocheck, float32)
+GEN_INPUT_FLUSH__NOCHECK(float64_input_flush__nocheck, float64)
+#undef GEN_INPUT_FLUSH__NOCHECK
+
+#define GEN_INPUT_FLUSH1(name, soft_t) \
+ static inline void name(soft_t *a, float_status *s) \
+ { \
+ if (likely(!s->flush_inputs_to_zero)) { \
+ return; \
+ } \
+ soft_t ## _input_flush__nocheck(a, s); \
+ }
+
+GEN_INPUT_FLUSH1(float32_input_flush1, float32)
+GEN_INPUT_FLUSH1(float64_input_flush1, float64)
+#undef GEN_INPUT_FLUSH1
+
+#define GEN_INPUT_FLUSH2(name, soft_t) \
+ static inline void name(soft_t *a, soft_t *b, float_status *s) \
+ { \
+ if (likely(!s->flush_inputs_to_zero)) { \
+ return; \
+ } \
+ soft_t ## _input_flush__nocheck(a, s); \
+ soft_t ## _input_flush__nocheck(b, s); \
+ }
+
+GEN_INPUT_FLUSH2(float32_input_flush2, float32)
+GEN_INPUT_FLUSH2(float64_input_flush2, float64)
+#undef GEN_INPUT_FLUSH2
+
+#define GEN_INPUT_FLUSH3(name, soft_t) \
+ static inline void name(soft_t *a, soft_t *b, soft_t *c, float_status *s) \
+ { \
+ if (likely(!s->flush_inputs_to_zero)) { \
+ return; \
+ } \
+ soft_t ## _input_flush__nocheck(a, s); \
+ soft_t ## _input_flush__nocheck(b, s); \
+ soft_t ## _input_flush__nocheck(c, s); \
+ }
+
+GEN_INPUT_FLUSH3(float32_input_flush3, float32)
+GEN_INPUT_FLUSH3(float64_input_flush3, float64)
+#undef GEN_INPUT_FLUSH3
+
+/*
+ * Choose whether to use fpclassify or float32/64_* primitives in the generated
+ * hardfloat functions. Each combination of number of inputs and float size
+ * gets its own value.
+ */
+#if defined(__x86_64__)
+# define QEMU_HARDFLOAT_1F32_USE_FP 0
+# define QEMU_HARDFLOAT_1F64_USE_FP 1
+# define QEMU_HARDFLOAT_2F32_USE_FP 0
+# define QEMU_HARDFLOAT_2F64_USE_FP 1
+# define QEMU_HARDFLOAT_3F32_USE_FP 0
+# define QEMU_HARDFLOAT_3F64_USE_FP 1
+#else
+# define QEMU_HARDFLOAT_1F32_USE_FP 0
+# define QEMU_HARDFLOAT_1F64_USE_FP 0
+# define QEMU_HARDFLOAT_2F32_USE_FP 0
+# define QEMU_HARDFLOAT_2F64_USE_FP 0
+# define QEMU_HARDFLOAT_3F32_USE_FP 0
+# define QEMU_HARDFLOAT_3F64_USE_FP 0
+#endif
+
+/*
+ * QEMU_HARDFLOAT_USE_ISINF chooses whether to use isinf() over
+ * float{32,64}_is_infinity when !USE_FP.
+ * On x86_64/aarch64, using the former over the latter can yield a ~6% speedup.
+ * On power64 however, using isinf() reduces fp-bench performance by up to 50%.
+ */
+#if defined(__x86_64__) || defined(__aarch64__)
+# define QEMU_HARDFLOAT_USE_ISINF 1
+#else
+# define QEMU_HARDFLOAT_USE_ISINF 0
+#endif
+
+/*
+ * Some targets clear the FP flags before most FP operations. This prevents
+ * the use of hardfloat, since hardfloat relies on the inexact flag being
+ * already set.
+ */
+#if defined(TARGET_PPC) || defined(__FAST_MATH__)
+# if defined(__FAST_MATH__)
+# warning disabling hardfloat due to -ffast-math: hardfloat requires an exact \
+ IEEE implementation
+# endif
+# define QEMU_NO_HARDFLOAT 1
+# define QEMU_SOFTFLOAT_ATTR QEMU_FLATTEN
+#else
+# define QEMU_NO_HARDFLOAT 0
+# define QEMU_SOFTFLOAT_ATTR QEMU_FLATTEN __attribute__((noinline))
+#endif
+
+static inline bool can_use_fpu(const float_status *s)
+{
+ if (QEMU_NO_HARDFLOAT) {
+ return false;
+ }
+ return likely(s->float_exception_flags & float_flag_inexact &&
+ s->float_rounding_mode == float_round_nearest_even);
+}
+
+/*
+ * Hardfloat generation functions. Each operation can have two flavors:
+ * either using softfloat primitives (e.g. float32_is_zero_or_normal) for
+ * most condition checks, or native ones (e.g. fpclassify).
+ *
+ * The flavor is chosen by the callers. Instead of using macros, we rely on the
+ * compiler to propagate constants and inline everything into the callers.
+ *
+ * We only generate functions for operations with two inputs, since only
+ * these are common enough to justify consolidating them into common code.
+ */
+
+typedef union {
+ float32 s;
+ float h;
+} union_float32;
+
+typedef union {
+ float64 s;
+ double h;
+} union_float64;
+
+typedef bool (*f32_check_fn)(union_float32 a, union_float32 b);
+typedef bool (*f64_check_fn)(union_float64 a, union_float64 b);
+
+typedef float32 (*soft_f32_op2_fn)(float32 a, float32 b, float_status *s);
+typedef float64 (*soft_f64_op2_fn)(float64 a, float64 b, float_status *s);
+typedef float (*hard_f32_op2_fn)(float a, float b);
+typedef double (*hard_f64_op2_fn)(double a, double b);
+
+/* 2-input is-zero-or-normal */
+static inline bool f32_is_zon2(union_float32 a, union_float32 b)
+{
+ if (QEMU_HARDFLOAT_2F32_USE_FP) {
+ /*
+ * Not using a temp variable for consecutive fpclassify calls ends up
+ * generating faster code.
+ */
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ (fpclassify(b.h) == FP_NORMAL || fpclassify(b.h) == FP_ZERO);
+ }
+ return float32_is_zero_or_normal(a.s) &&
+ float32_is_zero_or_normal(b.s);
+}
+
+static inline bool f64_is_zon2(union_float64 a, union_float64 b)
+{
+ if (QEMU_HARDFLOAT_2F64_USE_FP) {
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ (fpclassify(b.h) == FP_NORMAL || fpclassify(b.h) == FP_ZERO);
+ }
+ return float64_is_zero_or_normal(a.s) &&
+ float64_is_zero_or_normal(b.s);
+}
+
+/* 3-input is-zero-or-normal */
+static inline
+bool f32_is_zon3(union_float32 a, union_float32 b, union_float32 c)
+{
+ if (QEMU_HARDFLOAT_3F32_USE_FP) {
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ (fpclassify(b.h) == FP_NORMAL || fpclassify(b.h) == FP_ZERO) &&
+ (fpclassify(c.h) == FP_NORMAL || fpclassify(c.h) == FP_ZERO);
+ }
+ return float32_is_zero_or_normal(a.s) &&
+ float32_is_zero_or_normal(b.s) &&
+ float32_is_zero_or_normal(c.s);
+}
+
+static inline
+bool f64_is_zon3(union_float64 a, union_float64 b, union_float64 c)
+{
+ if (QEMU_HARDFLOAT_3F64_USE_FP) {
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ (fpclassify(b.h) == FP_NORMAL || fpclassify(b.h) == FP_ZERO) &&
+ (fpclassify(c.h) == FP_NORMAL || fpclassify(c.h) == FP_ZERO);
+ }
+ return float64_is_zero_or_normal(a.s) &&
+ float64_is_zero_or_normal(b.s) &&
+ float64_is_zero_or_normal(c.s);
+}
+
+static inline bool f32_is_inf(union_float32 a)
+{
+ if (QEMU_HARDFLOAT_USE_ISINF) {
+ return isinf(a.h);
+ }
+ return float32_is_infinity(a.s);
+}
+
+static inline bool f64_is_inf(union_float64 a)
+{
+ if (QEMU_HARDFLOAT_USE_ISINF) {
+ return isinf(a.h);
+ }
+ return float64_is_infinity(a.s);
+}
+
+/* Note: @fast_test and @post can be NULL */
+static inline float32
+float32_gen2(float32 xa, float32 xb, float_status *s,
+ hard_f32_op2_fn hard, soft_f32_op2_fn soft,
+ f32_check_fn pre, f32_check_fn post,
+ f32_check_fn fast_test, soft_f32_op2_fn fast_op)
+{
+ union_float32 ua, ub, ur;
+
+ ua.s = xa;
+ ub.s = xb;
+
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+
+ float32_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(!pre(ua, ub))) {
+ goto soft;
+ }
+ if (fast_test && fast_test(ua, ub)) {
+ return fast_op(ua.s, ub.s, s);
+ }
+
+ ur.h = hard(ua.h, ub.h);
+ if (unlikely(f32_is_inf(ur))) {
+ s->float_exception_flags |= float_flag_overflow;
+ } else if (unlikely(fabsf(ur.h) <= FLT_MIN)) {
+ if (post == NULL || post(ua, ub)) {
+ goto soft;
+ }
+ }
+ return ur.s;
+
+ soft:
+ return soft(ua.s, ub.s, s);
+}
+
+static inline float64
+float64_gen2(float64 xa, float64 xb, float_status *s,
+ hard_f64_op2_fn hard, soft_f64_op2_fn soft,
+ f64_check_fn pre, f64_check_fn post,
+ f64_check_fn fast_test, soft_f64_op2_fn fast_op)
+{
+ union_float64 ua, ub, ur;
+
+ ua.s = xa;
+ ub.s = xb;
+
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+
+ float64_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(!pre(ua, ub))) {
+ goto soft;
+ }
+ if (fast_test && fast_test(ua, ub)) {
+ return fast_op(ua.s, ub.s, s);
+ }
+
+ ur.h = hard(ua.h, ub.h);
+ if (unlikely(f64_is_inf(ur))) {
+ s->float_exception_flags |= float_flag_overflow;
+ } else if (unlikely(fabs(ur.h) <= DBL_MIN)) {
+ if (post == NULL || post(ua, ub)) {
+ goto soft;
+ }
+ }
+ return ur.s;
+
+ soft:
+ return soft(ua.s, ub.s, s);
+}
+
/*----------------------------------------------------------------------------
| Returns the fraction bits of the half-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
@@ -336,8 +655,8 @@ static inline float64 float64_pack_raw(FloatParts p)
#include "softfloat-specialize.h"
/* Canonicalize EXP and FRAC, setting CLS. */
-static FloatParts canonicalize(FloatParts part, const FloatFmt *parm,
- float_status *status)
+static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
+ float_status *status)
{
if (part.exp == parm->exp_max && !parm->arm_althp) {
if (part.frac == 0) {
@@ -513,7 +832,7 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
static FloatParts float16a_unpack_canonical(float16 f, float_status *s,
const FloatFmt *params)
{
- return canonicalize(float16_unpack_raw(f), params, s);
+ return sf_canonicalize(float16_unpack_raw(f), params, s);
}
static FloatParts float16_unpack_canonical(float16 f, float_status *s)
@@ -534,7 +853,7 @@ static float16 float16_round_pack_canonical(FloatParts p, float_status *s)
static FloatParts float32_unpack_canonical(float32 f, float_status *s)
{
- return canonicalize(float32_unpack_raw(f), &float32_params, s);
+ return sf_canonicalize(float32_unpack_raw(f), &float32_params, s);
}
static float32 float32_round_pack_canonical(FloatParts p, float_status *s)
@@ -544,7 +863,7 @@ static float32 float32_round_pack_canonical(FloatParts p, float_status *s)
static FloatParts float64_unpack_canonical(float64 f, float_status *s)
{
- return canonicalize(float64_unpack_raw(f), &float64_params, s);
+ return sf_canonicalize(float64_unpack_raw(f), &float64_params, s);
}
static float64 float64_round_pack_canonical(FloatParts p, float_status *s)
@@ -735,49 +1054,128 @@ float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status)
return float16_round_pack_canonical(pr, status);
}
-float32 QEMU_FLATTEN float32_add(float32 a, float32 b, float_status *status)
+float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status)
+{
+ FloatParts pa = float16_unpack_canonical(a, status);
+ FloatParts pb = float16_unpack_canonical(b, status);
+ FloatParts pr = addsub_floats(pa, pb, true, status);
+
+ return float16_round_pack_canonical(pr, status);
+}
+
+static float32 QEMU_SOFTFLOAT_ATTR
+soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status)
{
FloatParts pa = float32_unpack_canonical(a, status);
FloatParts pb = float32_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, false, status);
+ FloatParts pr = addsub_floats(pa, pb, subtract, status);
return float32_round_pack_canonical(pr, status);
}
-float64 QEMU_FLATTEN float64_add(float64 a, float64 b, float_status *status)
+static inline float32 soft_f32_add(float32 a, float32 b, float_status *status)
+{
+ return soft_f32_addsub(a, b, false, status);
+}
+
+static inline float32 soft_f32_sub(float32 a, float32 b, float_status *status)
+{
+ return soft_f32_addsub(a, b, true, status);
+}
+
+static float64 QEMU_SOFTFLOAT_ATTR
+soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status)
{
FloatParts pa = float64_unpack_canonical(a, status);
FloatParts pb = float64_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, false, status);
+ FloatParts pr = addsub_floats(pa, pb, subtract, status);
return float64_round_pack_canonical(pr, status);
}
-float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status)
+static inline float64 soft_f64_add(float64 a, float64 b, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, true, status);
+ return soft_f64_addsub(a, b, false, status);
+}
- return float16_round_pack_canonical(pr, status);
+static inline float64 soft_f64_sub(float64 a, float64 b, float_status *status)
+{
+ return soft_f64_addsub(a, b, true, status);
}
-float32 QEMU_FLATTEN float32_sub(float32 a, float32 b, float_status *status)
+static float hard_f32_add(float a, float b)
{
- FloatParts pa = float32_unpack_canonical(a, status);
- FloatParts pb = float32_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, true, status);
+ return a + b;
+}
- return float32_round_pack_canonical(pr, status);
+static float hard_f32_sub(float a, float b)
+{
+ return a - b;
}
-float64 QEMU_FLATTEN float64_sub(float64 a, float64 b, float_status *status)
+static double hard_f64_add(double a, double b)
{
- FloatParts pa = float64_unpack_canonical(a, status);
- FloatParts pb = float64_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, true, status);
+ return a + b;
+}
- return float64_round_pack_canonical(pr, status);
+static double hard_f64_sub(double a, double b)
+{
+ return a - b;
+}
+
+static bool f32_addsub_post(union_float32 a, union_float32 b)
+{
+ if (QEMU_HARDFLOAT_2F32_USE_FP) {
+ return !(fpclassify(a.h) == FP_ZERO && fpclassify(b.h) == FP_ZERO);
+ }
+ return !(float32_is_zero(a.s) && float32_is_zero(b.s));
+}
+
+static bool f64_addsub_post(union_float64 a, union_float64 b)
+{
+ if (QEMU_HARDFLOAT_2F64_USE_FP) {
+ return !(fpclassify(a.h) == FP_ZERO && fpclassify(b.h) == FP_ZERO);
+ } else {
+ return !(float64_is_zero(a.s) && float64_is_zero(b.s));
+ }
+}
+
+static float32 float32_addsub(float32 a, float32 b, float_status *s,
+ hard_f32_op2_fn hard, soft_f32_op2_fn soft)
+{
+ return float32_gen2(a, b, s, hard, soft,
+ f32_is_zon2, f32_addsub_post, NULL, NULL);
+}
+
+static float64 float64_addsub(float64 a, float64 b, float_status *s,
+ hard_f64_op2_fn hard, soft_f64_op2_fn soft)
+{
+ return float64_gen2(a, b, s, hard, soft,
+ f64_is_zon2, f64_addsub_post, NULL, NULL);
+}
+
+float32 QEMU_FLATTEN
+float32_add(float32 a, float32 b, float_status *s)
+{
+ return float32_addsub(a, b, s, hard_f32_add, soft_f32_add);
+}
+
+float32 QEMU_FLATTEN
+float32_sub(float32 a, float32 b, float_status *s)
+{
+ return float32_addsub(a, b, s, hard_f32_sub, soft_f32_sub);
+}
+
+float64 QEMU_FLATTEN
+float64_add(float64 a, float64 b, float_status *s)
+{
+ return float64_addsub(a, b, s, hard_f64_add, soft_f64_add);
+}
+
+float64 QEMU_FLATTEN
+float64_sub(float64 a, float64 b, float_status *s)
+{
+ return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub);
}
/*
@@ -838,7 +1236,8 @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status)
return float16_round_pack_canonical(pr, status);
}
-float32 QEMU_FLATTEN float32_mul(float32 a, float32 b, float_status *status)
+static float32 QEMU_SOFTFLOAT_ATTR
+soft_f32_mul(float32 a, float32 b, float_status *status)
{
FloatParts pa = float32_unpack_canonical(a, status);
FloatParts pb = float32_unpack_canonical(b, status);
@@ -847,7 +1246,8 @@ float32 QEMU_FLATTEN float32_mul(float32 a, float32 b, float_status *status)
return float32_round_pack_canonical(pr, status);
}
-float64 QEMU_FLATTEN float64_mul(float64 a, float64 b, float_status *status)
+static float64 QEMU_SOFTFLOAT_ATTR
+soft_f64_mul(float64 a, float64 b, float_status *status)
{
FloatParts pa = float64_unpack_canonical(a, status);
FloatParts pb = float64_unpack_canonical(b, status);
@@ -856,6 +1256,54 @@ float64 QEMU_FLATTEN float64_mul(float64 a, float64 b, float_status *status)
return float64_round_pack_canonical(pr, status);
}
+static float hard_f32_mul(float a, float b)
+{
+ return a * b;
+}
+
+static double hard_f64_mul(double a, double b)
+{
+ return a * b;
+}
+
+static bool f32_mul_fast_test(union_float32 a, union_float32 b)
+{
+ return float32_is_zero(a.s) || float32_is_zero(b.s);
+}
+
+static bool f64_mul_fast_test(union_float64 a, union_float64 b)
+{
+ return float64_is_zero(a.s) || float64_is_zero(b.s);
+}
+
+static float32 f32_mul_fast_op(float32 a, float32 b, float_status *s)
+{
+ bool signbit = float32_is_neg(a) ^ float32_is_neg(b);
+
+ return float32_set_sign(float32_zero, signbit);
+}
+
+static float64 f64_mul_fast_op(float64 a, float64 b, float_status *s)
+{
+ bool signbit = float64_is_neg(a) ^ float64_is_neg(b);
+
+ return float64_set_sign(float64_zero, signbit);
+}
+
+float32 QEMU_FLATTEN
+float32_mul(float32 a, float32 b, float_status *s)
+{
+ return float32_gen2(a, b, s, hard_f32_mul, soft_f32_mul,
+ f32_is_zon2, NULL, f32_mul_fast_test, f32_mul_fast_op);
+}
+
+float64 QEMU_FLATTEN
+float64_mul(float64 a, float64 b, float_status *s)
+{
+ return float64_gen2(a, b, s, hard_f64_mul, soft_f64_mul,
+ f64_is_zon2, NULL, f64_mul_fast_test, f64_mul_fast_op);
+}
+
/*
* Returns the result of multiplying the floating-point values `a' and
* `b' then adding 'c', with no intermediate rounding step after the
@@ -1070,8 +1518,9 @@ float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c,
return float16_round_pack_canonical(pr, status);
}
-float32 QEMU_FLATTEN float32_muladd(float32 a, float32 b, float32 c,
- int flags, float_status *status)
+static float32 QEMU_SOFTFLOAT_ATTR
+soft_f32_muladd(float32 a, float32 b, float32 c, int flags,
+ float_status *status)
{
FloatParts pa = float32_unpack_canonical(a, status);
FloatParts pb = float32_unpack_canonical(b, status);
@@ -1081,8 +1530,9 @@ float32 QEMU_FLATTEN float32_muladd(float32 a, float32 b, float32 c,
return float32_round_pack_canonical(pr, status);
}
-float64 QEMU_FLATTEN float64_muladd(float64 a, float64 b, float64 c,
- int flags, float_status *status)
+static float64 QEMU_SOFTFLOAT_ATTR
+soft_f64_muladd(float64 a, float64 b, float64 c, int flags,
+ float_status *status)
{
FloatParts pa = float64_unpack_canonical(a, status);
FloatParts pb = float64_unpack_canonical(b, status);
@@ -1092,6 +1542,128 @@ float64 QEMU_FLATTEN float64_muladd(float64 a, float64 b, float64 c,
return float64_round_pack_canonical(pr, status);
}
+float32 QEMU_FLATTEN
+float32_muladd(float32 xa, float32 xb, float32 xc, int flags, float_status *s)
+{
+ union_float32 ua, ub, uc, ur;
+
+ ua.s = xa;
+ ub.s = xb;
+ uc.s = xc;
+
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+ if (unlikely(flags & float_muladd_halve_result)) {
+ goto soft;
+ }
+
+ float32_input_flush3(&ua.s, &ub.s, &uc.s, s);
+ if (unlikely(!f32_is_zon3(ua, ub, uc))) {
+ goto soft;
+ }
+ /*
+ * When (a || b) == 0, there's no need to check for under/over flow,
+ * since we know the addend is (normal || 0) and the product is 0.
+ */
+ if (float32_is_zero(ua.s) || float32_is_zero(ub.s)) {
+ union_float32 up;
+ bool prod_sign;
+
+ prod_sign = float32_is_neg(ua.s) ^ float32_is_neg(ub.s);
+ prod_sign ^= !!(flags & float_muladd_negate_product);
+ up.s = float32_set_sign(float32_zero, prod_sign);
+
+ if (flags & float_muladd_negate_c) {
+ uc.h = -uc.h;
+ }
+ ur.h = up.h + uc.h;
+ } else {
+ if (flags & float_muladd_negate_product) {
+ ua.h = -ua.h;
+ }
+ if (flags & float_muladd_negate_c) {
+ uc.h = -uc.h;
+ }
+
+ ur.h = fmaf(ua.h, ub.h, uc.h);
+
+ if (unlikely(f32_is_inf(ur))) {
+ s->float_exception_flags |= float_flag_overflow;
+ } else if (unlikely(fabsf(ur.h) <= FLT_MIN)) {
+ goto soft;
+ }
+ }
+ if (flags & float_muladd_negate_result) {
+ return float32_chs(ur.s);
+ }
+ return ur.s;
+
+ soft:
+ return soft_f32_muladd(ua.s, ub.s, uc.s, flags, s);
+}
+
+float64 QEMU_FLATTEN
+float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
+{
+ union_float64 ua, ub, uc, ur;
+
+ ua.s = xa;
+ ub.s = xb;
+ uc.s = xc;
+
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+ if (unlikely(flags & float_muladd_halve_result)) {
+ goto soft;
+ }
+
+ float64_input_flush3(&ua.s, &ub.s, &uc.s, s);
+ if (unlikely(!f64_is_zon3(ua, ub, uc))) {
+ goto soft;
+ }
+ /*
+ * When (a || b) == 0, there's no need to check for under/over flow,
+ * since we know the addend is (normal || 0) and the product is 0.
+ */
+ if (float64_is_zero(ua.s) || float64_is_zero(ub.s)) {
+ union_float64 up;
+ bool prod_sign;
+
+ prod_sign = float64_is_neg(ua.s) ^ float64_is_neg(ub.s);
+ prod_sign ^= !!(flags & float_muladd_negate_product);
+ up.s = float64_set_sign(float64_zero, prod_sign);
+
+ if (flags & float_muladd_negate_c) {
+ uc.h = -uc.h;
+ }
+ ur.h = up.h + uc.h;
+ } else {
+ if (flags & float_muladd_negate_product) {
+ ua.h = -ua.h;
+ }
+ if (flags & float_muladd_negate_c) {
+ uc.h = -uc.h;
+ }
+
+ ur.h = fma(ua.h, ub.h, uc.h);
+
+ if (unlikely(f64_is_inf(ur))) {
+ s->float_exception_flags |= float_flag_overflow;
+ } else if (unlikely(fabs(ur.h) <= FLT_MIN)) {
+ goto soft;
+ }
+ }
+ if (flags & float_muladd_negate_result) {
+ return float64_chs(ur.s);
+ }
+ return ur.s;
+
+ soft:
+ return soft_f64_muladd(ua.s, ub.s, uc.s, flags, s);
+}
+
/*
* Returns the result of dividing the floating-point value `a' by the
* corresponding value `b'. The operation is performed according to
@@ -1180,7 +1752,8 @@ float16 float16_div(float16 a, float16 b, float_status *status)
return float16_round_pack_canonical(pr, status);
}
-float32 float32_div(float32 a, float32 b, float_status *status)
+static float32 QEMU_SOFTFLOAT_ATTR
+soft_f32_div(float32 a, float32 b, float_status *status)
{
FloatParts pa = float32_unpack_canonical(a, status);
FloatParts pb = float32_unpack_canonical(b, status);
@@ -1189,7 +1762,8 @@ float32 float32_div(float32 a, float32 b, float_status *status)
return float32_round_pack_canonical(pr, status);
}
-float64 float64_div(float64 a, float64 b, float_status *status)
+static float64 QEMU_SOFTFLOAT_ATTR
+soft_f64_div(float64 a, float64 b, float_status *status)
{
FloatParts pa = float64_unpack_canonical(a, status);
FloatParts pb = float64_unpack_canonical(b, status);
@@ -1198,6 +1772,64 @@ float64 float64_div(float64 a, float64 b, float_status *status)
return float64_round_pack_canonical(pr, status);
}
+static float hard_f32_div(float a, float b)
+{
+ return a / b;
+}
+
+static double hard_f64_div(double a, double b)
+{
+ return a / b;
+}
+
+static bool f32_div_pre(union_float32 a, union_float32 b)
+{
+ if (QEMU_HARDFLOAT_2F32_USE_FP) {
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ fpclassify(b.h) == FP_NORMAL;
+ }
+ return float32_is_zero_or_normal(a.s) && float32_is_normal(b.s);
+}
+
+static bool f64_div_pre(union_float64 a, union_float64 b)
+{
+ if (QEMU_HARDFLOAT_2F64_USE_FP) {
+ return (fpclassify(a.h) == FP_NORMAL || fpclassify(a.h) == FP_ZERO) &&
+ fpclassify(b.h) == FP_NORMAL;
+ }
+ return float64_is_zero_or_normal(a.s) && float64_is_normal(b.s);
+}
+
+static bool f32_div_post(union_float32 a, union_float32 b)
+{
+ if (QEMU_HARDFLOAT_2F32_USE_FP) {
+ return fpclassify(a.h) != FP_ZERO;
+ }
+ return !float32_is_zero(a.s);
+}
+
+static bool f64_div_post(union_float64 a, union_float64 b)
+{
+ if (QEMU_HARDFLOAT_2F64_USE_FP) {
+ return fpclassify(a.h) != FP_ZERO;
+ }
+ return !float64_is_zero(a.s);
+}
+
+float32 QEMU_FLATTEN
+float32_div(float32 a, float32 b, float_status *s)
+{
+ return float32_gen2(a, b, s, hard_f32_div, soft_f32_div,
+ f32_div_pre, f32_div_post, NULL, NULL);
+}
+
+float64 QEMU_FLATTEN
+float64_div(float64 a, float64 b, float_status *s)
+{
+ return float64_gen2(a, b, s, hard_f64_div, soft_f64_div,
+ f64_div_pre, f64_div_post, NULL, NULL);
+}
+
/*
* Float to Float conversions
*
@@ -2271,28 +2903,109 @@ static int compare_floats(FloatParts a, FloatParts b, bool is_quiet,
}
}
-#define COMPARE(sz) \
-int float ## sz ## _compare(float ## sz a, float ## sz b, \
- float_status *s) \
+#define COMPARE(name, attr, sz) \
+static int attr \
+name(float ## sz a, float ## sz b, bool is_quiet, float_status *s) \
{ \
FloatParts pa = float ## sz ## _unpack_canonical(a, s); \
FloatParts pb = float ## sz ## _unpack_canonical(b, s); \
- return compare_floats(pa, pb, false, s); \
-} \
-int float ## sz ## _compare_quiet(float ## sz a, float ## sz b, \
- float_status *s) \
-{ \
- FloatParts pa = float ## sz ## _unpack_canonical(a, s); \
- FloatParts pb = float ## sz ## _unpack_canonical(b, s); \
- return compare_floats(pa, pb, true, s); \
+ return compare_floats(pa, pb, is_quiet, s); \
}
-COMPARE(16)
-COMPARE(32)
-COMPARE(64)
+COMPARE(soft_f16_compare, QEMU_FLATTEN, 16)
+COMPARE(soft_f32_compare, QEMU_SOFTFLOAT_ATTR, 32)
+COMPARE(soft_f64_compare, QEMU_SOFTFLOAT_ATTR, 64)
#undef COMPARE
+int float16_compare(float16 a, float16 b, float_status *s)
+{
+ return soft_f16_compare(a, b, false, s);
+}
+
+int float16_compare_quiet(float16 a, float16 b, float_status *s)
+{
+ return soft_f16_compare(a, b, true, s);
+}
+
+static int QEMU_FLATTEN
+f32_compare(float32 xa, float32 xb, bool is_quiet, float_status *s)
+{
+ union_float32 ua, ub;
+
+ ua.s = xa;
+ ub.s = xb;
+
+ if (QEMU_NO_HARDFLOAT) {
+ goto soft;
+ }
+
+ float32_input_flush2(&ua.s, &ub.s, s);
+ if (isgreaterequal(ua.h, ub.h)) {
+ if (isgreater(ua.h, ub.h)) {
+ return float_relation_greater;
+ }
+ return float_relation_equal;
+ }
+ if (likely(isless(ua.h, ub.h))) {
+ return float_relation_less;
+ }
+ /* The only condition remaining is unordered.
+ * Fall through to set flags.
+ */
+ soft:
+ return soft_f32_compare(ua.s, ub.s, is_quiet, s);
+}
+
+int float32_compare(float32 a, float32 b, float_status *s)
+{
+ return f32_compare(a, b, false, s);
+}
+
+int float32_compare_quiet(float32 a, float32 b, float_status *s)
+{
+ return f32_compare(a, b, true, s);
+}
+
+static int QEMU_FLATTEN
+f64_compare(float64 xa, float64 xb, bool is_quiet, float_status *s)
+{
+ union_float64 ua, ub;
+
+ ua.s = xa;
+ ub.s = xb;
+
+ if (QEMU_NO_HARDFLOAT) {
+ goto soft;
+ }
+
+ float64_input_flush2(&ua.s, &ub.s, s);
+ if (isgreaterequal(ua.h, ub.h)) {
+ if (isgreater(ua.h, ub.h)) {
+ return float_relation_greater;
+ }
+ return float_relation_equal;
+ }
+ if (likely(isless(ua.h, ub.h))) {
+ return float_relation_less;
+ }
+ /* The only condition remaining is unordered.
+ * Fall through to set flags.
+ */
+ soft:
+ return soft_f64_compare(ua.s, ub.s, is_quiet, s);
+}
+
+int float64_compare(float64 a, float64 b, float_status *s)
+{
+ return f64_compare(a, b, false, s);
+}
+
+int float64_compare_quiet(float64 a, float64 b, float_status *s)
+{
+ return f64_compare(a, b, true, s);
+}
+
/* Multiply A by 2 raised to the power N. */
static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s)
{
@@ -2412,20 +3125,76 @@ float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status)
return float16_round_pack_canonical(pr, status);
}
-float32 QEMU_FLATTEN float32_sqrt(float32 a, float_status *status)
+static float32 QEMU_SOFTFLOAT_ATTR
+soft_f32_sqrt(float32 a, float_status *status)
{
FloatParts pa = float32_unpack_canonical(a, status);
FloatParts pr = sqrt_float(pa, status, &float32_params);
return float32_round_pack_canonical(pr, status);
}
-float64 QEMU_FLATTEN float64_sqrt(float64 a, float_status *status)
+static float64 QEMU_SOFTFLOAT_ATTR
+soft_f64_sqrt(float64 a, float_status *status)
{
FloatParts pa = float64_unpack_canonical(a, status);
FloatParts pr = sqrt_float(pa, status, &float64_params);
return float64_round_pack_canonical(pr, status);
}
+float32 QEMU_FLATTEN float32_sqrt(float32 xa, float_status *s)
+{
+ union_float32 ua, ur;
+
+ ua.s = xa;
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+
+ float32_input_flush1(&ua.s, s);
+ if (QEMU_HARDFLOAT_1F32_USE_FP) {
+ if (unlikely(!(fpclassify(ua.h) == FP_NORMAL ||
+ fpclassify(ua.h) == FP_ZERO) ||
+ signbit(ua.h))) {
+ goto soft;
+ }
+ } else if (unlikely(!float32_is_zero_or_normal(ua.s) ||
+ float32_is_neg(ua.s))) {
+ goto soft;
+ }
+ ur.h = sqrtf(ua.h);
+ return ur.s;
+
+ soft:
+ return soft_f32_sqrt(ua.s, s);
+}
+
+float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s)
+{
+ union_float64 ua, ur;
+
+ ua.s = xa;
+ if (unlikely(!can_use_fpu(s))) {
+ goto soft;
+ }
+
+ float64_input_flush1(&ua.s, s);
+ if (QEMU_HARDFLOAT_1F64_USE_FP) {
+ if (unlikely(!(fpclassify(ua.h) == FP_NORMAL ||
+ fpclassify(ua.h) == FP_ZERO) ||
+ signbit(ua.h))) {
+ goto soft;
+ }
+ } else if (unlikely(!float64_is_zero_or_normal(ua.s) ||
+ float64_is_neg(ua.s))) {
+ goto soft;
+ }
+ ur.h = sqrt(ua.h);
+ return ur.s;
+
+ soft:
+ return soft_f64_sqrt(ua.s, s);
+}
+
/*----------------------------------------------------------------------------
| The pattern for a default generated NaN.
*----------------------------------------------------------------------------*/
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index 7a3b87cc9e..54cb36a212 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -18,14 +18,11 @@
#include "qemu/error-report.h"
#include "qemu/option.h"
-static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
+static QTAILQ_HEAD(, FsDriverListEntry) fsdriver_entries =
QTAILQ_HEAD_INITIALIZER(fsdriver_entries);
static FsDriverTable FsDrivers[] = {
{ .name = "local", .ops = &local_ops},
-#ifdef CONFIG_OPEN_BY_HANDLE
- { .name = "handle", .ops = &handle_ops},
-#endif
{ .name = "synth", .ops = &synth_ops},
{ .name = "proxy", .ops = &proxy_ops},
};
diff --git a/gdbstub.c b/gdbstub.c
index c4e4f9f082..bfc7afb509 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -29,6 +29,7 @@
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "exec/gdbstub.h"
+#include "hw/cpu/cluster.h"
#endif
#define MAX_PACKET_LENGTH 4096
@@ -296,6 +297,13 @@ typedef struct GDBRegisterState {
struct GDBRegisterState *next;
} GDBRegisterState;
+typedef struct GDBProcess {
+ uint32_t pid;
+ bool attached;
+
+ char target_xml[1024];
+} GDBProcess;
+
enum RSState {
RS_INACTIVE,
RS_IDLE,
@@ -324,6 +332,9 @@ typedef struct GDBState {
CharBackend chr;
Chardev *mon_chr;
#endif
+ bool multiprocess;
+ GDBProcess *processes;
+ int process_num;
char syscall_buf[256];
gdb_syscall_complete_cb current_syscall_cb;
} GDBState;
@@ -631,13 +642,186 @@ static int memtox(char *buf, const char *mem, int len)
return p - buf;
}
-static const char *get_feature_xml(const char *p, const char **newp,
- CPUClass *cc)
+static uint32_t gdb_get_cpu_pid(const GDBState *s, CPUState *cpu)
+{
+#ifndef CONFIG_USER_ONLY
+ gchar *path, *name = NULL;
+ Object *obj;
+ CPUClusterState *cluster;
+ uint32_t ret;
+
+ path = object_get_canonical_path(OBJECT(cpu));
+
+ if (path == NULL) {
+ /* Return the default process' PID */
+ ret = s->processes[s->process_num - 1].pid;
+ goto out;
+ }
+
+ name = object_get_canonical_path_component(OBJECT(cpu));
+ assert(name != NULL);
+
+ /*
+ * Retrieve the CPU parent path by removing the last '/' and the CPU name
+ * from the CPU canonical path.
+ */
+ path[strlen(path) - strlen(name) - 1] = '\0';
+
+ obj = object_resolve_path_type(path, TYPE_CPU_CLUSTER, NULL);
+
+ if (obj == NULL) {
+ /* Return the default process' PID */
+ ret = s->processes[s->process_num - 1].pid;
+ goto out;
+ }
+
+ cluster = CPU_CLUSTER(obj);
+ ret = cluster->cluster_id + 1;
+
+out:
+ g_free(name);
+ g_free(path);
+
+ return ret;
+
+#else
+ /* TODO: In user mode, we should use the task state PID */
+ return s->processes[s->process_num - 1].pid;
+#endif
+}
+
+static GDBProcess *gdb_get_process(const GDBState *s, uint32_t pid)
+{
+ int i;
+
+ if (!pid) {
+ /* 0 means any process, we take the first one */
+ return &s->processes[0];
+ }
+
+ for (i = 0; i < s->process_num; i++) {
+ if (s->processes[i].pid == pid) {
+ return &s->processes[i];
+ }
+ }
+
+ return NULL;
+}
+
+static GDBProcess *gdb_get_cpu_process(const GDBState *s, CPUState *cpu)
+{
+ return gdb_get_process(s, gdb_get_cpu_pid(s, cpu));
+}
+
+static CPUState *find_cpu(uint32_t thread_id)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ if (cpu_gdb_index(cpu) == thread_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
+
+static CPUState *get_first_cpu_in_process(const GDBState *s,
+ GDBProcess *process)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ if (gdb_get_cpu_pid(s, cpu) == process->pid) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
+
+static CPUState *gdb_next_cpu_in_process(const GDBState *s, CPUState *cpu)
+{
+ uint32_t pid = gdb_get_cpu_pid(s, cpu);
+ cpu = CPU_NEXT(cpu);
+
+ while (cpu) {
+ if (gdb_get_cpu_pid(s, cpu) == pid) {
+ break;
+ }
+
+ cpu = CPU_NEXT(cpu);
+ }
+
+ return cpu;
+}
+
+static CPUState *gdb_get_cpu(const GDBState *s, uint32_t pid, uint32_t tid)
+{
+ GDBProcess *process;
+ CPUState *cpu;
+
+ if (!tid) {
+ /* 0 means any thread, we take the first one */
+ tid = 1;
+ }
+
+ cpu = find_cpu(tid);
+
+ if (cpu == NULL) {
+ return NULL;
+ }
+
+ process = gdb_get_cpu_process(s, cpu);
+
+ if (process->pid != pid) {
+ return NULL;
+ }
+
+ if (!process->attached) {
+ return NULL;
+ }
+
+ return cpu;
+}
+
+/* Return the cpu following @cpu, while ignoring unattached processes. */
+static CPUState *gdb_next_attached_cpu(const GDBState *s, CPUState *cpu)
+{
+ cpu = CPU_NEXT(cpu);
+
+ while (cpu) {
+ if (gdb_get_cpu_process(s, cpu)->attached) {
+ break;
+ }
+
+ cpu = CPU_NEXT(cpu);
+ }
+
+ return cpu;
+}
+
+/* Return the first attached cpu */
+static CPUState *gdb_first_attached_cpu(const GDBState *s)
+{
+ CPUState *cpu = first_cpu;
+ GDBProcess *process = gdb_get_cpu_process(s, cpu);
+
+ if (!process->attached) {
+ return gdb_next_attached_cpu(s, cpu);
+ }
+
+ return cpu;
+}
+
+static const char *get_feature_xml(const GDBState *s, const char *p,
+ const char **newp, GDBProcess *process)
{
size_t len;
int i;
const char *name;
- static char target_xml[1024];
+ CPUState *cpu = get_first_cpu_in_process(s, process);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
len = 0;
while (p[len] && p[len] != ':')
@@ -646,36 +830,37 @@ static const char *get_feature_xml(const char *p, const char **newp,
name = NULL;
if (strncmp(p, "target.xml", len) == 0) {
+ char *buf = process->target_xml;
+ const size_t buf_sz = sizeof(process->target_xml);
+
/* Generate the XML description for this CPU. */
- if (!target_xml[0]) {
+ if (!buf[0]) {
GDBRegisterState *r;
- CPUState *cpu = first_cpu;
- pstrcat(target_xml, sizeof(target_xml),
+ pstrcat(buf, buf_sz,
"<?xml version=\"1.0\"?>"
"<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
"<target>");
if (cc->gdb_arch_name) {
gchar *arch = cc->gdb_arch_name(cpu);
- pstrcat(target_xml, sizeof(target_xml), "<architecture>");
- pstrcat(target_xml, sizeof(target_xml), arch);
- pstrcat(target_xml, sizeof(target_xml), "</architecture>");
+ pstrcat(buf, buf_sz, "<architecture>");
+ pstrcat(buf, buf_sz, arch);
+ pstrcat(buf, buf_sz, "</architecture>");
g_free(arch);
}
- pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
- pstrcat(target_xml, sizeof(target_xml), cc->gdb_core_xml_file);
- pstrcat(target_xml, sizeof(target_xml), "\"/>");
+ pstrcat(buf, buf_sz, "<xi:include href=\"");
+ pstrcat(buf, buf_sz, cc->gdb_core_xml_file);
+ pstrcat(buf, buf_sz, "\"/>");
for (r = cpu->gdb_regs; r; r = r->next) {
- pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
- pstrcat(target_xml, sizeof(target_xml), r->xml);
- pstrcat(target_xml, sizeof(target_xml), "\"/>");
+ pstrcat(buf, buf_sz, "<xi:include href=\"");
+ pstrcat(buf, buf_sz, r->xml);
+ pstrcat(buf, buf_sz, "\"/>");
}
- pstrcat(target_xml, sizeof(target_xml), "</target>");
+ pstrcat(buf, buf_sz, "</target>");
}
- return target_xml;
+ return buf;
}
if (cc->gdb_get_dynamic_xml) {
- CPUState *cpu = first_cpu;
char *xmlname = g_strndup(p, len);
const char *xml = cc->gdb_get_dynamic_xml(cpu, xmlname);
@@ -862,6 +1047,24 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
}
}
+static inline void gdb_cpu_breakpoint_remove_all(CPUState *cpu)
+{
+ cpu_breakpoint_remove_all(cpu, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+ cpu_watchpoint_remove_all(cpu, BP_GDB);
+#endif
+}
+
+static void gdb_process_breakpoint_remove_all(const GDBState *s, GDBProcess *p)
+{
+ CPUState *cpu = get_first_cpu_in_process(s, p);
+
+ while (cpu) {
+ gdb_cpu_breakpoint_remove_all(cpu);
+ cpu = gdb_next_cpu_in_process(s, cpu);
+ }
+}
+
static void gdb_breakpoint_remove_all(void)
{
CPUState *cpu;
@@ -872,10 +1075,7 @@ static void gdb_breakpoint_remove_all(void)
}
CPU_FOREACH(cpu) {
- cpu_breakpoint_remove_all(cpu, BP_GDB);
-#ifndef CONFIG_USER_ONLY
- cpu_watchpoint_remove_all(cpu, BP_GDB);
-#endif
+ gdb_cpu_breakpoint_remove_all(cpu);
}
}
@@ -887,17 +1087,71 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
cpu_set_pc(cpu, pc);
}
-static CPUState *find_cpu(uint32_t thread_id)
+static char *gdb_fmt_thread_id(const GDBState *s, CPUState *cpu,
+ char *buf, size_t buf_size)
{
- CPUState *cpu;
+ if (s->multiprocess) {
+ snprintf(buf, buf_size, "p%02x.%02x",
+ gdb_get_cpu_pid(s, cpu), cpu_gdb_index(cpu));
+ } else {
+ snprintf(buf, buf_size, "%02x", cpu_gdb_index(cpu));
+ }
- CPU_FOREACH(cpu) {
- if (cpu_gdb_index(cpu) == thread_id) {
- return cpu;
+ return buf;
+}
+
+typedef enum GDBThreadIdKind {
+ GDB_ONE_THREAD = 0,
+ GDB_ALL_THREADS, /* One process, all threads */
+ GDB_ALL_PROCESSES,
+ GDB_READ_THREAD_ERR
+} GDBThreadIdKind;
+
+static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
+ uint32_t *pid, uint32_t *tid)
+{
+ unsigned long p, t;
+ int ret;
+
+ if (*buf == 'p') {
+ buf++;
+ ret = qemu_strtoul(buf, &buf, 16, &p);
+
+ if (ret) {
+ return GDB_READ_THREAD_ERR;
}
+
+ /* Skip '.' */
+ buf++;
+ } else {
+ p = 1;
}
- return NULL;
+ ret = qemu_strtoul(buf, &buf, 16, &t);
+
+ if (ret) {
+ return GDB_READ_THREAD_ERR;
+ }
+
+ *end_buf = buf;
+
+ if (p == -1) {
+ return GDB_ALL_PROCESSES;
+ }
+
+ if (pid) {
+ *pid = p;
+ }
+
+ if (t == -1) {
+ return GDB_ALL_THREADS;
+ }
+
+ if (tid) {
+ *tid = t;
+ }
+
+ return GDB_ONE_THREAD;
}
static int is_query_packet(const char *p, const char *query, char separator)
@@ -915,10 +1169,12 @@ static int is_query_packet(const char *p, const char *query, char separator)
*/
static int gdb_handle_vcont(GDBState *s, const char *p)
{
- int res, idx, signal = 0;
+ int res, signal = 0;
char cur_action;
char *newstates;
unsigned long tmp;
+ uint32_t pid, tid;
+ GDBProcess *process;
CPUState *cpu;
#ifdef CONFIG_USER_ONLY
int max_cpus = 1; /* global variable max_cpus exists only in system mode */
@@ -961,25 +1217,48 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
res = -ENOTSUP;
goto out;
}
- /* thread specification. special values: (none), -1 = all; 0 = any */
- if ((p[0] == ':' && p[1] == '-' && p[2] == '1') || (p[0] != ':')) {
- if (*p == ':') {
- p += 3;
- }
- for (idx = 0; idx < max_cpus; idx++) {
- if (newstates[idx] == 1) {
- newstates[idx] = cur_action;
+
+ if (*p++ != ':') {
+ res = -ENOTSUP;
+ goto out;
+ }
+
+ switch (read_thread_id(p, &p, &pid, &tid)) {
+ case GDB_READ_THREAD_ERR:
+ res = -EINVAL;
+ goto out;
+
+ case GDB_ALL_PROCESSES:
+ cpu = gdb_first_attached_cpu(s);
+ while (cpu) {
+ if (newstates[cpu->cpu_index] == 1) {
+ newstates[cpu->cpu_index] = cur_action;
}
+
+ cpu = gdb_next_attached_cpu(s, cpu);
}
- } else if (*p == ':') {
- p++;
- res = qemu_strtoul(p, &p, 16, &tmp);
- if (res) {
+ break;
+
+ case GDB_ALL_THREADS:
+ process = gdb_get_process(s, pid);
+
+ if (!process->attached) {
+ res = -EINVAL;
goto out;
}
- /* 0 means any thread, so we pick the first valid CPU */
- cpu = tmp ? find_cpu(tmp) : first_cpu;
+ cpu = get_first_cpu_in_process(s, process);
+ while (cpu) {
+ if (newstates[cpu->cpu_index] == 1) {
+ newstates[cpu->cpu_index] = cur_action;
+ }
+
+ cpu = gdb_next_cpu_in_process(s, cpu);
+ }
+ break;
+
+ case GDB_ONE_THREAD:
+ cpu = gdb_get_cpu(s, pid, tid);
/* invalid CPU/thread specified */
if (!cpu) {
@@ -991,6 +1270,7 @@ static int gdb_handle_vcont(GDBState *s, const char *p)
if (newstates[cpu->cpu_index] == 1) {
newstates[cpu->cpu_index] = cur_action;
}
+ break;
}
}
s->signal = signal;
@@ -1005,24 +1285,30 @@ out:
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
CPUState *cpu;
+ GDBProcess *process;
CPUClass *cc;
const char *p;
- uint32_t thread;
+ uint32_t pid, tid;
int ch, reg_size, type, res;
uint8_t mem_buf[MAX_PACKET_LENGTH];
char buf[sizeof(mem_buf) + 1 /* trailing NUL */];
+ char thread_id[16];
uint8_t *registers;
target_ulong addr, len;
+ GDBThreadIdKind thread_kind;
trace_gdbstub_io_command(line_buf);
p = line_buf;
ch = *p++;
switch(ch) {
+ case '!':
+ put_packet(s, "OK");
+ break;
case '?':
/* TODO: Make this return the correct value for user-mode. */
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP,
- cpu_gdb_index(s->c_cpu));
+ snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
+ gdb_fmt_thread_id(s, s->c_cpu, thread_id, sizeof(thread_id)));
put_packet(s, buf);
/* Remove all the breakpoints when this query is issued,
* because gdb is doing and initial connect and the state
@@ -1062,6 +1348,41 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
goto unknown_command;
}
break;
+ } else if (strncmp(p, "Attach;", 7) == 0) {
+ unsigned long pid;
+
+ p += 7;
+
+ if (qemu_strtoul(p, &p, 16, &pid)) {
+ put_packet(s, "E22");
+ break;
+ }
+
+ process = gdb_get_process(s, pid);
+
+ if (process == NULL) {
+ put_packet(s, "E22");
+ break;
+ }
+
+ cpu = get_first_cpu_in_process(s, process);
+
+ if (cpu == NULL) {
+ /* Refuse to attach an empty process */
+ put_packet(s, "E22");
+ break;
+ }
+
+ process->attached = true;
+
+ s->g_cpu = cpu;
+ s->c_cpu = cpu;
+
+ snprintf(buf, sizeof(buf), "T%02xthread:%s;", GDB_SIGNAL_TRAP,
+ gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
+
+ put_packet(s, buf);
+ break;
} else {
goto unknown_command;
}
@@ -1071,9 +1392,40 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
exit(0);
case 'D':
/* Detach packet */
- gdb_breakpoint_remove_all();
- gdb_syscall_mode = GDB_SYS_DISABLED;
- gdb_continue(s);
+ pid = 1;
+
+ if (s->multiprocess) {
+ unsigned long lpid;
+ if (*p != ';') {
+ put_packet(s, "E22");
+ break;
+ }
+
+ if (qemu_strtoul(p + 1, &p, 16, &lpid)) {
+ put_packet(s, "E22");
+ break;
+ }
+
+ pid = lpid;
+ }
+
+ process = gdb_get_process(s, pid);
+ gdb_process_breakpoint_remove_all(s, process);
+ process->attached = false;
+
+ if (pid == gdb_get_cpu_pid(s, s->c_cpu)) {
+ s->c_cpu = gdb_first_attached_cpu(s);
+ }
+
+ if (pid == gdb_get_cpu_pid(s, s->g_cpu)) {
+ s->g_cpu = gdb_first_attached_cpu(s);
+ }
+
+ if (s->c_cpu == NULL) {
+ /* No more process attached */
+ gdb_syscall_mode = GDB_SYS_DISABLED;
+ gdb_continue(s);
+ }
put_packet(s, "OK");
break;
case 's':
@@ -1220,12 +1572,18 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
break;
case 'H':
type = *p++;
- thread = strtoull(p, (char **)&p, 16);
- if (thread == -1 || thread == 0) {
+
+ thread_kind = read_thread_id(p, &p, &pid, &tid);
+ if (thread_kind == GDB_READ_THREAD_ERR) {
+ put_packet(s, "E22");
+ break;
+ }
+
+ if (thread_kind != GDB_ONE_THREAD) {
put_packet(s, "OK");
break;
}
- cpu = find_cpu(thread);
+ cpu = gdb_get_cpu(s, pid, tid);
if (cpu == NULL) {
put_packet(s, "E22");
break;
@@ -1245,8 +1603,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
break;
case 'T':
- thread = strtoull(p, (char **)&p, 16);
- cpu = find_cpu(thread);
+ thread_kind = read_thread_id(p, &p, &pid, &tid);
+ if (thread_kind == GDB_READ_THREAD_ERR) {
+ put_packet(s, "E22");
+ break;
+ }
+ cpu = gdb_get_cpu(s, pid, tid);
if (cpu != NULL) {
put_packet(s, "OK");
@@ -1280,31 +1642,55 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
put_packet(s, "OK");
break;
} else if (strcmp(p,"C") == 0) {
- /* "Current thread" remains vague in the spec, so always return
- * the first CPU (gdb returns the first thread). */
- put_packet(s, "QC1");
+ /*
+ * "Current thread" remains vague in the spec, so always return
+ * the first thread of the current process (gdb returns the
+ * first thread).
+ */
+ cpu = get_first_cpu_in_process(s, gdb_get_cpu_process(s, s->g_cpu));
+ snprintf(buf, sizeof(buf), "QC%s",
+ gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id)));
+ put_packet(s, buf);
break;
} else if (strcmp(p,"fThreadInfo") == 0) {
- s->query_cpu = first_cpu;
+ s->query_cpu = gdb_first_attached_cpu(s);
goto report_cpuinfo;
} else if (strcmp(p,"sThreadInfo") == 0) {
report_cpuinfo:
if (s->query_cpu) {
- snprintf(buf, sizeof(buf), "m%x", cpu_gdb_index(s->query_cpu));
+ snprintf(buf, sizeof(buf), "m%s",
+ gdb_fmt_thread_id(s, s->query_cpu,
+ thread_id, sizeof(thread_id)));
put_packet(s, buf);
- s->query_cpu = CPU_NEXT(s->query_cpu);
+ s->query_cpu = gdb_next_attached_cpu(s, s->query_cpu);
} else
put_packet(s, "l");
break;
} else if (strncmp(p,"ThreadExtraInfo,", 16) == 0) {
- thread = strtoull(p+16, (char **)&p, 16);
- cpu = find_cpu(thread);
+ if (read_thread_id(p + 16, &p, &pid, &tid) == GDB_READ_THREAD_ERR) {
+ put_packet(s, "E22");
+ break;
+ }
+ cpu = gdb_get_cpu(s, pid, tid);
if (cpu != NULL) {
cpu_synchronize_state(cpu);
- /* memtohex() doubles the required space */
- len = snprintf((char *)mem_buf, sizeof(buf) / 2,
- "CPU#%d [%s]", cpu->cpu_index,
- cpu->halted ? "halted " : "running");
+
+ if (s->multiprocess && (s->process_num > 1)) {
+ /* Print the CPU model and name in multiprocess mode */
+ ObjectClass *oc = object_get_class(OBJECT(cpu));
+ const char *cpu_model = object_class_get_name(oc);
+ char *cpu_name =
+ object_get_canonical_path_component(OBJECT(cpu));
+ len = snprintf((char *)mem_buf, sizeof(buf) / 2,
+ "%s %s [%s]", cpu_model, cpu_name,
+ cpu->halted ? "halted " : "running");
+ g_free(cpu_name);
+ } else {
+ /* memtohex() doubles the required space */
+ len = snprintf((char *)mem_buf, sizeof(buf) / 2,
+ "CPU#%d [%s]", cpu->cpu_index,
+ cpu->halted ? "halted " : "running");
+ }
trace_gdbstub_op_extra_info((char *)mem_buf);
memtohex(buf, mem_buf, len);
put_packet(s, buf);
@@ -1346,6 +1732,12 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (cc->gdb_core_xml_file != NULL) {
pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
}
+
+ if (strstr(p, "multiprocess+")) {
+ s->multiprocess = true;
+ }
+ pstrcat(buf, sizeof(buf), ";multiprocess+");
+
put_packet(s, buf);
break;
}
@@ -1353,14 +1745,15 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
const char *xml;
target_ulong total_len;
- cc = CPU_GET_CLASS(first_cpu);
+ process = gdb_get_cpu_process(s, s->g_cpu);
+ cc = CPU_GET_CLASS(s->g_cpu);
if (cc->gdb_core_xml_file == NULL) {
goto unknown_command;
}
gdb_has_xml = true;
p += 19;
- xml = get_feature_xml(p, &p, cc);
+ xml = get_feature_xml(s, p, &p, process);
if (!xml) {
snprintf(buf, sizeof(buf), "E00");
put_packet(s, buf);
@@ -1411,6 +1804,16 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
void gdb_set_stop_cpu(CPUState *cpu)
{
+ GDBProcess *p = gdb_get_cpu_process(gdbserver_state, cpu);
+
+ if (!p->attached) {
+ /*
+ * Having a stop CPU corresponding to a process that is not attached
+ * confuses GDB. So we ignore the request.
+ */
+ return;
+ }
+
gdbserver_state->c_cpu = cpu;
gdbserver_state->g_cpu = cpu;
}
@@ -1421,6 +1824,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
GDBState *s = gdbserver_state;
CPUState *cpu = s->c_cpu;
char buf[256];
+ char thread_id[16];
const char *type;
int ret;
@@ -1432,6 +1836,14 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
put_packet(s, s->syscall_buf);
return;
}
+
+ if (cpu == NULL) {
+ /* No process attached */
+ return;
+ }
+
+ gdb_fmt_thread_id(s, cpu, thread_id, sizeof(thread_id));
+
switch (state) {
case RUN_STATE_DEBUG:
if (cpu->watchpoint_hit) {
@@ -1449,8 +1861,8 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu),
(target_ulong)cpu->watchpoint_hit->vaddr);
snprintf(buf, sizeof(buf),
- "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";",
- GDB_SIGNAL_TRAP, cpu_gdb_index(cpu), type,
+ "T%02xthread:%s;%swatch:" TARGET_FMT_lx ";",
+ GDB_SIGNAL_TRAP, thread_id, type,
(target_ulong)cpu->watchpoint_hit->vaddr);
cpu->watchpoint_hit = NULL;
goto send_packet;
@@ -1492,7 +1904,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
break;
}
gdb_set_stop_cpu(cpu);
- snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_gdb_index(cpu));
+ snprintf(buf, sizeof(buf), "T%02xthread:%s;", ret, thread_id);
send_packet:
put_packet(s, buf);
@@ -1751,6 +2163,31 @@ void gdb_exit(CPUArchState *env, int code)
#endif
}
+/*
+ * Create the process that will contain all the "orphan" CPUs (that are not
+ * part of a CPU cluster). Note that if this process contains no CPUs, it won't
+ * be attachable and thus will be invisible to the user.
+ */
+static void create_default_process(GDBState *s)
+{
+ GDBProcess *process;
+ int max_pid = 0;
+
+ if (s->process_num) {
+ max_pid = s->processes[s->process_num - 1].pid;
+ }
+
+ s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
+ process = &s->processes[s->process_num - 1];
+
+ /* We need an available PID slot for this process */
+ assert(max_pid < UINT32_MAX);
+
+ process->pid = max_pid + 1;
+ process->attached = false;
+ process->target_xml[0] = '\0';
+}
+
#ifdef CONFIG_USER_ONLY
int
gdb_handlesig(CPUState *cpu, int sig)
@@ -1846,8 +2283,10 @@ static bool gdb_accept(void)
}
s = g_malloc0(sizeof(GDBState));
- s->c_cpu = first_cpu;
- s->g_cpu = first_cpu;
+ create_default_process(s);
+ s->processes[0].attached = true;
+ s->c_cpu = gdb_first_attached_cpu(s);
+ s->g_cpu = s->c_cpu;
s->fd = fd;
gdb_has_xml = false;
@@ -1933,8 +2372,19 @@ static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
static void gdb_chr_event(void *opaque, int event)
{
+ int i;
+ GDBState *s = (GDBState *) opaque;
+
switch (event) {
case CHR_EVENT_OPENED:
+ /* Start with first process attached, others detached */
+ for (i = 0; i < s->process_num; i++) {
+ s->processes[i].attached = !i;
+ }
+
+ s->c_cpu = gdb_first_attached_cpu(s);
+ s->g_cpu = s->c_cpu;
+
vm_stop(RUN_STATE_PAUSED);
gdb_has_xml = false;
break;
@@ -2004,6 +2454,66 @@ static const TypeInfo char_gdb_type_info = {
.class_init = char_gdb_class_init,
};
+static int find_cpu_clusters(Object *child, void *opaque)
+{
+ if (object_dynamic_cast(child, TYPE_CPU_CLUSTER)) {
+ GDBState *s = (GDBState *) opaque;
+ CPUClusterState *cluster = CPU_CLUSTER(child);
+ GDBProcess *process;
+
+ s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
+
+ process = &s->processes[s->process_num - 1];
+
+ /*
+ * GDB process IDs -1 and 0 are reserved. To avoid subtle errors at
+ * runtime, we enforce here that the machine does not use a cluster ID
+ * that would lead to PID 0.
+ */
+ assert(cluster->cluster_id != UINT32_MAX);
+ process->pid = cluster->cluster_id + 1;
+ process->attached = false;
+ process->target_xml[0] = '\0';
+
+ return 0;
+ }
+
+ return object_child_foreach(child, find_cpu_clusters, opaque);
+}
+
+static int pid_order(const void *a, const void *b)
+{
+ GDBProcess *pa = (GDBProcess *) a;
+ GDBProcess *pb = (GDBProcess *) b;
+
+ if (pa->pid < pb->pid) {
+ return -1;
+ } else if (pa->pid > pb->pid) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void create_processes(GDBState *s)
+{
+ object_child_foreach(object_get_root(), find_cpu_clusters, s);
+
+ if (s->processes) {
+ /* Sort by PID */
+ qsort(s->processes, s->process_num, sizeof(s->processes[0]), pid_order);
+ }
+
+ create_default_process(s);
+}
+
+static void cleanup_processes(GDBState *s)
+{
+ g_free(s->processes);
+ s->process_num = 0;
+ s->processes = NULL;
+}
+
int gdbserver_start(const char *device)
{
trace_gdbstub_op_start(device);
@@ -2060,15 +2570,17 @@ int gdbserver_start(const char *device)
} else {
qemu_chr_fe_deinit(&s->chr, true);
mon_chr = s->mon_chr;
+ cleanup_processes(s);
memset(s, 0, sizeof(GDBState));
s->mon_chr = mon_chr;
}
- s->c_cpu = first_cpu;
- s->g_cpu = first_cpu;
+
+ create_processes(s);
+
if (chr) {
qemu_chr_fe_init(&s->chr, chr, &error_abort);
qemu_chr_fe_set_handlers(&s->chr, gdb_chr_can_receive, gdb_chr_receive,
- gdb_chr_event, NULL, NULL, NULL, true);
+ gdb_chr_event, NULL, s, NULL, true);
}
s->state = chr ? RS_IDLE : RS_INACTIVE;
s->mon_chr = mon_chr;
diff --git a/gitdm.config b/gitdm.config
new file mode 100644
index 0000000000..7472d4b8be
--- /dev/null
+++ b/gitdm.config
@@ -0,0 +1,50 @@
+#
+# This is the gitdm configuration file for QEMU.
+#
+# It is to be used with LWN's git dataminer tool for generating
+# reports about development activity in the QEMU repo. The LWN gitdm
+# tool can be found at:
+#
+# git://git.lwn.net/gitdm.git
+#
+# A run to generate a report for the last year of activity would be
+#
+# git log --numstat --since "Last Year" | gitdm -n -l 10
+#
+
+# EmailAliases lets us cope with developers who use more
+# than one address or have changed addresses. This duplicates some of
+# the information in the existing .mailmap but in a slightly different
+# form.
+#
+EmailAliases contrib/gitdm/aliases
+
+#
+# EmailMap does the main work of mapping addresses onto
+# employers.
+#
+EmailMap contrib/gitdm/domain-map
+
+#
+# Use GroupMap to map a file full of addresses to the
+# same employer. This is used for people that don't post from easily
+# identifiable corporate emails.
+#
+
+GroupMap contrib/gitdm/group-map-redhat Red Hat
+GroupMap contrib/gitdm/group-map-wavecomp Wave Computing
+GroupMap contrib/gitdm/group-map-cadence Cadence Design Systems
+GroupMap contrib/gitdm/group-map-codeweavers CodeWeavers
+GroupMap contrib/gitdm/group-map-ibm IBM
+
+# Also group together our prolific individual contributors
+# and those working under academic auspices
+GroupMap contrib/gitdm/group-map-individuals (None)
+GroupMap contrib/gitdm/group-map-academics Academics (various)
+
+#
+#
+# Use FileTypeMap to map a file types to file names using regular
+# regular expressions.
+#
+FileTypeMap contrib/gitdm/filetypes.txt
diff --git a/hmp-commands.hx b/hmp-commands.hx
index db0c681f74..ba71558c25 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1849,14 +1849,16 @@ ETEXI
.name = "cpu-add",
.args_type = "id:i",
.params = "id",
- .help = "add cpu",
+ .help = "add cpu (deprecated, use device_add instead)",
.cmd = hmp_cpu_add,
},
STEXI
@item cpu-add @var{id}
@findex cpu-add
-Add CPU with id @var{id}
+Add CPU with id @var{id}. This command is deprecated, please
++use @code{device_add} instead. For details, refer to
+'docs/cpu-hotplug.rst'.
ETEXI
{
diff --git a/hmp.c b/hmp.c
index 7828f93a39..8da5fd8760 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1220,7 +1220,10 @@ void hmp_cont(Monitor *mon, const QDict *qdict)
void hmp_system_wakeup(Monitor *mon, const QDict *qdict)
{
- qmp_system_wakeup(NULL);
+ Error *err = NULL;
+
+ qmp_system_wakeup(&err);
+ hmp_handle_error(mon, &err);
}
void hmp_nmi(Monitor *mon, const QDict *qdict)
@@ -2323,7 +2326,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
}
qmp_nbd_server_add(info->value->device, false, NULL,
- true, writable, &local_err);
+ true, writable, false, NULL, &local_err);
if (local_err != NULL) {
qmp_nbd_server_stop(NULL);
@@ -2344,7 +2347,8 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict)
bool writable = qdict_get_try_bool(qdict, "writable", false);
Error *local_err = NULL;
- qmp_nbd_server_add(device, !!name, name, true, writable, &local_err);
+ qmp_nbd_server_add(device, !!name, name, true, writable,
+ false, NULL, &local_err);
hmp_handle_error(mon, &local_err);
}
@@ -2372,6 +2376,8 @@ void hmp_cpu_add(Monitor *mon, const QDict *qdict)
int cpuid;
Error *err = NULL;
+ error_report("cpu_add is deprecated, please use device_add instead");
+
cpuid = qdict_get_int(qdict, "id");
qmp_cpu_add(cpuid, &err);
hmp_handle_error(mon, &err);
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
deleted file mode 100644
index 3465b1ef30..0000000000
--- a/hw/9pfs/9p-handle.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * 9p handle callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * Aneesh Kumar K.V <aneesh.kumar@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 "qemu/osdep.h"
-#include "9p.h"
-#include "9p-xattr.h"
-#include <arpa/inet.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "qapi/error.h"
-#include "qemu/xattr.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include <linux/fs.h>
-#ifdef CONFIG_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-#include <sys/ioctl.h>
-
-#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
-#endif
-#ifndef EXT2_SUPER_MAGIC
-#define EXT2_SUPER_MAGIC 0xEF53
-#endif
-#ifndef REISERFS_SUPER_MAGIC
-#define REISERFS_SUPER_MAGIC 0x52654973
-#endif
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-
-typedef struct HandleData {
- int mountfd;
- int handle_bytes;
-} HandleData;
-
-static inline int name_to_handle(int dirfd, const char *name,
- struct file_handle *fh, int *mnt_id, int flags)
-{
- return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
-}
-
-static inline int open_by_handle(int mountfd, const char *fh, int flags)
-{
- return open_by_handle_at(mountfd, (struct file_handle *)fh, flags);
-}
-
-static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
-{
- int fd, ret;
- fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);
- if (fd < 0) {
- return fd;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- if (ret < 0) {
- goto err_out;
- }
- ret = fchmod(fd, credp->fc_mode & 07777);
-err_out:
- close(fd);
- return ret;
-}
-
-
-static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path,
- struct stat *stbuf)
-{
- int fd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int fd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = readlinkat(fd, "", buf, bufsz);
- close(fd);
- return ret;
-}
-
-static int handle_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir.stream);
-}
-
-static int handle_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- HandleData *data = (HandleData *) ctx->private;
-
- fs->fd = open_by_handle(data->mountfd, fs_path->data, flags);
- return fs->fd;
-}
-
-static int handle_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int ret;
- ret = handle_open(ctx, fs_path, O_DIRECTORY, fs);
- if (ret < 0) {
- return -1;
- }
- fs->dir.stream = fdopendir(ret);
- if (!fs->dir.stream) {
- return -1;
- }
- return 0;
-}
-
-static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir.stream);
-}
-
-static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir.stream);
-}
-
-static struct dirent *handle_readdir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return readdir(fs->dir.stream);
-}
-
-static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir.stream, off);
-}
-
-static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
-#ifdef CONFIG_PREADV
- return preadv(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- return readv(fs->fd, iov, iovcnt);
- }
-#endif
-}
-
-static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- int err = lseek(fs->fd, offset, SEEK_SET);
- if (err == -1) {
- return err;
- } else {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is sepcified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int fd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fchmod(fd, credp->fc_mode);
- close(fd);
- return ret;
-}
-
-static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int dirfd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
- if (!ret) {
- ret = handle_update_file_cred(dirfd, name, credp);
- }
- close(dirfd);
- return ret;
-}
-
-static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int dirfd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = mkdirat(dirfd, name, credp->fc_mode);
- if (!ret) {
- ret = handle_update_file_cred(dirfd, name, credp);
- }
- close(dirfd);
- return ret;
-}
-
-static int handle_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- int ret;
- int dirfd, fd;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode);
- if (fd >= 0) {
- ret = handle_update_file_cred(dirfd, name, credp);
- if (ret < 0) {
- close(fd);
- fd = ret;
- } else {
- fs->fd = fd;
- }
- }
- close(dirfd);
- return fd;
-}
-
-
-static int handle_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int fd, dirfd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
- ret = symlinkat(oldpath, dirfd, name);
- if (!ret) {
- fd = openat(dirfd, name, O_PATH | O_NOFOLLOW);
- if (fd < 0) {
- ret = fd;
- goto err_out;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- close(fd);
- }
-err_out:
- close(dirfd);
- return ret;
-}
-
-static int handle_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int oldfd, newdirfd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH);
- if (oldfd < 0) {
- return oldfd;
- }
- newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH);
- if (newdirfd < 0) {
- close(oldfd);
- return newdirfd;
- }
- ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
- close(newdirfd);
- close(oldfd);
- return ret;
-}
-
-static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY);
- if (fd < 0) {
- return fd;
- }
- ret = ftruncate(fd, size);
- close(fd);
- return ret;
-}
-
-static int handle_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- errno = EOPNOTSUPP;
- return -1;
-}
-
-static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int fd, ret;
- HandleData *data = (HandleData *) fs_ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_PATH);
- if (fd < 0) {
- return fd;
- }
- ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
- close(fd);
- return ret;
-}
-
-static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int ret;
- int fd;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = futimens(fd, buf);
- close(fd);
- return ret;
-}
-
-static int handle_remove(FsContext *ctx, const char *path)
-{
- errno = EOPNOTSUPP;
- return -1;
-}
-
-static int handle_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int handle_statfs(FsContext *ctx, V9fsPath *fs_path,
- struct statfs *stbuf)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fstatfs(fd, stbuf);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fgetxattr(fd, name, value, size);
- close(fd);
- return ret;
-}
-
-static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = flistxattr(fd, value, size);
- close(fd);
- return ret;
-}
-
-static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fsetxattr(fd, name, value, size, flags);
- close(fd);
- return ret;
-}
-
-static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int fd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK);
- if (fd < 0) {
- return fd;
- }
- ret = fremovexattr(fd, name);
- close(fd);
- return ret;
-}
-
-static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- char *buffer;
- struct file_handle *fh;
- int dirfd, ret, mnt_id;
- HandleData *data = (HandleData *) ctx->private;
-
- /* "." and ".." are not allowed */
- if (!strcmp(name, ".") || !strcmp(name, "..")) {
- errno = EINVAL;
- return -1;
-
- }
- if (dir_path) {
- dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH);
- } else {
- /* relative to export root */
- buffer = rpath(ctx, ".");
- dirfd = open(buffer, O_DIRECTORY);
- g_free(buffer);
- }
- if (dirfd < 0) {
- return dirfd;
- }
- fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes);
- fh->handle_bytes = data->handle_bytes;
- /* add a "./" at the beginning of the path */
- buffer = g_strdup_printf("./%s", name);
- /* flag = 0 imply don't follow symlink */
- ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
- if (!ret) {
- target->data = (char *)fh;
- target->size = sizeof(struct file_handle) + data->handle_bytes;
- } else {
- g_free(fh);
- }
- close(dirfd);
- g_free(buffer);
- return ret;
-}
-
-static int handle_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int olddirfd, newdirfd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH);
- if (olddirfd < 0) {
- return olddirfd;
- }
- newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH);
- if (newdirfd < 0) {
- close(olddirfd);
- return newdirfd;
- }
- ret = renameat(olddirfd, old_name, newdirfd, new_name);
- close(newdirfd);
- close(olddirfd);
- return ret;
-}
-
-static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int dirfd, ret;
- HandleData *data = (HandleData *) ctx->private;
-
- dirfd = open_by_handle(data->mountfd, dir->data, O_PATH);
- if (dirfd < 0) {
- return dirfd;
- }
-
- ret = unlinkat(dirfd, name, flags);
-
- close(dirfd);
- return ret;
-}
-
-static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
-#ifdef FS_IOC_GETVERSION
- int err;
- V9fsFidOpenState fid_open;
-
- /*
- * Do not try to open special files like device nodes, fifos etc
- * We can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = handle_open(ctx, path, O_RDONLY, &fid_open);
- if (err < 0) {
- return err;
- }
- err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
- handle_close(ctx, &fid_open);
- return err;
-#else
- errno = ENOTTY;
- return -1;
-#endif
-}
-
-static int handle_init(FsContext *ctx, Error **errp)
-{
- int ret, mnt_id;
- struct statfs stbuf;
- struct file_handle fh;
- HandleData *data = g_malloc(sizeof(HandleData));
-
- data->mountfd = open(ctx->fs_root, O_DIRECTORY);
- if (data->mountfd < 0) {
- ret = data->mountfd;
- goto err_out;
- }
- ret = statfs(ctx->fs_root, &stbuf);
- if (!ret) {
- switch (stbuf.f_type) {
- case EXT2_SUPER_MAGIC:
- case BTRFS_SUPER_MAGIC:
- case REISERFS_SUPER_MAGIC:
- case XFS_SUPER_MAGIC:
- ctx->exops.get_st_gen = handle_ioc_getversion;
- break;
- }
- }
- memset(&fh, 0, sizeof(struct file_handle));
- ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0);
- if (ret && errno == EOVERFLOW) {
- data->handle_bytes = fh.handle_bytes;
- ctx->private = data;
- ret = 0;
- goto out;
- }
- /* we got 0 byte handle ? */
- ret = -1;
- close(data->mountfd);
-err_out:
- g_free(data);
-out:
- return ret;
-}
-
-static void handle_cleanup(FsContext *ctx)
-{
- HandleData *data = ctx->private;
-
- close(data->mountfd);
- g_free(data);
-}
-
-static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
-{
- const char *sec_model = qemu_opt_get(opts, "security_model");
- const char *path = qemu_opt_get(opts, "path");
-
- warn_report("handle backend is deprecated");
-
- if (sec_model) {
- error_setg(errp,
- "Invalid argument security_model specified with handle fsdriver");
- return -1;
- }
-
- if (!path) {
- error_setg(errp, "fsdev: No path specified");
- return -1;
- }
- fse->path = g_strdup(path);
- return 0;
-
-}
-
-FileOperations handle_ops = {
- .parse_opts = handle_parse_opts,
- .init = handle_init,
- .cleanup = handle_cleanup,
- .lstat = handle_lstat,
- .readlink = handle_readlink,
- .close = handle_close,
- .closedir = handle_closedir,
- .open = handle_open,
- .opendir = handle_opendir,
- .rewinddir = handle_rewinddir,
- .telldir = handle_telldir,
- .readdir = handle_readdir,
- .seekdir = handle_seekdir,
- .preadv = handle_preadv,
- .pwritev = handle_pwritev,
- .chmod = handle_chmod,
- .mknod = handle_mknod,
- .mkdir = handle_mkdir,
- .fstat = handle_fstat,
- .open2 = handle_open2,
- .symlink = handle_symlink,
- .link = handle_link,
- .truncate = handle_truncate,
- .rename = handle_rename,
- .chown = handle_chown,
- .utimensat = handle_utimensat,
- .remove = handle_remove,
- .fsync = handle_fsync,
- .statfs = handle_statfs,
- .lgetxattr = handle_lgetxattr,
- .llistxattr = handle_llistxattr,
- .lsetxattr = handle_lsetxattr,
- .lremovexattr = handle_lremovexattr,
- .name_to_path = handle_name_to_path,
- .renameat = handle_renameat,
- .unlinkat = handle_unlinkat,
-};
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index bdf7919abf..55821343e5 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1331,8 +1331,8 @@ static void coroutine_fn v9fs_walk(void *opaque)
trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
if (nwnames && nwnames <= P9_MAXWELEM) {
- wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
- qids = g_malloc0(sizeof(qids[0]) * nwnames);
+ wnames = g_new0(V9fsString, nwnames);
+ qids = g_new0(V9fsQID, nwnames);
for (i = 0; i < nwnames; i++) {
err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
if (err < 0) {
diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs
index e3fa673665..8ac04962bd 100644
--- a/hw/9pfs/Makefile.objs
+++ b/hw/9pfs/Makefile.objs
@@ -4,7 +4,6 @@ common-obj-y += 9p-local.o 9p-xattr.o
common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
common-obj-y += coth.o cofs.o codir.o cofile.o
common-obj-y += coxattr.o 9p-synth.o
-common-obj-$(CONFIG_OPEN_BY_HANDLE) += 9p-handle.o
common-obj-y += 9p-proxy.o
endif
diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c
index 3f54a21c76..25ab04d95a 100644
--- a/hw/9pfs/xen-9p-backend.c
+++ b/hw/9pfs/xen-9p-backend.c
@@ -12,7 +12,7 @@
#include "hw/hw.h"
#include "hw/9pfs/9p.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "hw/9pfs/xen-9pfs.h"
#include "qapi/error.h"
#include "qemu/config-file.h"
@@ -45,7 +45,7 @@ typedef struct Xen9pfsRing {
} Xen9pfsRing;
typedef struct Xen9pfsDev {
- struct XenDevice xendev; /* must be first */
+ struct XenLegacyDevice xendev; /* must be first */
V9fsState state;
char *path;
char *security_model;
@@ -56,7 +56,7 @@ typedef struct Xen9pfsDev {
Xen9pfsRing *rings;
} Xen9pfsDev;
-static void xen_9pfs_disconnect(struct XenDevice *xendev);
+static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
static void xen_9pfs_in_sg(Xen9pfsRing *ring,
struct iovec *in_sg,
@@ -178,7 +178,7 @@ static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
g_free(ring->sg);
- ring->sg = g_malloc0(sizeof(*ring->sg) * 2);
+ ring->sg = g_new0(struct iovec, 2);
xen_9pfs_out_sg(ring, ring->sg, &num, pdu->idx);
*piov = ring->sg;
*pniov = num;
@@ -196,7 +196,7 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
g_free(ring->sg);
- ring->sg = g_malloc0(sizeof(*ring->sg) * 2);
+ ring->sg = g_new0(struct iovec, 2);
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
buf_size = iov_size(ring->sg, num);
@@ -243,7 +243,7 @@ static const V9fsTransport xen_9p_transport = {
.push_and_notify = xen_9pfs_push_and_notify,
};
-static int xen_9pfs_init(struct XenDevice *xendev)
+static int xen_9pfs_init(struct XenLegacyDevice *xendev)
{
return 0;
}
@@ -305,7 +305,7 @@ static void xen_9pfs_evtchn_event(void *opaque)
qemu_bh_schedule(ring->bh);
}
-static void xen_9pfs_disconnect(struct XenDevice *xendev)
+static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
{
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
int i;
@@ -321,7 +321,7 @@ static void xen_9pfs_disconnect(struct XenDevice *xendev)
}
}
-static int xen_9pfs_free(struct XenDevice *xendev)
+static int xen_9pfs_free(struct XenLegacyDevice *xendev)
{
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
int i;
@@ -354,7 +354,7 @@ static int xen_9pfs_free(struct XenDevice *xendev)
return 0;
}
-static int xen_9pfs_connect(struct XenDevice *xendev)
+static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
{
Error *err = NULL;
int i;
@@ -368,7 +368,7 @@ static int xen_9pfs_connect(struct XenDevice *xendev)
return -1;
}
- xen_9pdev->rings = g_malloc0(xen_9pdev->num_rings * sizeof(Xen9pfsRing));
+ xen_9pdev->rings = g_new0(Xen9pfsRing, xen_9pdev->num_rings);
for (i = 0; i < xen_9pdev->num_rings; i++) {
char *str;
int ring_order;
@@ -467,7 +467,7 @@ out:
return -1;
}
-static void xen_9pfs_alloc(struct XenDevice *xendev)
+static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
{
xenstore_write_be_str(xendev, "versions", VERSIONS);
xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
index 11c35bcb44..2d46e3789a 100644
--- a/hw/acpi/Makefile.objs
+++ b/hw/acpi/Makefile.objs
@@ -11,6 +11,7 @@ common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
common-obj-y += acpi_interface.o
common-obj-y += bios-linker-loader.o
common-obj-y += aml-build.o
+common-obj-$(CONFIG_TPM) += tpm.o
common-obj-$(CONFIG_IPMI) += ipmi.o
common-obj-$(call lnot,$(CONFIG_IPMI)) += ipmi-stub.o
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 1e43cd736d..555c24f21d 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1589,6 +1589,74 @@ void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
g_array_free(tables->vmgenid, mfre);
}
+/*
+ * ACPI spec 5.2.5.3 Root System Description Pointer (RSDP).
+ * (Revision 1.0 or later)
+ */
+void
+build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data)
+{
+ int tbl_off = tbl->len; /* Table offset in the RSDP file */
+
+ switch (rsdp_data->revision) {
+ case 0:
+ /* With ACPI 1.0, we must have an RSDT pointer */
+ g_assert(rsdp_data->rsdt_tbl_offset);
+ break;
+ case 2:
+ /* With ACPI 2.0+, we must have an XSDT pointer */
+ g_assert(rsdp_data->xsdt_tbl_offset);
+ break;
+ default:
+ /* Only revisions 0 (ACPI 1.0) and 2 (ACPI 2.0+) are valid for RSDP */
+ g_assert_not_reached();
+ }
+
+ bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, tbl, 16,
+ true /* fseg memory */);
+
+ g_array_append_vals(tbl, "RSD PTR ", 8); /* Signature */
+ build_append_int_noprefix(tbl, 0, 1); /* Checksum */
+ g_array_append_vals(tbl, rsdp_data->oem_id, 6); /* OEMID */
+ build_append_int_noprefix(tbl, rsdp_data->revision, 1); /* Revision */
+ build_append_int_noprefix(tbl, 0, 4); /* RsdtAddress */
+ if (rsdp_data->rsdt_tbl_offset) {
+ /* RSDT address to be filled by guest linker */
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
+ tbl_off + 16, 4,
+ ACPI_BUILD_TABLE_FILE,
+ *rsdp_data->rsdt_tbl_offset);
+ }
+
+ /* Checksum to be filled by guest linker */
+ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
+ tbl_off, 20, /* ACPI rev 1.0 RSDP size */
+ 8);
+
+ if (rsdp_data->revision == 0) {
+ /* ACPI 1.0 RSDP, we're done */
+ return;
+ }
+
+ build_append_int_noprefix(tbl, 36, 4); /* Length */
+
+ /* XSDT address to be filled by guest linker */
+ build_append_int_noprefix(tbl, 0, 8); /* XsdtAddress */
+ /* We already validated our xsdt pointer */
+ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE,
+ tbl_off + 24, 8,
+ ACPI_BUILD_TABLE_FILE,
+ *rsdp_data->xsdt_tbl_offset);
+
+ build_append_int_noprefix(tbl, 0, 1); /* Extended Checksum */
+ build_append_int_noprefix(tbl, 0, 3); /* Reserved */
+
+ /* Extended checksum to be filled by Guest linker */
+ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
+ tbl_off, 36, /* ACPI rev 2.0 RSDP size */
+ 32);
+}
+
/* Build rsdt table */
void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
index aafdc61648..47877c0ec1 100644
--- a/hw/acpi/core.c
+++ b/hw/acpi/core.c
@@ -35,14 +35,18 @@
struct acpi_table_header {
uint16_t _length; /* our length, not actual part of the hdr */
/* allows easier parsing for fw_cfg clients */
- char sig[4]; /* ACPI signature (4 ASCII characters) */
+ char sig[4]
+ QEMU_NONSTRING; /* ACPI signature (4 ASCII characters) */
uint32_t length; /* Length of table, in bytes, including header */
uint8_t revision; /* ACPI Specification minor version # */
uint8_t checksum; /* To make sum of entire table == 0 */
- char oem_id[6]; /* OEM identification */
- char oem_table_id[8]; /* OEM table identification */
+ char oem_id[6]
+ QEMU_NONSTRING; /* OEM identification */
+ char oem_table_id[8]
+ QEMU_NONSTRING; /* OEM table identification */
uint32_t oem_revision; /* OEM revision number */
- char asl_compiler_id[4]; /* ASL compiler vendor ID */
+ char asl_compiler_id[4]
+ QEMU_NONSTRING; /* ASL compiler vendor ID */
uint32_t asl_compiler_revision; /* ASL compiler revision number */
} QEMU_PACKED;
@@ -514,7 +518,8 @@ static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
static void acpi_pm_tmr_timer(void *opaque)
{
ACPIREGS *ar = opaque;
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER);
+
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL);
ar->tmr.update_sci(ar);
}
@@ -617,6 +622,12 @@ void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
ar->pm1.cnt.s4_val = s4_val;
ar->wakeup.notify = acpi_notify_wakeup;
qemu_register_wakeup_notifier(&ar->wakeup);
+
+ /*
+ * Register wake-up support in QMP query-current-machine API
+ */
+ qemu_register_wakeup_support();
+
memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
&acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
index 8c7c1013f3..921cad2c5e 100644
--- a/hw/acpi/memory_hotplug.c
+++ b/hw/acpi/memory_hotplug.c
@@ -686,15 +686,15 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
method = aml_method("_OST", 3, AML_NOTSERIALIZED);
s = MEMORY_SLOT_OST_METHOD;
- aml_append(method, aml_return(aml_call4(
- s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
- )));
+ aml_append(method,
+ aml_call4(s, aml_name("_UID"), aml_arg(0),
+ aml_arg(1), aml_arg(2)));
aml_append(dev, method);
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
s = MEMORY_SLOT_EJECT_METHOD;
- aml_append(method, aml_return(aml_call2(
- s, aml_name("_UID"), aml_arg(0))));
+ aml_append(method,
+ aml_call2(s, aml_name("_UID"), aml_arg(0)));
aml_append(dev, method);
aml_append(dev_container, dev);
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 80d42e12ff..7bc7a72340 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -30,6 +30,7 @@
#include "hw/hw.h"
#include "hw/i386/pc.h"
#include "hw/pci/pci.h"
+#include "hw/pci/pci_bridge.h"
#include "hw/acpi/acpi.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
@@ -153,6 +154,7 @@ static bool acpi_pcihp_pc_no_hotplug(AcpiPciHpState *s, PCIDevice *dev)
static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slots)
{
+ HotplugHandler *hotplug_ctrl;
BusChild *kid, *next;
int slot = ctz32(slots);
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
@@ -170,7 +172,8 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
PCIDevice *dev = PCI_DEVICE(qdev);
if (PCI_SLOT(dev->devfn) == slot) {
if (!acpi_pcihp_pc_no_hotplug(s, dev)) {
- object_unparent(OBJECT(qdev));
+ hotplug_ctrl = qdev_get_hotplug_handler(qdev);
+ hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort);
}
}
}
@@ -217,25 +220,48 @@ void acpi_pcihp_reset(AcpiPciHpState *s)
acpi_pcihp_update(s);
}
-void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
- DeviceState *dev, Error **errp)
+void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
{
- PCIDevice *pdev = PCI_DEVICE(dev);
- int slot = PCI_SLOT(pdev->devfn);
- int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
- if (bsel < 0) {
+ /* Only hotplugged devices need the hotplug capability. */
+ if (dev->hotplugged &&
+ acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))) < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
+}
+
+void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
+ DeviceState *dev, Error **errp)
+{
+ PCIDevice *pdev = PCI_DEVICE(dev);
+ int slot = PCI_SLOT(pdev->devfn);
+ int bsel;
/* 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
* event when the device is disabled later. */
if (!dev->hotplugged) {
+ /*
+ * Overwrite the default hotplug handler with the ACPI PCI one
+ * for cold plugged bridges only.
+ */
+ if (!s->legacy_piix &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
+ PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
+
+ qbus_set_hotplug_handler(BUS(sec), DEVICE(hotplug_dev),
+ &error_abort);
+ /* We don't have to overwrite any other hotplug handler yet */
+ assert(QLIST_EMPTY(&sec->child));
+ }
+
return;
}
+ bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
+ g_assert(bsel >= 0);
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
}
@@ -243,6 +269,13 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
+ object_unparent(OBJECT(dev));
+}
+
+void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ AcpiPciHpState *s, DeviceState *dev,
+ Error **errp)
+{
PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index e330f24c71..88f9a9ec09 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -173,6 +173,7 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
PIIX4PMState *s = opaque;
pm_io_space_update(s);
+ smbus_io_space_update(s);
return 0;
}
@@ -370,6 +371,18 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
acpi_pm1_evt_power_down(&s->ar);
}
+static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
+ } else if (!object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ !object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ error_setg(errp, "acpi: device pre plug request for not supported"
+ " device type: %s", object_get_typename(OBJECT(dev)));
+ }
+}
+
static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -392,8 +405,7 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
}
} else {
- error_setg(errp, "acpi: device plug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ g_assert_not_reached();
}
}
@@ -407,8 +419,8 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug,
dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
- acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
- errp);
+ acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->acpi_pci_hotplug,
+ dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
!s->cpu_hotplug_legacy) {
acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
@@ -426,6 +438,9 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
if (s->acpi_memory_hotplug.is_enabled &&
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
+ errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
!s->cpu_hotplug_legacy) {
acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
@@ -435,15 +450,6 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
}
}
-static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
-{
- PIIX4PMState *s = opaque;
-
- /* pci_bus cannot outlive PIIX4PMState, because /machine keeps it alive
- * and it's not hot-unpluggable */
- qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort);
-}
-
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
@@ -457,12 +463,6 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
pci_conf[0x63] = 0x60;
pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
(memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
-
- if (s->use_acpi_pci_hotplug) {
- pci_for_each_bus(pci_get_bus(d), piix4_update_bus_hotplug, s);
- } else {
- piix4_update_bus_hotplug(pci_get_bus(d), s);
- }
}
static void piix4_pm_add_propeties(PIIX4PMState *s)
@@ -536,6 +536,7 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s);
+ qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), DEVICE(s), &error_abort);
piix4_pm_add_propeties(s);
}
@@ -702,6 +703,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
*/
dc->user_creatable = false;
dc->hotpluggable = false;
+ hc->pre_plug = piix4_device_pre_plug_cb;
hc->plug = piix4_device_plug_cb;
hc->unplug_request = piix4_device_unplug_request_cb;
hc->unplug = piix4_device_unplug_cb;
diff --git a/hw/acpi/tpm.c b/hw/acpi/tpm.c
new file mode 100644
index 0000000000..b96459e45b
--- /dev/null
+++ b/hw/acpi/tpm.c
@@ -0,0 +1,459 @@
+/* Support for generating ACPI TPM tables
+ *
+ * Copyright (C) 2018 IBM, Corp.
+ * Copyright (C) 2018 Red Hat Inc
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program 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 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 "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/acpi/tpm.h"
+
+void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)
+{
+ Aml *method, *field, *ifctx, *ifctx2, *ifctx3, *func_mask,
+ *not_implemented, *pak, *tpm2, *tpm3, *pprm, *pprq, *zero, *one;
+
+ if (!object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) {
+ return;
+ }
+
+ zero = aml_int(0);
+ one = aml_int(1);
+ func_mask = aml_int(TPM_PPI_FUNC_MASK);
+ not_implemented = aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED);
+
+ /*
+ * TPP2 is for the registers that ACPI code used to pass
+ * the PPI code and parameter (PPRQ, PPRM) to the firmware.
+ */
+ aml_append(dev,
+ aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
+ aml_int(TPM_PPI_ADDR_BASE + 0x100),
+ 0x5A));
+ field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
+ aml_append(field, aml_named_field("PPIN", 8));
+ aml_append(field, aml_named_field("PPIP", 32));
+ aml_append(field, aml_named_field("PPRP", 32));
+ aml_append(field, aml_named_field("PPRQ", 32));
+ aml_append(field, aml_named_field("PPRM", 32));
+ aml_append(field, aml_named_field("LPPR", 32));
+ aml_append(dev, field);
+ pprq = aml_name("PPRQ");
+ pprm = aml_name("PPRM");
+
+ aml_append(dev,
+ aml_operation_region(
+ "TPP3", AML_SYSTEM_MEMORY,
+ aml_int(TPM_PPI_ADDR_BASE +
+ 0x15a /* movv, docs/specs/tpm.txt */),
+ 0x1));
+ field = aml_field("TPP3", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
+ aml_append(field, aml_named_field("MOVV", 8));
+ aml_append(dev, field);
+
+ /*
+ * DerefOf in Windows is broken with SYSTEM_MEMORY. Use a dynamic
+ * operation region inside of a method for getting FUNC[op].
+ */
+ method = aml_method("TPFN", 1, AML_SERIALIZED);
+ {
+ Aml *op = aml_arg(0);
+ ifctx = aml_if(aml_lgreater_equal(op, aml_int(0x100)));
+ {
+ aml_append(ifctx, aml_return(zero));
+ }
+ aml_append(method, ifctx);
+
+ aml_append(method,
+ aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
+ aml_add(aml_int(TPM_PPI_ADDR_BASE), op, NULL), 0x1));
+ field = aml_field("TPP1", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
+ aml_append(field, aml_named_field("TPPF", 8));
+ aml_append(method, field);
+ aml_append(method, aml_return(aml_name("TPPF")));
+ }
+ aml_append(dev, method);
+
+ /*
+ * Use global TPM2 & TPM3 variables to workaround Windows ACPI bug
+ * when returning packages.
+ */
+ pak = aml_package(2);
+ aml_append(pak, zero);
+ aml_append(pak, zero);
+ aml_append(dev, aml_name_decl("TPM2", pak));
+ tpm2 = aml_name("TPM2");
+
+ pak = aml_package(3);
+ aml_append(pak, zero);
+ aml_append(pak, zero);
+ aml_append(pak, zero);
+ aml_append(dev, aml_name_decl("TPM3", pak));
+ tpm3 = aml_name("TPM3");
+
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ {
+ uint8_t zerobyte[1] = { 0 };
+ Aml *function, *arguments, *rev, *op, *op_arg, *op_flags, *uuid;
+
+ uuid = aml_arg(0);
+ rev = aml_arg(1);
+ function = aml_arg(2);
+ arguments = aml_arg(3);
+ op = aml_local(0);
+ op_flags = aml_local(1);
+
+ /* Physical Presence Interface */
+ ifctx = aml_if(
+ aml_equal(uuid,
+ aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
+ {
+ /* standard DSM query function */
+ ifctx2 = aml_if(aml_equal(function, zero));
+ {
+ uint8_t byte_list[2] = { 0xff, 0x01 }; /* functions 1-8 */
+
+ aml_append(ifctx2,
+ aml_return(aml_buffer(sizeof(byte_list),
+ byte_list)));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.1 Get Physical Presence Interface Version
+ *
+ * Arg 2 (Integer): Function Index = 1
+ * Arg 3 (Package): Arguments = Empty Package
+ * Returns: Type: String
+ */
+ ifctx2 = aml_if(aml_equal(function, one));
+ {
+ aml_append(ifctx2, aml_return(aml_string("1.3")));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.3 Submit TPM Operation Request to Pre-OS Environment
+ *
+ * Arg 2 (Integer): Function Index = 2
+ * Arg 3 (Package): Arguments = Package: Type: Integer
+ * Operation Value of the Request
+ * Returns: Type: Integer
+ * 0: Success
+ * 1: Operation Value of the Request Not Supported
+ * 2: General Failure
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(2)));
+ {
+ /* get opcode */
+ aml_append(ifctx2,
+ aml_store(aml_derefof(aml_index(arguments,
+ zero)), op));
+
+ /* get opcode flags */
+ aml_append(ifctx2,
+ aml_store(aml_call1("TPFN", op), op_flags));
+
+ /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
+ ifctx3 = aml_if(
+ aml_equal(
+ aml_and(op_flags, func_mask, NULL),
+ not_implemented));
+ {
+ /* 1: Operation Value of the Request Not Supported */
+ aml_append(ifctx3, aml_return(one));
+ }
+ aml_append(ifctx2, ifctx3);
+
+ aml_append(ifctx2, aml_store(op, pprq));
+ aml_append(ifctx2, aml_store(zero, pprm));
+ /* 0: success */
+ aml_append(ifctx2, aml_return(zero));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.4 Get Pending TPM Operation Requested By the OS
+ *
+ * Arg 2 (Integer): Function Index = 3
+ * Arg 3 (Package): Arguments = Empty Package
+ * Returns: Type: Package of Integers
+ * Integer 1: Function Return code
+ * 0: Success
+ * 1: General Failure
+ * Integer 2: Pending operation requested by the OS
+ * 0: None
+ * >0: Operation Value of the Pending Request
+ * Integer 3: Optional argument to pending operation
+ * requested by the OS
+ * 0: None
+ * >0: Argument Value of the Pending Request
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(3)));
+ {
+ /*
+ * Revision ID of 1, no integer parameter beyond
+ * parameter two are expected
+ */
+ ifctx3 = aml_if(aml_equal(rev, one));
+ {
+ /* TPM2[1] = PPRQ */
+ aml_append(ifctx3,
+ aml_store(pprq, aml_index(tpm2, one)));
+ aml_append(ifctx3, aml_return(tpm2));
+ }
+ aml_append(ifctx2, ifctx3);
+
+ /*
+ * A return value of {0, 23, 1} indicates that
+ * operation 23 with argument 1 is pending.
+ */
+ ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
+ {
+ /* TPM3[1] = PPRQ */
+ aml_append(ifctx3,
+ aml_store(pprq, aml_index(tpm3, one)));
+ /* TPM3[2] = PPRM */
+ aml_append(ifctx3,
+ aml_store(pprm, aml_index(tpm3, aml_int(2))));
+ aml_append(ifctx3, aml_return(tpm3));
+ }
+ aml_append(ifctx2, ifctx3);
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.5 Get Platform-Specific Action to Transition to
+ * Pre-OS Environment
+ *
+ * Arg 2 (Integer): Function Index = 4
+ * Arg 3 (Package): Arguments = Empty Package
+ * Returns: Type: Integer
+ * 0: None
+ * 1: Shutdown
+ * 2: Reboot
+ * 3: OS Vendor-specific
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(4)));
+ {
+ /* reboot */
+ aml_append(ifctx2, aml_return(aml_int(2)));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.6 Return TPM Operation Response to OS Environment
+ *
+ * Arg 2 (Integer): Function Index = 5
+ * Arg 3 (Package): Arguments = Empty Package
+ * Returns: Type: Package of Integer
+ * Integer 1: Function Return code
+ * 0: Success
+ * 1: General Failure
+ * Integer 2: Most recent operation request
+ * 0: None
+ * >0: Operation Value of the most recent request
+ * Integer 3: Response to the most recent operation request
+ * 0: Success
+ * 0x00000001..0x00000FFF: Corresponding TPM
+ * error code
+ * 0xFFFFFFF0: User Abort or timeout of dialog
+ * 0xFFFFFFF1: firmware Failure
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(5)));
+ {
+ /* TPM3[1] = LPPR */
+ aml_append(ifctx2,
+ aml_store(aml_name("LPPR"),
+ aml_index(tpm3, one)));
+ /* TPM3[2] = PPRP */
+ aml_append(ifctx2,
+ aml_store(aml_name("PPRP"),
+ aml_index(tpm3, aml_int(2))));
+ aml_append(ifctx2, aml_return(tpm3));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.0: 2.1.7 Submit preferred user language
+ *
+ * Arg 2 (Integer): Function Index = 6
+ * Arg 3 (Package): Arguments = String Package
+ * Preferred language code
+ * Returns: Type: Integer
+ * Function Return Code
+ * 3: Not implemented
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(6)));
+ {
+ /* 3 = not implemented */
+ aml_append(ifctx2, aml_return(aml_int(3)));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.1: 2.1.7 Submit TPM Operation Request to
+ * Pre-OS Environment 2
+ *
+ * Arg 2 (Integer): Function Index = 7
+ * Arg 3 (Package): Arguments = Package: Type: Integer
+ * Integer 1: Operation Value of the Request
+ * Integer 2: Argument for Operation (optional)
+ * Returns: Type: Integer
+ * 0: Success
+ * 1: Not Implemented
+ * 2: General Failure
+ * 3: Operation blocked by current firmware settings
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(7)));
+ {
+ /* get opcode */
+ aml_append(ifctx2, aml_store(aml_derefof(aml_index(arguments,
+ zero)),
+ op));
+
+ /* get opcode flags */
+ aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
+ op_flags));
+ /* if func[opcode] & TPM_PPI_FUNC_NOT_IMPLEMENTED */
+ ifctx3 = aml_if(
+ aml_equal(
+ aml_and(op_flags, func_mask, NULL),
+ not_implemented));
+ {
+ /* 1: not implemented */
+ aml_append(ifctx3, aml_return(one));
+ }
+ aml_append(ifctx2, ifctx3);
+
+ /* if func[opcode] & TPM_PPI_FUNC_BLOCKED */
+ ifctx3 = aml_if(
+ aml_equal(
+ aml_and(op_flags, func_mask, NULL),
+ aml_int(TPM_PPI_FUNC_BLOCKED)));
+ {
+ /* 3: blocked by firmware */
+ aml_append(ifctx3, aml_return(aml_int(3)));
+ }
+ aml_append(ifctx2, ifctx3);
+
+ /* revision to integer */
+ ifctx3 = aml_if(aml_equal(rev, one));
+ {
+ /* revision 1 */
+ /* PPRQ = op */
+ aml_append(ifctx3, aml_store(op, pprq));
+ /* no argument, PPRM = 0 */
+ aml_append(ifctx3, aml_store(zero, pprm));
+ }
+ aml_append(ifctx2, ifctx3);
+
+ ifctx3 = aml_if(aml_equal(rev, aml_int(2)));
+ {
+ /* revision 2 */
+ /* PPRQ = op */
+ op_arg = aml_derefof(aml_index(arguments, one));
+ aml_append(ifctx3, aml_store(op, pprq));
+ /* PPRM = arg3[1] */
+ aml_append(ifctx3, aml_store(op_arg, pprm));
+ }
+ aml_append(ifctx2, ifctx3);
+ /* 0: success */
+ aml_append(ifctx2, aml_return(zero));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * PPI 1.1: 2.1.8 Get User Confirmation Status for Operation
+ *
+ * Arg 2 (Integer): Function Index = 8
+ * Arg 3 (Package): Arguments = Package: Type: Integer
+ * Operation Value that may need user confirmation
+ * Returns: Type: Integer
+ * 0: Not implemented
+ * 1: Firmware only
+ * 2: Blocked for OS by firmware configuration
+ * 3: Allowed and physically present user required
+ * 4: Allowed and physically present user not required
+ */
+ ifctx2 = aml_if(aml_equal(function, aml_int(8)));
+ {
+ /* get opcode */
+ aml_append(ifctx2,
+ aml_store(aml_derefof(aml_index(arguments,
+ zero)),
+ op));
+
+ /* get opcode flags */
+ aml_append(ifctx2, aml_store(aml_call1("TPFN", op),
+ op_flags));
+ /* return confirmation status code */
+ aml_append(ifctx2,
+ aml_return(
+ aml_and(op_flags, func_mask, NULL)));
+ }
+ aml_append(ifctx, ifctx2);
+
+ aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
+ }
+ aml_append(method, ifctx);
+
+ /*
+ * "TCG Platform Reset Attack Mitigation Specification 1.00",
+ * Chapter 6 "ACPI _DSM Function"
+ */
+ ifctx = aml_if(
+ aml_equal(uuid,
+ aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
+ {
+ /* standard DSM query function */
+ ifctx2 = aml_if(aml_equal(function, zero));
+ {
+ uint8_t byte_list[1] = { 0x03 }; /* functions 1-2 supported */
+
+ aml_append(ifctx2,
+ aml_return(aml_buffer(sizeof(byte_list),
+ byte_list)));
+ }
+ aml_append(ifctx, ifctx2);
+
+ /*
+ * TCG Platform Reset Attack Mitigation Specification 1.0 Ch.6
+ *
+ * Arg 2 (Integer): Function Index = 1
+ * Arg 3 (Package): Arguments = Package: Type: Integer
+ * Operation Value of the Request
+ * Returns: Type: Integer
+ * 0: Success
+ * 1: General Failure
+ */
+ ifctx2 = aml_if(aml_equal(function, one));
+ {
+ aml_append(ifctx2,
+ aml_store(aml_derefof(aml_index(arguments, zero)),
+ op));
+ {
+ aml_append(ifctx2, aml_store(op, aml_name("MOVV")));
+
+ /* 0: success */
+ aml_append(ifctx2, aml_return(zero));
+ }
+ }
+ aml_append(ifctx, ifctx2);
+ }
+ aml_append(method, ifctx);
+ }
+ aml_append(dev, method);
+}
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
index 8004afe45b..397e2dcdc7 100644
--- a/hw/alpha/typhoon.c
+++ b/hw/alpha/typhoon.c
@@ -75,7 +75,9 @@ static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
}
}
-static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult cchip_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
{
CPUState *cpu = current_cpu;
TyphoonState *s = opaque;
@@ -196,11 +198,11 @@ static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
break;
default:
- cpu_unassigned_access(cpu, addr, false, false, 0, size);
- return -1;
+ return MEMTX_ERROR;
}
- return ret;
+ *data = ret;
+ return MEMTX_OK;
}
static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
@@ -209,7 +211,8 @@ static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
return 0;
}
-static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult pchip_read(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
{
TyphoonState *s = opaque;
uint64_t ret = 0;
@@ -294,15 +297,16 @@ static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
break;
default:
- cpu_unassigned_access(current_cpu, addr, false, false, 0, size);
- return -1;
+ return MEMTX_ERROR;
}
- return ret;
+ *data = ret;
+ return MEMTX_OK;
}
-static void cchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
+static MemTxResult cchip_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
{
TyphoonState *s = opaque;
uint64_t oldval, newval;
@@ -446,9 +450,10 @@ static void cchip_write(void *opaque, hwaddr addr,
break;
default:
- cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
- return;
+ return MEMTX_ERROR;
}
+
+ return MEMTX_OK;
}
static void dchip_write(void *opaque, hwaddr addr,
@@ -457,8 +462,9 @@ static void dchip_write(void *opaque, hwaddr addr,
/* Skip this. It's all related to DRAM timing and setup. */
}
-static void pchip_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
+static MemTxResult pchip_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
{
TyphoonState *s = opaque;
uint64_t oldval;
@@ -553,14 +559,15 @@ static void pchip_write(void *opaque, hwaddr addr,
break;
default:
- cpu_unassigned_access(current_cpu, addr, true, false, 0, size);
- return;
+ return MEMTX_ERROR;
}
+
+ return MEMTX_OK;
}
static const MemoryRegionOps cchip_ops = {
- .read = cchip_read,
- .write = cchip_write,
+ .read_with_attrs = cchip_read,
+ .write_with_attrs = cchip_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 8,
@@ -587,8 +594,8 @@ static const MemoryRegionOps dchip_ops = {
};
static const MemoryRegionOps pchip_ops = {
- .read = pchip_read,
- .write = pchip_write,
+ .read_with_attrs = pchip_read,
+ .write_with_attrs = pchip_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 8,
@@ -657,8 +664,8 @@ static bool window_translate(TyphoonWindow *win, hwaddr addr,
pte_addr |= (addr & (wsm | 0xfe000)) >> 10;
return pte_translate(pte_addr, ret);
} else {
- /* Direct-mapped translation. */
- return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
+ /* Direct-mapped translation. */
+ return make_iommu_tlbe(tba & ~wsm_ext, wsm_ext, ret);
}
}
@@ -693,7 +700,7 @@ static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
/* Check the fourth window for DAC disable. */
if ((pchip->win[3].wba & 0x80000000000ull) == 0
- && window_translate(&pchip->win[3], addr, &ret)) {
+ && window_translate(&pchip->win[3], addr, &ret)) {
goto success;
}
} else {
@@ -704,7 +711,7 @@ static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
if (pchip->ctl & 0x40) {
/* See 10.1.4.4; in particular <39:35> is ignored. */
make_iommu_tlbe(0, 0x007ffffffffull, &ret);
- goto success;
+ goto success;
}
}
@@ -716,8 +723,8 @@ static IOMMUTLBEntry typhoon_translate_iommu(IOMMUMemoryRegion *iommu,
pte_addr = pchip->win[3].tba & 0x7ffc00000ull;
pte_addr |= (addr & 0xffffe000u) >> 10;
if (pte_translate(pte_addr, &ret)) {
- goto success;
- }
+ goto success;
+ }
}
}
}
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 9fe875cdb5..df0d079ad0 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -22,6 +22,7 @@
#include "hw/sysbus.h"
#include "hw/devices.h"
#include "hw/arm/allwinner-a10.h"
+#include "hw/misc/unimp.h"
static void aw_a10_init(Object *obj)
{
@@ -85,6 +86,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(sysbusdev, 4, s->irq[67]);
sysbus_connect_irq(sysbusdev, 5, s->irq[68]);
+ memory_region_init_ram(&s->sram_a, OBJECT(dev), "sram A", 48 * KiB,
+ &error_fatal);
+ memory_region_add_subregion(get_system_memory(), 0x00000000, &s->sram_a);
+ create_unimplemented_device("a10-sram-ctrl", 0x01c00000, 4 * KiB);
+
/* FIXME use qdev NIC properties instead of nd_table[] */
if (nd_table[0].used) {
qemu_check_nic_model(&nd_table[0], TYPE_AW_EMAC);
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 4bf9131b81..f444652830 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -285,11 +285,6 @@ void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size)
big_endian = 0;
#endif
- if (!kernel_filename && !qtest_enabled()) {
- error_report("Guest image must be specified (using -kernel)");
- exit(1);
- }
-
if (arm_feature(&cpu->env, ARM_FEATURE_EL3)) {
asidx = ARMASIdx_S;
} else {
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 586baa9b64..c7a67af7a9 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -30,8 +30,9 @@
* Documentation/arm/Booting and Documentation/arm64/booting.txt
* They have different preferred image load offsets from system RAM base.
*/
-#define KERNEL_ARGS_ADDR 0x100
-#define KERNEL_LOAD_ADDR 0x00010000
+#define KERNEL_ARGS_ADDR 0x100
+#define KERNEL_NOLOAD_ADDR 0x02000000
+#define KERNEL_LOAD_ADDR 0x00010000
#define KERNEL64_LOAD_ADDR 0x00080000
#define ARM64_TEXT_OFFSET_OFFSET 8
@@ -63,8 +64,10 @@ typedef enum {
FIXUP_TERMINATOR, /* end of insns */
FIXUP_BOARDID, /* overwrite with board ID number */
FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
- FIXUP_ARGPTR, /* overwrite with pointer to kernel args */
- FIXUP_ENTRYPOINT, /* overwrite with kernel entry point */
+ FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */
+ FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */
+ FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */
+ FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */
FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
FIXUP_BOOTREG, /* overwrite with boot register address */
FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
@@ -83,10 +86,10 @@ static const ARMInsnFixup bootloader_aarch64[] = {
{ 0xaa1f03e3 }, /* mov x3, xzr */
{ 0x58000084 }, /* ldr x4, entry ; Load the lower 32-bits of kernel entry */
{ 0xd61f0080 }, /* br x4 ; Jump to the kernel entry point */
- { 0, FIXUP_ARGPTR }, /* arg: .word @DTB Lower 32-bits */
- { 0 }, /* .word @DTB Higher 32-bits */
- { 0, FIXUP_ENTRYPOINT }, /* entry: .word @Kernel Entry Lower 32-bits */
- { 0 }, /* .word @Kernel Entry Higher 32-bits */
+ { 0, FIXUP_ARGPTR_LO }, /* arg: .word @DTB Lower 32-bits */
+ { 0, FIXUP_ARGPTR_HI}, /* .word @DTB Higher 32-bits */
+ { 0, FIXUP_ENTRYPOINT_LO }, /* entry: .word @Kernel Entry Lower 32-bits */
+ { 0, FIXUP_ENTRYPOINT_HI }, /* .word @Kernel Entry Higher 32-bits */
{ 0, FIXUP_TERMINATOR }
};
@@ -106,8 +109,8 @@ static const ARMInsnFixup bootloader[] = {
{ 0xe59f2004 }, /* ldr r2, [pc, #4] */
{ 0xe59ff004 }, /* ldr pc, [pc, #4] */
{ 0, FIXUP_BOARDID },
- { 0, FIXUP_ARGPTR },
- { 0, FIXUP_ENTRYPOINT },
+ { 0, FIXUP_ARGPTR_LO },
+ { 0, FIXUP_ENTRYPOINT_LO },
{ 0, FIXUP_TERMINATOR }
};
@@ -174,8 +177,10 @@ static void write_bootloader(const char *name, hwaddr addr,
break;
case FIXUP_BOARDID:
case FIXUP_BOARD_SETUP:
- case FIXUP_ARGPTR:
- case FIXUP_ENTRYPOINT:
+ case FIXUP_ARGPTR_LO:
+ case FIXUP_ARGPTR_HI:
+ case FIXUP_ENTRYPOINT_LO:
+ case FIXUP_ENTRYPOINT_HI:
case FIXUP_GIC_CPU_IF:
case FIXUP_BOOTREG:
case FIXUP_DSB:
@@ -1078,7 +1083,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
entry = elf_entry;
if (kernel_size < 0) {
- kernel_size = load_uimage_as(info->kernel_filename, &entry, NULL,
+ uint64_t loadaddr = info->loader_start + KERNEL_NOLOAD_ADDR;
+ kernel_size = load_uimage_as(info->kernel_filename, &entry, &loadaddr,
&is_linux, NULL, NULL, as);
}
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) {
@@ -1152,9 +1158,13 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
/* Place the DTB after the initrd in memory with alignment. */
info->dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
align);
- fixupcontext[FIXUP_ARGPTR] = info->dtb_start;
+ fixupcontext[FIXUP_ARGPTR_LO] = info->dtb_start;
+ fixupcontext[FIXUP_ARGPTR_HI] = info->dtb_start >> 32;
} else {
- fixupcontext[FIXUP_ARGPTR] = info->loader_start + KERNEL_ARGS_ADDR;
+ fixupcontext[FIXUP_ARGPTR_LO] =
+ info->loader_start + KERNEL_ARGS_ADDR;
+ fixupcontext[FIXUP_ARGPTR_HI] =
+ (info->loader_start + KERNEL_ARGS_ADDR) >> 32;
if (info->ram_size >= (1ULL << 32)) {
error_report("RAM size must be less than 4GB to boot"
" Linux kernel using ATAGS (try passing a device tree"
@@ -1162,7 +1172,8 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
exit(1);
}
}
- fixupcontext[FIXUP_ENTRYPOINT] = entry;
+ fixupcontext[FIXUP_ENTRYPOINT_LO] = entry;
+ fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32;
write_bootloader("bootloader", info->loader_start,
primary_loader, fixupcontext, as);
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 6dd02ae47e..82b1d020a5 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -322,6 +322,7 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
"EXP_IRQ", 57 + i * 3));
+ g_free(mscname);
return sysbus_mmio_get_region(s, 0);
}
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 9648b3af44..d22532a11c 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -1147,14 +1147,13 @@ static const MemoryRegionOps mv88w8618_wlan_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int mv88w8618_wlan_init(SysBusDevice *dev)
+static void mv88w8618_wlan_realize(DeviceState *dev, Error **errp)
{
MemoryRegion *iomem = g_new(MemoryRegion, 1);
memory_region_init_io(iomem, OBJECT(dev), &mv88w8618_wlan_ops, NULL,
"musicpal-wlan", MP_WLAN_SIZE);
- sysbus_init_mmio(dev, iomem);
- return 0;
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), iomem);
}
/* GPIO register offsets */
@@ -1696,7 +1695,7 @@ static void musicpal_init(MachineState *machine)
dev = qdev_create(NULL, TYPE_MV88W8618_AUDIO);
s = SYS_BUS_DEVICE(dev);
object_property_set_link(OBJECT(dev), OBJECT(wm8750_dev),
- TYPE_WM8750, NULL);
+ "wm8750", NULL);
qdev_init_nofail(dev);
sysbus_mmio_map(s, 0, MP_AUDIO_BASE);
sysbus_connect_irq(s, 0, pic[MP_AUDIO_IRQ]);
@@ -1720,9 +1719,9 @@ DEFINE_MACHINE("musicpal", musicpal_machine_init)
static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = mv88w8618_wlan_init;
+ dc->realize = mv88w8618_wlan_realize;
}
static const TypeInfo mv88w8618_wlan_info = {
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index b89c1bdea0..1630c27594 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -21,35 +21,46 @@
#include "qemu/log.h"
#include "cpu.h"
+#include "hw/arm/nrf51.h"
#include "hw/arm/nrf51_soc.h"
-#define IOMEM_BASE 0x40000000
-#define IOMEM_SIZE 0x20000000
-
-#define FICR_BASE 0x10000000
-#define FICR_SIZE 0x000000fc
-
-#define FLASH_BASE 0x00000000
-#define SRAM_BASE 0x20000000
-
-#define PRIVATE_BASE 0xF0000000
-#define PRIVATE_SIZE 0x10000000
-
/*
* The size and base is for the NRF51822 part. If other parts
* are supported in the future, add a sub-class of NRF51SoC for
* the specific variants
*/
-#define NRF51822_FLASH_SIZE (256 * 1024)
-#define NRF51822_SRAM_SIZE (16 * 1024)
+#define NRF51822_FLASH_SIZE (256 * NRF51_PAGE_SIZE)
+#define NRF51822_SRAM_SIZE (16 * NRF51_PAGE_SIZE)
#define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
+static uint64_t clock_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
+ __func__, addr, size);
+ return 1;
+}
+
+static void clock_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
+ __func__, addr, data, size);
+}
+
+static const MemoryRegionOps clock_ops = {
+ .read = clock_read,
+ .write = clock_write
+};
+
+
static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
{
NRF51State *s = NRF51_SOC(dev_soc);
MemoryRegion *mr;
Error *err = NULL;
+ uint8_t i = 0;
+ hwaddr base_addr = 0;
if (!s->board_memory) {
error_setg(errp, "memory property was not set");
@@ -76,14 +87,14 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
error_propagate(errp, err);
return;
}
- memory_region_add_subregion(&s->container, FLASH_BASE, &s->flash);
+ memory_region_add_subregion(&s->container, NRF51_FLASH_BASE, &s->flash);
memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
}
- memory_region_add_subregion(&s->container, SRAM_BASE, &s->sram);
+ memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram);
/* UART */
object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
@@ -92,19 +103,71 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
- memory_region_add_subregion_overlap(&s->container, UART_BASE, mr, 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_UART_BASE, mr, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
qdev_get_gpio_in(DEVICE(&s->cpu),
- BASE_TO_IRQ(UART_BASE)));
+ BASE_TO_IRQ(NRF51_UART_BASE)));
+
+ /* RNG */
+ object_property_set_bool(OBJECT(&s->rng), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_RNG_BASE, mr, 0);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rng), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu),
+ BASE_TO_IRQ(NRF51_RNG_BASE)));
+
+ /* GPIO */
+ object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_GPIO_BASE, mr, 0);
+
+ /* Pass all GPIOs to the SOC layer so they are available to the board */
+ qdev_pass_gpios(DEVICE(&s->gpio), dev_soc, NULL);
+
+ /* TIMER */
+ for (i = 0; i < NRF51_NUM_TIMERS; i++) {
+ object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ base_addr = NRF51_TIMER_BASE + i * NRF51_TIMER_SIZE;
- create_unimplemented_device("nrf51_soc.io", IOMEM_BASE, IOMEM_SIZE);
- create_unimplemented_device("nrf51_soc.ficr", FICR_BASE, FICR_SIZE);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer[i]), 0, base_addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu),
+ BASE_TO_IRQ(base_addr)));
+ }
+
+ /* STUB Peripherals */
+ memory_region_init_io(&s->clock, NULL, &clock_ops, NULL,
+ "nrf51_soc.clock", 0x1000);
+ memory_region_add_subregion_overlap(&s->container,
+ NRF51_IOMEM_BASE, &s->clock, -1);
+
+ create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
+ NRF51_IOMEM_SIZE);
+ create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
+ NRF51_FICR_SIZE);
create_unimplemented_device("nrf51_soc.private",
- PRIVATE_BASE, PRIVATE_SIZE);
+ NRF51_PRIVATE_BASE, NRF51_PRIVATE_SIZE);
}
static void nrf51_soc_init(Object *obj)
{
+ uint8_t i = 0;
+
NRF51State *s = NRF51_SOC(obj);
memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX);
@@ -119,6 +182,18 @@ static void nrf51_soc_init(Object *obj)
TYPE_NRF51_UART);
object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev",
&error_abort);
+
+ sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng),
+ TYPE_NRF51_RNG);
+
+ sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
+ TYPE_NRF51_GPIO);
+
+ for (i = 0; i < NRF51_NUM_TIMERS; i++) {
+ sysbus_init_child_obj(obj, "timer[*]", &s->timer[i],
+ sizeof(s->timer[i]), TYPE_NRF51_TIMER);
+
+ }
}
static Property nrf51_soc_properties[] = {
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index 6c69ce79b2..442529cc65 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -131,7 +131,7 @@ static void gptm_tick(void *opaque)
s->state |= 1;
if ((s->control & 0x20)) {
/* Output trigger. */
- qemu_irq_pulse(s->trigger);
+ qemu_irq_pulse(s->trigger);
}
if (s->mode[0] & 1) {
/* One-shot. */
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 5785fb697c..04b62c714d 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -366,36 +366,6 @@ static void acpi_dsdt_add_power_button(Aml *scope)
aml_append(scope, dev);
}
-/* RSDP */
-static GArray *
-build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned xsdt_tbl_offset)
-{
- AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
- unsigned xsdt_pa_size = sizeof(rsdp->xsdt_physical_address);
- unsigned xsdt_pa_offset =
- (char *)&rsdp->xsdt_physical_address - rsdp_table->data;
-
- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16,
- true /* fseg memory */);
-
- memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
- memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id));
- rsdp->length = cpu_to_le32(sizeof(*rsdp));
- rsdp->revision = 0x02;
-
- /* Address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker,
- ACPI_BUILD_RSDP_FILE, xsdt_pa_offset, xsdt_pa_size,
- ACPI_BUILD_TABLE_FILE, xsdt_tbl_offset);
-
- /* Checksum to be filled by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
- (char *)rsdp - rsdp_table->data, sizeof *rsdp,
- (char *)&rsdp->checksum - rsdp_table->data);
-
- return rsdp_table;
-}
-
static void
build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
@@ -448,6 +418,7 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
smmu->mapping_count = cpu_to_le32(1);
smmu->mapping_offset = cpu_to_le32(sizeof(*smmu));
smmu->base_address = cpu_to_le64(vms->memmap[VIRT_SMMU].base);
+ smmu->flags = cpu_to_le32(ACPI_IORT_SMMU_V3_COHACC_OVERRIDE);
smmu->event_gsiv = cpu_to_le32(irq);
smmu->pri_gsiv = cpu_to_le32(irq + 1);
smmu->gerr_gsiv = cpu_to_le32(irq + 2);
@@ -854,7 +825,15 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
build_xsdt(tables_blob, tables->linker, table_offsets, NULL, NULL);
/* RSDP is in FSEG memory, so allocate it separately */
- build_rsdp(tables->rsdp, tables->linker, xsdt);
+ {
+ AcpiRsdpData rsdp_data = {
+ .revision = 2,
+ .oem_id = ACPI_BUILD_APPNAME6,
+ .xsdt_tbl_offset = &xsdt,
+ .rsdt_tbl_offset = NULL,
+ };
+ build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+ }
/* Cleanup memory that's no longer used. */
g_array_free(table_offsets, true);
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index f69e7eb399..99c2b6e60d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -43,7 +43,6 @@
#include "sysemu/numa.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
-#include "hw/compat.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
#include "qemu/bitops.h"
@@ -55,7 +54,7 @@
#include "hw/intc/arm_gic.h"
#include "hw/intc/arm_gicv3_common.h"
#include "kvm_arm.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
@@ -74,7 +73,6 @@
static const TypeInfo machvirt_##major##_##minor##_info = { \
.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
.parent = TYPE_VIRT_MACHINE, \
- .instance_init = virt_##major##_##minor##_instance_init, \
.class_init = virt_##major##_##minor##_class_init, \
}; \
static void machvirt_machine_##major##_##minor##_init(void) \
@@ -1778,26 +1776,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
hc->plug = virt_machine_device_plug_cb;
}
-static const TypeInfo virt_machine_info = {
- .name = TYPE_VIRT_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(VirtMachineState),
- .class_size = sizeof(VirtMachineClass),
- .class_init = virt_machine_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
- },
-};
-
-static void machvirt_machine_init(void)
-{
- type_register_static(&virt_machine_info);
-}
-type_init(machvirt_machine_init);
-
-static void virt_3_1_instance_init(Object *obj)
+static void virt_instance_init(Object *obj)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
@@ -1867,109 +1846,88 @@ static void virt_3_1_instance_init(Object *obj)
vms->irqmap = a15irqmap;
}
-static void virt_machine_3_1_options(MachineClass *mc)
+static const TypeInfo virt_machine_info = {
+ .name = TYPE_VIRT_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(VirtMachineState),
+ .class_size = sizeof(VirtMachineClass),
+ .class_init = virt_machine_class_init,
+ .instance_init = virt_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
+};
+
+static void machvirt_machine_init(void)
{
+ type_register_static(&virt_machine_info);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(3, 1)
+type_init(machvirt_machine_init);
-#define VIRT_COMPAT_3_0 \
- HW_COMPAT_3_0
+static void virt_machine_4_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(4, 0)
-static void virt_3_0_instance_init(Object *obj)
+static void virt_machine_3_1_options(MachineClass *mc)
{
- virt_3_1_instance_init(obj);
+ virt_machine_4_0_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
}
+DEFINE_VIRT_MACHINE(3, 1)
static void virt_machine_3_0_options(MachineClass *mc)
{
virt_machine_3_1_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_3_0);
+ compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
}
DEFINE_VIRT_MACHINE(3, 0)
-#define VIRT_COMPAT_2_12 \
- HW_COMPAT_2_12
-
-static void virt_2_12_instance_init(Object *obj)
-{
- virt_3_0_instance_init(obj);
-}
-
static void virt_machine_2_12_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_3_0_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_12);
+ compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
vmc->no_highmem_ecam = true;
mc->max_cpus = 255;
}
DEFINE_VIRT_MACHINE(2, 12)
-#define VIRT_COMPAT_2_11 \
- HW_COMPAT_2_11
-
-static void virt_2_11_instance_init(Object *obj)
-{
- virt_2_12_instance_init(obj);
-}
-
static void virt_machine_2_11_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_12_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_11);
+ compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
vmc->smbios_old_sys_ver = true;
}
DEFINE_VIRT_MACHINE(2, 11)
-#define VIRT_COMPAT_2_10 \
- HW_COMPAT_2_10
-
-static void virt_2_10_instance_init(Object *obj)
-{
- virt_2_11_instance_init(obj);
-}
-
static void virt_machine_2_10_options(MachineClass *mc)
{
virt_machine_2_11_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_10);
+ compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
/* before 2.11 we never faulted accesses to bad addresses */
mc->ignore_memory_transaction_failures = true;
}
DEFINE_VIRT_MACHINE(2, 10)
-#define VIRT_COMPAT_2_9 \
- HW_COMPAT_2_9
-
-static void virt_2_9_instance_init(Object *obj)
-{
- virt_2_10_instance_init(obj);
-}
-
static void virt_machine_2_9_options(MachineClass *mc)
{
virt_machine_2_10_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_9);
+ compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
}
DEFINE_VIRT_MACHINE(2, 9)
-#define VIRT_COMPAT_2_8 \
- HW_COMPAT_2_8
-
-static void virt_2_8_instance_init(Object *obj)
-{
- virt_2_9_instance_init(obj);
-}
-
static void virt_machine_2_8_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_9_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_8);
+ compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
/* For 2.8 and earlier we falsely claimed in the DT that
* our timers were edge-triggered, not level-triggered.
*/
@@ -1977,20 +1935,12 @@ static void virt_machine_2_8_options(MachineClass *mc)
}
DEFINE_VIRT_MACHINE(2, 8)
-#define VIRT_COMPAT_2_7 \
- HW_COMPAT_2_7
-
-static void virt_2_7_instance_init(Object *obj)
-{
- virt_2_8_instance_init(obj);
-}
-
static void virt_machine_2_7_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_8_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_7);
+ compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
/* ITS was introduced with 2.8 */
vmc->no_its = true;
/* Stick with 1K pages for migration compatibility */
@@ -1998,20 +1948,12 @@ static void virt_machine_2_7_options(MachineClass *mc)
}
DEFINE_VIRT_MACHINE(2, 7)
-#define VIRT_COMPAT_2_6 \
- HW_COMPAT_2_6
-
-static void virt_2_6_instance_init(Object *obj)
-{
- virt_2_7_instance_init(obj);
-}
-
static void virt_machine_2_6_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_2_7_options(mc);
- SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_6);
+ compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
vmc->disallow_affinity_adjustment = true;
/* Disable PMU for 2.6 as PMU support was first introduced in 2.7 */
vmc->no_pmu = true;
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 1e31a3f442..f95fde2309 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -130,6 +130,7 @@ static void fdt_add_gic_nodes(VersalVirt *s)
2, MM_GIC_APU_REDIST_0_SIZE);
qemu_fdt_setprop_cell(s->fdt, nodename, "#interrupt-cells", 3);
qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "arm,gic-v3");
+ g_free(nodename);
}
static void fdt_add_timer_nodes(VersalVirt *s)
@@ -342,7 +343,7 @@ static void *versal_virt_get_dtb(const struct arm_boot_info *binfo,
return board->fdt;
}
-#define NUM_VIRTIO_TRANSPORT 32
+#define NUM_VIRTIO_TRANSPORT 8
static void create_virtio_regions(VersalVirt *s)
{
int virtio_mmio_size = 0x200;
@@ -351,7 +352,7 @@ static void create_virtio_regions(VersalVirt *s)
for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
char *name = g_strdup_printf("virtio%d", i);;
hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size;
- int irq = VERSAL_RSVD_HIGH_IRQ_FIRST + i;
+ int irq = VERSAL_RSVD_IRQ_FIRST + i;
MemoryRegion *mr;
DeviceState *dev;
qemu_irq pic_irq;
@@ -364,12 +365,12 @@ static void create_virtio_regions(VersalVirt *s)
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq);
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->soc.mr_ps, base, mr);
- sysbus_create_simple("virtio-mmio", base, pic_irq);
+ g_free(name);
}
for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) {
hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size;
- int irq = VERSAL_RSVD_HIGH_IRQ_FIRST + i;
+ int irq = VERSAL_RSVD_IRQ_FIRST + i;
char *name = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
qemu_fdt_add_subnode(s->fdt, name);
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index c195040350..c67ac2e64a 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -178,12 +178,19 @@ static void xlnx_zynqmp_create_rpu(XlnxZynqMPState *s, const char *boot_cpu,
int i;
int num_rpus = MIN(smp_cpus - XLNX_ZYNQMP_NUM_APU_CPUS, XLNX_ZYNQMP_NUM_RPU_CPUS);
+ object_initialize_child(OBJECT(s), "rpu-cluster", &s->rpu_cluster,
+ sizeof(s->rpu_cluster), TYPE_CPU_CLUSTER,
+ &error_abort, NULL);
+ qdev_prop_set_uint32(DEVICE(&s->rpu_cluster), "cluster-id", 1);
+
+ qdev_init_nofail(DEVICE(&s->rpu_cluster));
+
for (i = 0; i < num_rpus; i++) {
char *name;
object_initialize(&s->rpu_cpu[i], sizeof(s->rpu_cpu[i]),
"cortex-r5f-" TYPE_ARM_CPU);
- object_property_add_child(OBJECT(s), "rpu-cpu[*]",
+ object_property_add_child(OBJECT(&s->rpu_cluster), "rpu-cpu[*]",
OBJECT(&s->rpu_cpu[i]), &error_abort);
name = object_get_canonical_path_component(OBJECT(&s->rpu_cpu[i]));
@@ -213,10 +220,16 @@ static void xlnx_zynqmp_init(Object *obj)
int i;
int num_apus = MIN(smp_cpus, XLNX_ZYNQMP_NUM_APU_CPUS);
+ object_initialize_child(obj, "apu-cluster", &s->apu_cluster,
+ sizeof(s->apu_cluster), TYPE_CPU_CLUSTER,
+ &error_abort, NULL);
+ qdev_prop_set_uint32(DEVICE(&s->apu_cluster), "cluster-id", 0);
+
for (i = 0; i < num_apus; i++) {
- object_initialize_child(obj, "apu-cpu[*]", &s->apu_cpu[i],
- sizeof(s->apu_cpu[i]),
- "cortex-a53-" TYPE_ARM_CPU, &error_abort, NULL);
+ object_initialize_child(OBJECT(&s->apu_cluster), "apu-cpu[*]",
+ &s->apu_cpu[i], sizeof(s->apu_cpu[i]),
+ "cortex-a53-" TYPE_ARM_CPU, &error_abort,
+ NULL);
}
sysbus_init_child_obj(obj, "gic", &s->gic, sizeof(s->gic),
@@ -333,6 +346,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
qdev_prop_set_bit(DEVICE(&s->gic),
"has-virtualization-extensions", s->virt);
+ qdev_init_nofail(DEVICE(&s->apu_cluster));
+
/* Realize APUs before realizing the GIC. KVM requires this. */
for (i = 0; i < num_apus; i++) {
char *name;
diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c
index 6600ab4851..035dd76cbf 100644
--- a/hw/audio/marvell_88w8618.c
+++ b/hw/audio/marvell_88w8618.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/hw.h"
-#include "hw/i2c/i2c.h"
#include "hw/audio/wm8750.h"
#include "audio/audio.h"
#include "qapi/error.h"
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
index 53ce5751ae..e206b8e712 100644
--- a/hw/block/Makefile.objs
+++ b/hw/block/Makefile.objs
@@ -4,7 +4,7 @@ common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
common-obj-$(CONFIG_NAND) += nand.o
common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
-common-obj-$(CONFIG_XEN) += xen_disk.o
+common-obj-$(CONFIG_XEN) += xen-block.o
common-obj-$(CONFIG_ECC) += ecc.o
common-obj-$(CONFIG_ONENAND) += onenand.o
common-obj-$(CONFIG_NVME_PCI) += nvme.o
diff --git a/hw/block/dataplane/Makefile.objs b/hw/block/dataplane/Makefile.objs
index e786f66421..c6c68dbc00 100644
--- a/hw/block/dataplane/Makefile.objs
+++ b/hw/block/dataplane/Makefile.objs
@@ -1 +1,2 @@
obj-y += virtio-blk.o
+obj-$(CONFIG_XEN) += xen-block.o
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
new file mode 100644
index 0000000000..d0d8905a33
--- /dev/null
+++ b/hw/block/dataplane/xen-block.c
@@ -0,0 +1,827 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ * (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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.
+ *
+ * This program 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 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/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "hw/xen/xen_common.h"
+#include "hw/block/xen_blkif.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/iothread.h"
+#include "xen-block.h"
+
+typedef struct XenBlockRequest {
+ blkif_request_t req;
+ int16_t status;
+ off_t start;
+ QEMUIOVector v;
+ void *buf;
+ size_t size;
+ int presync;
+ int aio_inflight;
+ int aio_errors;
+ XenBlockDataPlane *dataplane;
+ QLIST_ENTRY(XenBlockRequest) list;
+ BlockAcctCookie acct;
+} XenBlockRequest;
+
+struct XenBlockDataPlane {
+ XenDevice *xendev;
+ XenEventChannel *event_channel;
+ unsigned int *ring_ref;
+ unsigned int nr_ring_ref;
+ void *sring;
+ int64_t file_blk;
+ int64_t file_size;
+ int protocol;
+ blkif_back_rings_t rings;
+ int more_work;
+ QLIST_HEAD(inflight_head, XenBlockRequest) inflight;
+ QLIST_HEAD(freelist_head, XenBlockRequest) freelist;
+ int requests_total;
+ int requests_inflight;
+ unsigned int max_requests;
+ BlockBackend *blk;
+ QEMUBH *bh;
+ IOThread *iothread;
+ AioContext *ctx;
+};
+
+static void reset_request(XenBlockRequest *request)
+{
+ memset(&request->req, 0, sizeof(request->req));
+ request->status = 0;
+ request->start = 0;
+ request->size = 0;
+ request->presync = 0;
+
+ request->aio_inflight = 0;
+ request->aio_errors = 0;
+
+ request->dataplane = NULL;
+ memset(&request->list, 0, sizeof(request->list));
+ memset(&request->acct, 0, sizeof(request->acct));
+
+ qemu_iovec_reset(&request->v);
+}
+
+static XenBlockRequest *xen_block_start_request(XenBlockDataPlane *dataplane)
+{
+ XenBlockRequest *request = NULL;
+
+ if (QLIST_EMPTY(&dataplane->freelist)) {
+ if (dataplane->requests_total >= dataplane->max_requests) {
+ goto out;
+ }
+ /* allocate new struct */
+ request = g_malloc0(sizeof(*request));
+ request->dataplane = dataplane;
+ /*
+ * We cannot need more pages per requests than this, and since we
+ * re-use requests, allocate the memory once here. It will be freed
+ * xen_block_dataplane_destroy() when the request list is freed.
+ */
+ request->buf = qemu_memalign(XC_PAGE_SIZE,
+ BLKIF_MAX_SEGMENTS_PER_REQUEST *
+ XC_PAGE_SIZE);
+ dataplane->requests_total++;
+ qemu_iovec_init(&request->v, 1);
+ } else {
+ /* get one from freelist */
+ request = QLIST_FIRST(&dataplane->freelist);
+ QLIST_REMOVE(request, list);
+ }
+ QLIST_INSERT_HEAD(&dataplane->inflight, request, list);
+ dataplane->requests_inflight++;
+
+out:
+ return request;
+}
+
+static void xen_block_finish_request(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+
+ QLIST_REMOVE(request, list);
+ dataplane->requests_inflight--;
+}
+
+static void xen_block_release_request(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+
+ QLIST_REMOVE(request, list);
+ reset_request(request);
+ request->dataplane = dataplane;
+ QLIST_INSERT_HEAD(&dataplane->freelist, request, list);
+ dataplane->requests_inflight--;
+}
+
+/*
+ * translate request into iovec + start offset
+ * do sanity checks along the way
+ */
+static int xen_block_parse_request(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+ size_t len;
+ int i;
+
+ switch (request->req.operation) {
+ case BLKIF_OP_READ:
+ break;
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ request->presync = 1;
+ if (!request->req.nr_segments) {
+ return 0;
+ }
+ /* fall through */
+ case BLKIF_OP_WRITE:
+ break;
+ case BLKIF_OP_DISCARD:
+ return 0;
+ default:
+ error_report("error: unknown operation (%d)", request->req.operation);
+ goto err;
+ };
+
+ if (request->req.operation != BLKIF_OP_READ &&
+ blk_is_read_only(dataplane->blk)) {
+ error_report("error: write req for ro device");
+ goto err;
+ }
+
+ request->start = request->req.sector_number * dataplane->file_blk;
+ for (i = 0; i < request->req.nr_segments; i++) {
+ if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ error_report("error: nr_segments too big");
+ goto err;
+ }
+ if (request->req.seg[i].first_sect > request->req.seg[i].last_sect) {
+ error_report("error: first > last sector");
+ goto err;
+ }
+ if (request->req.seg[i].last_sect * dataplane->file_blk >=
+ XC_PAGE_SIZE) {
+ error_report("error: page crossing");
+ goto err;
+ }
+
+ len = (request->req.seg[i].last_sect -
+ request->req.seg[i].first_sect + 1) * dataplane->file_blk;
+ request->size += len;
+ }
+ if (request->start + request->size > dataplane->file_size) {
+ error_report("error: access beyond end of file");
+ goto err;
+ }
+ return 0;
+
+err:
+ request->status = BLKIF_RSP_ERROR;
+ return -1;
+}
+
+static int xen_block_copy_request(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+ XenDevice *xendev = dataplane->xendev;
+ XenDeviceGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int i, count;
+ int64_t file_blk = dataplane->file_blk;
+ bool to_domain = (request->req.operation == BLKIF_OP_READ);
+ void *virt = request->buf;
+ Error *local_err = NULL;
+
+ if (request->req.nr_segments == 0) {
+ return 0;
+ }
+
+ count = request->req.nr_segments;
+
+ for (i = 0; i < count; i++) {
+ if (to_domain) {
+ segs[i].dest.foreign.ref = request->req.seg[i].gref;
+ segs[i].dest.foreign.offset = request->req.seg[i].first_sect *
+ file_blk;
+ segs[i].source.virt = virt;
+ } else {
+ segs[i].source.foreign.ref = request->req.seg[i].gref;
+ segs[i].source.foreign.offset = request->req.seg[i].first_sect *
+ file_blk;
+ segs[i].dest.virt = virt;
+ }
+ segs[i].len = (request->req.seg[i].last_sect -
+ request->req.seg[i].first_sect + 1) * file_blk;
+ virt += segs[i].len;
+ }
+
+ xen_device_copy_grant_refs(xendev, to_domain, segs, count, &local_err);
+
+ if (local_err) {
+ error_reportf_err(local_err, "failed to copy data: ");
+
+ request->aio_errors++;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int xen_block_do_aio(XenBlockRequest *request);
+static int xen_block_send_response(XenBlockRequest *request);
+
+static void xen_block_complete_aio(void *opaque, int ret)
+{
+ XenBlockRequest *request = opaque;
+ XenBlockDataPlane *dataplane = request->dataplane;
+
+ aio_context_acquire(dataplane->ctx);
+
+ if (ret != 0) {
+ error_report("%s I/O error",
+ request->req.operation == BLKIF_OP_READ ?
+ "read" : "write");
+ request->aio_errors++;
+ }
+
+ request->aio_inflight--;
+ if (request->presync) {
+ request->presync = 0;
+ xen_block_do_aio(request);
+ goto done;
+ }
+ if (request->aio_inflight > 0) {
+ goto done;
+ }
+
+ switch (request->req.operation) {
+ case BLKIF_OP_READ:
+ /* in case of failure request->aio_errors is increased */
+ if (ret == 0) {
+ xen_block_copy_request(request);
+ }
+ break;
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (!request->req.nr_segments) {
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+ xen_block_finish_request(request);
+
+ switch (request->req.operation) {
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (!request->req.nr_segments) {
+ break;
+ }
+ case BLKIF_OP_READ:
+ if (request->status == BLKIF_RSP_OKAY) {
+ block_acct_done(blk_get_stats(dataplane->blk), &request->acct);
+ } else {
+ block_acct_failed(blk_get_stats(dataplane->blk), &request->acct);
+ }
+ break;
+ case BLKIF_OP_DISCARD:
+ default:
+ break;
+ }
+ if (xen_block_send_response(request)) {
+ Error *local_err = NULL;
+
+ xen_device_notify_event_channel(dataplane->xendev,
+ dataplane->event_channel,
+ &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+ xen_block_release_request(request);
+
+ qemu_bh_schedule(dataplane->bh);
+
+done:
+ aio_context_release(dataplane->ctx);
+}
+
+static bool xen_block_split_discard(XenBlockRequest *request,
+ blkif_sector_t sector_number,
+ uint64_t nr_sectors)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+ int64_t byte_offset;
+ int byte_chunk;
+ uint64_t byte_remaining, limit;
+ uint64_t sec_start = sector_number;
+ uint64_t sec_count = nr_sectors;
+
+ /* Wrap around, or overflowing byte limit? */
+ if (sec_start + sec_count < sec_count ||
+ sec_start + sec_count > INT64_MAX / dataplane->file_blk) {
+ return false;
+ }
+
+ limit = BDRV_REQUEST_MAX_SECTORS * dataplane->file_blk;
+ byte_offset = sec_start * dataplane->file_blk;
+ byte_remaining = sec_count * dataplane->file_blk;
+
+ do {
+ byte_chunk = byte_remaining > limit ? limit : byte_remaining;
+ request->aio_inflight++;
+ blk_aio_pdiscard(dataplane->blk, byte_offset, byte_chunk,
+ xen_block_complete_aio, request);
+ byte_remaining -= byte_chunk;
+ byte_offset += byte_chunk;
+ } while (byte_remaining > 0);
+
+ return true;
+}
+
+static int xen_block_do_aio(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+
+ if (request->req.nr_segments &&
+ (request->req.operation == BLKIF_OP_WRITE ||
+ request->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+ xen_block_copy_request(request)) {
+ goto err;
+ }
+
+ request->aio_inflight++;
+ if (request->presync) {
+ blk_aio_flush(request->dataplane->blk, xen_block_complete_aio,
+ request);
+ return 0;
+ }
+
+ switch (request->req.operation) {
+ case BLKIF_OP_READ:
+ qemu_iovec_add(&request->v, request->buf, request->size);
+ block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
+ request->v.size, BLOCK_ACCT_READ);
+ request->aio_inflight++;
+ blk_aio_preadv(dataplane->blk, request->start, &request->v, 0,
+ xen_block_complete_aio, request);
+ break;
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (!request->req.nr_segments) {
+ break;
+ }
+
+ qemu_iovec_add(&request->v, request->buf, request->size);
+ block_acct_start(blk_get_stats(dataplane->blk), &request->acct,
+ request->v.size,
+ request->req.operation == BLKIF_OP_WRITE ?
+ BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
+ request->aio_inflight++;
+ blk_aio_pwritev(dataplane->blk, request->start, &request->v, 0,
+ xen_block_complete_aio, request);
+ break;
+ case BLKIF_OP_DISCARD:
+ {
+ struct blkif_request_discard *req = (void *)&request->req;
+ if (!xen_block_split_discard(request, req->sector_number,
+ req->nr_sectors)) {
+ goto err;
+ }
+ break;
+ }
+ default:
+ /* unknown operation (shouldn't happen -- parse catches this) */
+ goto err;
+ }
+
+ xen_block_complete_aio(request, 0);
+
+ return 0;
+
+err:
+ xen_block_finish_request(request);
+ request->status = BLKIF_RSP_ERROR;
+ return -1;
+}
+
+static int xen_block_send_response(XenBlockRequest *request)
+{
+ XenBlockDataPlane *dataplane = request->dataplane;
+ int send_notify = 0;
+ int have_requests = 0;
+ blkif_response_t *resp;
+
+ /* Place on the response ring for the relevant domain. */
+ switch (dataplane->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ resp = (blkif_response_t *)RING_GET_RESPONSE(
+ &dataplane->rings.native,
+ dataplane->rings.native.rsp_prod_pvt);
+ break;
+ case BLKIF_PROTOCOL_X86_32:
+ resp = (blkif_response_t *)RING_GET_RESPONSE(
+ &dataplane->rings.x86_32_part,
+ dataplane->rings.x86_32_part.rsp_prod_pvt);
+ break;
+ case BLKIF_PROTOCOL_X86_64:
+ resp = (blkif_response_t *)RING_GET_RESPONSE(
+ &dataplane->rings.x86_64_part,
+ dataplane->rings.x86_64_part.rsp_prod_pvt);
+ break;
+ default:
+ return 0;
+ }
+
+ resp->id = request->req.id;
+ resp->operation = request->req.operation;
+ resp->status = request->status;
+
+ dataplane->rings.common.rsp_prod_pvt++;
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&dataplane->rings.common,
+ send_notify);
+ if (dataplane->rings.common.rsp_prod_pvt ==
+ dataplane->rings.common.req_cons) {
+ /*
+ * Tail check for pending requests. Allows frontend to avoid
+ * notifications if requests are already in flight (lower
+ * overheads and promotes batching).
+ */
+ RING_FINAL_CHECK_FOR_REQUESTS(&dataplane->rings.common,
+ have_requests);
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(&dataplane->rings.common)) {
+ have_requests = 1;
+ }
+
+ if (have_requests) {
+ dataplane->more_work++;
+ }
+ return send_notify;
+}
+
+static int xen_block_get_request(XenBlockDataPlane *dataplane,
+ XenBlockRequest *request, RING_IDX rc)
+{
+ switch (dataplane->protocol) {
+ case BLKIF_PROTOCOL_NATIVE: {
+ blkif_request_t *req =
+ RING_GET_REQUEST(&dataplane->rings.native, rc);
+
+ memcpy(&request->req, req, sizeof(request->req));
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32: {
+ blkif_x86_32_request_t *req =
+ RING_GET_REQUEST(&dataplane->rings.x86_32_part, rc);
+
+ blkif_get_x86_32_req(&request->req, req);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64: {
+ blkif_x86_64_request_t *req =
+ RING_GET_REQUEST(&dataplane->rings.x86_64_part, rc);
+
+ blkif_get_x86_64_req(&request->req, req);
+ break;
+ }
+ }
+ /* Prevent the compiler from accessing the on-ring fields instead. */
+ barrier();
+ return 0;
+}
+
+/*
+ * Threshold of in-flight requests above which we will start using
+ * blk_io_plug()/blk_io_unplug() to batch requests.
+ */
+#define IO_PLUG_THRESHOLD 1
+
+static void xen_block_handle_requests(XenBlockDataPlane *dataplane)
+{
+ RING_IDX rc, rp;
+ XenBlockRequest *request;
+ int inflight_atstart = dataplane->requests_inflight;
+ int batched = 0;
+
+ dataplane->more_work = 0;
+
+ rc = dataplane->rings.common.req_cons;
+ rp = dataplane->rings.common.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ /*
+ * If there was more than IO_PLUG_THRESHOLD requests in flight
+ * when we got here, this is an indication that there the bottleneck
+ * is below us, so it's worth beginning to batch up I/O requests
+ * rather than submitting them immediately. The maximum number
+ * of requests we're willing to batch is the number already in
+ * flight, so it can grow up to max_requests when the bottleneck
+ * is below us.
+ */
+ if (inflight_atstart > IO_PLUG_THRESHOLD) {
+ blk_io_plug(dataplane->blk);
+ }
+ while (rc != rp) {
+ /* pull request from ring */
+ if (RING_REQUEST_CONS_OVERFLOW(&dataplane->rings.common, rc)) {
+ break;
+ }
+ request = xen_block_start_request(dataplane);
+ if (request == NULL) {
+ dataplane->more_work++;
+ break;
+ }
+ xen_block_get_request(dataplane, request, rc);
+ dataplane->rings.common.req_cons = ++rc;
+
+ /* parse them */
+ if (xen_block_parse_request(request) != 0) {
+ switch (request->req.operation) {
+ case BLKIF_OP_READ:
+ block_acct_invalid(blk_get_stats(dataplane->blk),
+ BLOCK_ACCT_READ);
+ break;
+ case BLKIF_OP_WRITE:
+ block_acct_invalid(blk_get_stats(dataplane->blk),
+ BLOCK_ACCT_WRITE);
+ break;
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ block_acct_invalid(blk_get_stats(dataplane->blk),
+ BLOCK_ACCT_FLUSH);
+ default:
+ break;
+ };
+
+ if (xen_block_send_response(request)) {
+ Error *local_err = NULL;
+
+ xen_device_notify_event_channel(dataplane->xendev,
+ dataplane->event_channel,
+ &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+ xen_block_release_request(request);
+ continue;
+ }
+
+ if (inflight_atstart > IO_PLUG_THRESHOLD &&
+ batched >= inflight_atstart) {
+ blk_io_unplug(dataplane->blk);
+ }
+ xen_block_do_aio(request);
+ if (inflight_atstart > IO_PLUG_THRESHOLD) {
+ if (batched >= inflight_atstart) {
+ blk_io_plug(dataplane->blk);
+ batched = 0;
+ } else {
+ batched++;
+ }
+ }
+ }
+ if (inflight_atstart > IO_PLUG_THRESHOLD) {
+ blk_io_unplug(dataplane->blk);
+ }
+
+ if (dataplane->more_work &&
+ dataplane->requests_inflight < dataplane->max_requests) {
+ qemu_bh_schedule(dataplane->bh);
+ }
+}
+
+static void xen_block_dataplane_bh(void *opaque)
+{
+ XenBlockDataPlane *dataplane = opaque;
+
+ aio_context_acquire(dataplane->ctx);
+ xen_block_handle_requests(dataplane);
+ aio_context_release(dataplane->ctx);
+}
+
+static void xen_block_dataplane_event(void *opaque)
+{
+ XenBlockDataPlane *dataplane = opaque;
+
+ qemu_bh_schedule(dataplane->bh);
+}
+
+XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
+ BlockConf *conf,
+ IOThread *iothread)
+{
+ XenBlockDataPlane *dataplane = g_new0(XenBlockDataPlane, 1);
+
+ dataplane->xendev = xendev;
+ dataplane->file_blk = conf->logical_block_size;
+ dataplane->blk = conf->blk;
+ dataplane->file_size = blk_getlength(dataplane->blk);
+
+ QLIST_INIT(&dataplane->inflight);
+ QLIST_INIT(&dataplane->freelist);
+
+ if (iothread) {
+ dataplane->iothread = iothread;
+ object_ref(OBJECT(dataplane->iothread));
+ dataplane->ctx = iothread_get_aio_context(dataplane->iothread);
+ } else {
+ dataplane->ctx = qemu_get_aio_context();
+ }
+ dataplane->bh = aio_bh_new(dataplane->ctx, xen_block_dataplane_bh,
+ dataplane);
+
+ return dataplane;
+}
+
+void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
+{
+ XenBlockRequest *request;
+
+ if (!dataplane) {
+ return;
+ }
+
+ while (!QLIST_EMPTY(&dataplane->freelist)) {
+ request = QLIST_FIRST(&dataplane->freelist);
+ QLIST_REMOVE(request, list);
+ qemu_iovec_destroy(&request->v);
+ qemu_vfree(request->buf);
+ g_free(request);
+ }
+
+ qemu_bh_delete(dataplane->bh);
+ if (dataplane->iothread) {
+ object_unref(OBJECT(dataplane->iothread));
+ }
+
+ g_free(dataplane);
+}
+
+void xen_block_dataplane_stop(XenBlockDataPlane *dataplane)
+{
+ XenDevice *xendev;
+
+ if (!dataplane) {
+ return;
+ }
+
+ aio_context_acquire(dataplane->ctx);
+ blk_set_aio_context(dataplane->blk, qemu_get_aio_context());
+ aio_context_release(dataplane->ctx);
+
+ xendev = dataplane->xendev;
+
+ if (dataplane->event_channel) {
+ Error *local_err = NULL;
+
+ xen_device_unbind_event_channel(xendev, dataplane->event_channel,
+ &local_err);
+ dataplane->event_channel = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+
+ if (dataplane->sring) {
+ Error *local_err = NULL;
+
+ xen_device_unmap_grant_refs(xendev, dataplane->sring,
+ dataplane->nr_ring_ref, &local_err);
+ dataplane->sring = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+
+ g_free(dataplane->ring_ref);
+ dataplane->ring_ref = NULL;
+}
+
+void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
+ const unsigned int ring_ref[],
+ unsigned int nr_ring_ref,
+ unsigned int event_channel,
+ unsigned int protocol,
+ Error **errp)
+{
+ XenDevice *xendev = dataplane->xendev;
+ Error *local_err = NULL;
+ unsigned int ring_size;
+ unsigned int i;
+
+ dataplane->nr_ring_ref = nr_ring_ref;
+ dataplane->ring_ref = g_new(unsigned int, nr_ring_ref);
+
+ for (i = 0; i < nr_ring_ref; i++) {
+ dataplane->ring_ref[i] = ring_ref[i];
+ }
+
+ dataplane->protocol = protocol;
+
+ ring_size = XC_PAGE_SIZE * dataplane->nr_ring_ref;
+ switch (dataplane->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ dataplane->max_requests = __CONST_RING_SIZE(blkif, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ dataplane->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
+ break;
+ }
+ default:
+ error_setg(errp, "unknown protocol %u", dataplane->protocol);
+ return;
+ }
+
+ xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ dataplane->sring = xen_device_map_grant_refs(xendev,
+ dataplane->ring_ref,
+ dataplane->nr_ring_ref,
+ PROT_READ | PROT_WRITE,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ switch (dataplane->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ blkif_sring_t *sring_native = dataplane->sring;
+
+ BACK_RING_INIT(&dataplane->rings.native, sring_native, ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ blkif_x86_32_sring_t *sring_x86_32 = dataplane->sring;
+
+ BACK_RING_INIT(&dataplane->rings.x86_32_part, sring_x86_32,
+ ring_size);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ blkif_x86_64_sring_t *sring_x86_64 = dataplane->sring;
+
+ BACK_RING_INIT(&dataplane->rings.x86_64_part, sring_x86_64,
+ ring_size);
+ break;
+ }
+ }
+
+ dataplane->event_channel =
+ xen_device_bind_event_channel(xendev, event_channel,
+ xen_block_dataplane_event, dataplane,
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto stop;
+ }
+
+ aio_context_acquire(dataplane->ctx);
+ blk_set_aio_context(dataplane->blk, dataplane->ctx);
+ aio_context_release(dataplane->ctx);
+ return;
+
+stop:
+ xen_block_dataplane_stop(dataplane);
+}
diff --git a/hw/block/dataplane/xen-block.h b/hw/block/dataplane/xen-block.h
new file mode 100644
index 0000000000..d6fa6d26dd
--- /dev/null
+++ b/hw/block/dataplane/xen-block.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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 HW_BLOCK_DATAPLANE_XEN_BLOCK_H
+#define HW_BLOCK_DATAPLANE_XEN_BLOCK_H
+
+#include "hw/block/block.h"
+#include "hw/xen/xen-bus.h"
+#include "sysemu/iothread.h"
+
+typedef struct XenBlockDataPlane XenBlockDataPlane;
+
+XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
+ BlockConf *conf,
+ IOThread *iothread);
+void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane);
+void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
+ const unsigned int ring_ref[],
+ unsigned int nr_ring_ref,
+ unsigned int event_channel,
+ unsigned int protocol,
+ Error **errp);
+void xen_block_dataplane_stop(XenBlockDataPlane *dataplane);
+
+#endif /* HW_BLOCK_DATAPLANE_XEN_BLOCK_H */
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index cabcf20c32..56c9d4b4b1 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -29,8 +29,8 @@ typedef struct NvmeSQueue {
uint64_t dma_addr;
QEMUTimer *timer;
NvmeRequest *io_req;
- QTAILQ_HEAD(sq_req_list, NvmeRequest) req_list;
- QTAILQ_HEAD(out_req_list, NvmeRequest) out_req_list;
+ QTAILQ_HEAD(, NvmeRequest) req_list;
+ QTAILQ_HEAD(, NvmeRequest) out_req_list;
QTAILQ_ENTRY(NvmeSQueue) entry;
} NvmeSQueue;
@@ -45,8 +45,8 @@ typedef struct NvmeCQueue {
uint32_t size;
uint64_t dma_addr;
QEMUTimer *timer;
- QTAILQ_HEAD(sq_list, NvmeSQueue) sq_list;
- QTAILQ_HEAD(cq_req_list, NvmeRequest) req_list;
+ QTAILQ_HEAD(, NvmeSQueue) sq_list;
+ QTAILQ_HEAD(, NvmeRequest) req_list;
} NvmeCQueue;
typedef struct NvmeNamespace {
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
index 2b48609776..f11118a687 100644
--- a/hw/block/onenand.c
+++ b/hw/block/onenand.c
@@ -772,9 +772,9 @@ static const MemoryRegionOps onenand_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int onenand_initfn(SysBusDevice *sbd)
+static void onenand_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
OneNANDState *s = ONE_NAND(dev);
uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
void *ram;
@@ -794,14 +794,14 @@ static int onenand_initfn(SysBusDevice *sbd)
0xff, size + (size >> 5));
} else {
if (blk_is_read_only(s->blk)) {
- error_report("Can't use a read-only drive");
- return -1;
+ error_setg(errp, "Can't use a read-only drive");
+ return;
}
blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
BLK_PERM_ALL, &local_err);
if (local_err) {
- error_report_err(local_err);
- return -1;
+ error_propagate(errp, local_err);
+ return;
}
s->blk_cur = s->blk;
}
@@ -826,7 +826,6 @@ static int onenand_initfn(SysBusDevice *sbd)
| ((s->id.dev & 0xff) << 8)
| (s->id.ver & 0xff),
&vmstate_onenand, s);
- return 0;
}
static Property onenand_properties[] = {
@@ -841,9 +840,8 @@ static Property onenand_properties[] = {
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->realize = onenand_realize;
dc->reset = onenand_system_reset;
dc->props = onenand_properties;
}
diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c
index 808ad76ba6..d0fae248dc 100644
--- a/hw/block/tc58128.c
+++ b/hw/block/tc58128.c
@@ -38,7 +38,8 @@ static void init_dev(tc58128_dev * dev, const char *filename)
memset(dev->flash_contents, 0xff, FLASH_SIZE);
if (filename) {
/* Load flash image skipping the first block */
- ret = load_image(filename, dev->flash_contents + 528 * 32);
+ ret = load_image_size(filename, dev->flash_contents + 528 * 32,
+ FLASH_SIZE - 528 * 32);
if (ret < 0) {
if (!qtest_enabled()) {
error_report("Could not load flash image %s", filename);
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 335c092450..55e5a5500c 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -127,3 +127,17 @@ xen_disk_init(char *name) "%s"
xen_disk_connect(char *name) "%s"
xen_disk_disconnect(char *name) "%s"
xen_disk_free(char *name) "%s"
+
+# hw/block/xen-block.c
+xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
+xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
+xen_block_disconnect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
+xen_block_unrealize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u"
+xen_disk_realize(void) ""
+xen_disk_unrealize(void) ""
+xen_cdrom_realize(void) ""
+xen_cdrom_unrealize(void) ""
+xen_block_blockdev_add(char *str) "%s"
+xen_block_blockdev_del(const char *node_name) "%s"
+xen_block_device_create(unsigned int number) "%u"
+xen_block_device_destroy(unsigned int number) "%u"
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index 1451940845..c3af28fad4 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -250,6 +250,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
VhostUserState *user;
+ struct vhost_virtqueue *vqs = NULL;
int i, ret;
if (!s->chardev.chr) {
@@ -288,6 +289,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
s->dev.vq_index = 0;
s->dev.backend_features = 0;
+ vqs = s->dev.vqs;
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
@@ -314,7 +316,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
vhost_err:
vhost_dev_cleanup(&s->dev);
virtio_err:
- g_free(s->dev.vqs);
+ g_free(vqs);
virtio_cleanup(vdev);
vhost_user_cleanup(user);
@@ -326,10 +328,11 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(dev);
+ struct vhost_virtqueue *vqs = s->dev.vqs;
vhost_user_blk_set_status(vdev, 0);
vhost_dev_cleanup(&s->dev);
- g_free(s->dev.vqs);
+ g_free(vqs);
virtio_cleanup(vdev);
if (s->vhost_user) {
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 83cf5c01f9..f208c6ddb9 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -96,7 +96,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
trace_virtio_blk_rw_complete(vdev, req, ret);
if (req->qiov.nalloc != -1) {
- /* If nalloc is != 1 req->qiov is a local copy of the original
+ /* If nalloc is != -1 req->qiov is a local copy of the original
* external iovec. It was allocated in submit_requests to be
* able to merge requests. */
qemu_iovec_destroy(&req->qiov);
@@ -482,7 +482,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
uint32_t type;
struct iovec *in_iov = req->elem.in_sg;
- struct iovec *iov = req->elem.out_sg;
+ struct iovec *out_iov = req->elem.out_sg;
unsigned in_num = req->elem.in_num;
unsigned out_num = req->elem.out_num;
VirtIOBlock *s = req->dev;
@@ -493,13 +493,13 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
return -1;
}
- if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &req->out,
sizeof(req->out)) != sizeof(req->out))) {
virtio_error(vdev, "virtio-blk request outhdr too short");
return -1;
}
- iov_discard_front(&iov, &out_num, sizeof(req->out));
+ iov_discard_front(&out_iov, &out_num, sizeof(req->out));
if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
virtio_error(vdev, "virtio-blk request inhdr too short");
@@ -526,7 +526,7 @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
&req->out.sector);
if (is_write) {
- qemu_iovec_init_external(&req->qiov, iov, out_num);
+ qemu_iovec_init_external(&req->qiov, out_iov, out_num);
trace_virtio_blk_handle_write(vdev, req, req->sector_num,
req->qiov.size / BDRV_SECTOR_SIZE);
} else {
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
new file mode 100644
index 0000000000..a636487b3e
--- /dev/null
+++ b/hw/block/xen-block.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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/osdep.h"
+#include "qemu/cutils.h"
+#include "qemu/option.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-block-core.h"
+#include "qapi/qapi-commands-misc.h"
+#include "qapi/qapi-visit-block-core.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/visitor.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
+#include "hw/hw.h"
+#include "hw/xen/xen_common.h"
+#include "hw/block/xen_blkif.h"
+#include "hw/xen/xen-block.h"
+#include "hw/xen/xen-backend.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/iothread.h"
+#include "dataplane/xen-block.h"
+#include "trace.h"
+
+static char *xen_block_get_name(XenDevice *xendev, Error **errp)
+{
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+
+ return g_strdup_printf("%lu", vdev->number);
+}
+
+static void xen_block_disconnect(XenDevice *xendev, Error **errp)
+{
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ const char *type = object_get_typename(OBJECT(blockdev));
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+
+ trace_xen_block_disconnect(type, vdev->disk, vdev->partition);
+
+ xen_block_dataplane_stop(blockdev->dataplane);
+}
+
+static void xen_block_connect(XenDevice *xendev, Error **errp)
+{
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ const char *type = object_get_typename(OBJECT(blockdev));
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+ unsigned int order, nr_ring_ref, *ring_ref, event_channel, protocol;
+ char *str;
+
+ trace_xen_block_connect(type, vdev->disk, vdev->partition);
+
+ if (xen_device_frontend_scanf(xendev, "ring-page-order", "%u",
+ &order) != 1) {
+ nr_ring_ref = 1;
+ ring_ref = g_new(unsigned int, nr_ring_ref);
+
+ if (xen_device_frontend_scanf(xendev, "ring-ref", "%u",
+ &ring_ref[0]) != 1) {
+ error_setg(errp, "failed to read ring-ref");
+ g_free(ring_ref);
+ return;
+ }
+ } else if (order <= blockdev->props.max_ring_page_order) {
+ unsigned int i;
+
+ nr_ring_ref = 1 << order;
+ ring_ref = g_new(unsigned int, nr_ring_ref);
+
+ for (i = 0; i < nr_ring_ref; i++) {
+ const char *key = g_strdup_printf("ring-ref%u", i);
+
+ if (xen_device_frontend_scanf(xendev, key, "%u",
+ &ring_ref[i]) != 1) {
+ error_setg(errp, "failed to read %s", key);
+ g_free((gpointer)key);
+ g_free(ring_ref);
+ return;
+ }
+
+ g_free((gpointer)key);
+ }
+ } else {
+ error_setg(errp, "invalid ring-page-order (%d)", order);
+ return;
+ }
+
+ if (xen_device_frontend_scanf(xendev, "event-channel", "%u",
+ &event_channel) != 1) {
+ error_setg(errp, "failed to read event-channel");
+ g_free(ring_ref);
+ return;
+ }
+
+ if (xen_device_frontend_scanf(xendev, "protocol", "%ms",
+ &str) != 1) {
+ protocol = BLKIF_PROTOCOL_NATIVE;
+ } else {
+ if (strcmp(str, XEN_IO_PROTO_ABI_X86_32) == 0) {
+ protocol = BLKIF_PROTOCOL_X86_32;
+ } else if (strcmp(str, XEN_IO_PROTO_ABI_X86_64) == 0) {
+ protocol = BLKIF_PROTOCOL_X86_64;
+ } else {
+ protocol = BLKIF_PROTOCOL_NATIVE;
+ }
+
+ free(str);
+ }
+
+ xen_block_dataplane_start(blockdev->dataplane, ring_ref, nr_ring_ref,
+ event_channel, protocol, errp);
+
+ g_free(ring_ref);
+}
+
+static void xen_block_unrealize(XenDevice *xendev, Error **errp)
+{
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ XenBlockDeviceClass *blockdev_class =
+ XEN_BLOCK_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(blockdev));
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+
+ if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
+ return;
+ }
+
+ trace_xen_block_unrealize(type, vdev->disk, vdev->partition);
+
+ /* Disconnect from the frontend in case this has not already happened */
+ xen_block_disconnect(xendev, NULL);
+
+ xen_block_dataplane_destroy(blockdev->dataplane);
+ blockdev->dataplane = NULL;
+
+ if (blockdev_class->unrealize) {
+ blockdev_class->unrealize(blockdev, errp);
+ }
+}
+
+static void xen_block_realize(XenDevice *xendev, Error **errp)
+{
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ XenBlockDeviceClass *blockdev_class =
+ XEN_BLOCK_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(blockdev));
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+ BlockConf *conf = &blockdev->props.conf;
+ Error *local_err = NULL;
+
+ if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
+ error_setg(errp, "vdev property not set");
+ return;
+ }
+
+ trace_xen_block_realize(type, vdev->disk, vdev->partition);
+
+ if (blockdev_class->realize) {
+ blockdev_class->realize(blockdev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
+
+ /*
+ * The blkif protocol does not deal with removable media, so it must
+ * always be present, even for CDRom devices.
+ */
+ assert(conf->blk);
+ if (!blk_is_inserted(conf->blk)) {
+ error_setg(errp, "device needs media, but drive is empty");
+ return;
+ }
+
+ if (!blkconf_apply_backend_options(conf, blockdev->info & VDISK_READONLY,
+ false, errp)) {
+ return;
+ }
+
+ if (!(blockdev->info & VDISK_CDROM) &&
+ !blkconf_geometry(conf, NULL, 65535, 255, 255, errp)) {
+ return;
+ }
+
+ blkconf_blocksizes(conf);
+
+ if (conf->logical_block_size > conf->physical_block_size) {
+ error_setg(
+ errp, "logical_block_size > physical_block_size not supported");
+ return;
+ }
+
+ blk_set_guest_block_size(conf->blk, conf->logical_block_size);
+
+ if (conf->discard_granularity > 0) {
+ xen_device_backend_printf(xendev, "feature-discard", "%u", 1);
+ }
+
+ xen_device_backend_printf(xendev, "feature-flush-cache", "%u", 1);
+ xen_device_backend_printf(xendev, "max-ring-page-order", "%u",
+ blockdev->props.max_ring_page_order);
+ xen_device_backend_printf(xendev, "info", "%u", blockdev->info);
+
+ xen_device_frontend_printf(xendev, "virtual-device", "%lu",
+ vdev->number);
+ xen_device_frontend_printf(xendev, "device-type", "%s",
+ blockdev->device_type);
+
+ xen_device_backend_printf(xendev, "sector-size", "%u",
+ conf->logical_block_size);
+ xen_device_backend_printf(xendev, "sectors", "%"PRIi64,
+ blk_getlength(conf->blk) /
+ conf->logical_block_size);
+
+ blockdev->dataplane =
+ xen_block_dataplane_create(xendev, conf, blockdev->props.iothread);
+}
+
+static void xen_block_frontend_changed(XenDevice *xendev,
+ enum xenbus_state frontend_state,
+ Error **errp)
+{
+ enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
+ Error *local_err = NULL;
+
+ switch (frontend_state) {
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ if (backend_state == XenbusStateConnected) {
+ break;
+ }
+
+ xen_block_disconnect(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ break;
+ }
+
+ xen_block_connect(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ break;
+ }
+
+ xen_device_backend_set_state(xendev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xen_device_backend_set_state(xendev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ xen_block_disconnect(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ break;
+ }
+
+ xen_device_backend_set_state(xendev, XenbusStateClosed);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static char *disk_to_vbd_name(unsigned int disk)
+{
+ char *name, *prefix = (disk >= 26) ?
+ disk_to_vbd_name((disk / 26) - 1) : g_strdup("");
+
+ name = g_strdup_printf("%s%c", prefix, 'a' + disk % 26);
+ g_free(prefix);
+
+ return name;
+}
+
+static void xen_block_get_vdev(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
+ char *str;
+
+ switch (vdev->type) {
+ case XEN_BLOCK_VDEV_TYPE_DP:
+ str = g_strdup_printf("d%lup%lu", vdev->disk, vdev->partition);
+ break;
+
+ case XEN_BLOCK_VDEV_TYPE_XVD:
+ case XEN_BLOCK_VDEV_TYPE_HD:
+ case XEN_BLOCK_VDEV_TYPE_SD: {
+ char *name = disk_to_vbd_name(vdev->disk);
+
+ str = g_strdup_printf("%s%s%lu",
+ (vdev->type == XEN_BLOCK_VDEV_TYPE_XVD) ?
+ "xvd" :
+ (vdev->type == XEN_BLOCK_VDEV_TYPE_HD) ?
+ "hd" :
+ "sd",
+ name, vdev->partition);
+ g_free(name);
+ break;
+ }
+ default:
+ error_setg(errp, "invalid vdev type");
+ return;
+ }
+
+ visit_type_str(v, name, &str, errp);
+ g_free(str);
+}
+
+static unsigned int vbd_name_to_disk(const char *name, const char **endp)
+{
+ unsigned int disk = 0;
+
+ while (*name != '\0') {
+ if (!g_ascii_isalpha(*name) || !g_ascii_islower(*name)) {
+ break;
+ }
+
+ disk *= 26;
+ disk += *name++ - 'a' + 1;
+ }
+ *endp = name;
+
+ return disk - 1;
+}
+
+static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ char *str, *p;
+ const char *end;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ p = strchr(str, 'd');
+ if (!p) {
+ goto invalid;
+ }
+
+ *p++ = '\0';
+ if (*str == '\0') {
+ vdev->type = XEN_BLOCK_VDEV_TYPE_DP;
+ } else if (strcmp(str, "xv") == 0) {
+ vdev->type = XEN_BLOCK_VDEV_TYPE_XVD;
+ } else if (strcmp(str, "h") == 0) {
+ vdev->type = XEN_BLOCK_VDEV_TYPE_HD;
+ } else if (strcmp(str, "s") == 0) {
+ vdev->type = XEN_BLOCK_VDEV_TYPE_SD;
+ } else {
+ goto invalid;
+ }
+
+ if (vdev->type == XEN_BLOCK_VDEV_TYPE_DP) {
+ if (qemu_strtoul(p, &end, 10, &vdev->disk)) {
+ goto invalid;
+ }
+
+ if (*end == 'p') {
+ p = (char *) ++end;
+ if (*end == '\0') {
+ goto invalid;
+ }
+ }
+ } else {
+ vdev->disk = vbd_name_to_disk(p, &end);
+ }
+
+ if (*end != '\0') {
+ p = (char *)end;
+
+ if (qemu_strtoul(p, &end, 10, &vdev->partition)) {
+ goto invalid;
+ }
+
+ if (*end != '\0') {
+ goto invalid;
+ }
+ } else {
+ vdev->partition = 0;
+ }
+
+ switch (vdev->type) {
+ case XEN_BLOCK_VDEV_TYPE_DP:
+ case XEN_BLOCK_VDEV_TYPE_XVD:
+ if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
+ vdev->number = (202 << 8) | (vdev->disk << 4) |
+ vdev->partition;
+ } else if (vdev->disk < (1 << 20) && vdev->partition < (1 << 8)) {
+ vdev->number = (1 << 28) | (vdev->disk << 8) |
+ vdev->partition;
+ } else {
+ goto invalid;
+ }
+ break;
+
+ case XEN_BLOCK_VDEV_TYPE_HD:
+ if ((vdev->disk == 0 || vdev->disk == 1) &&
+ vdev->partition < (1 << 6)) {
+ vdev->number = (3 << 8) | (vdev->disk << 6) | vdev->partition;
+ } else if ((vdev->disk == 2 || vdev->disk == 3) &&
+ vdev->partition < (1 << 6)) {
+ vdev->number = (22 << 8) | ((vdev->disk - 2) << 6) |
+ vdev->partition;
+ } else {
+ goto invalid;
+ }
+ break;
+
+ case XEN_BLOCK_VDEV_TYPE_SD:
+ if (vdev->disk < (1 << 4) && vdev->partition < (1 << 4)) {
+ vdev->number = (8 << 8) | (vdev->disk << 4) | vdev->partition;
+ } else {
+ goto invalid;
+ }
+ break;
+
+ default:
+ goto invalid;
+ }
+
+ g_free(str);
+ return;
+
+invalid:
+ error_setg(errp, "invalid virtual disk specifier");
+
+ vdev->type = XEN_BLOCK_VDEV_TYPE_INVALID;
+ g_free(str);
+}
+
+/*
+ * This property deals with 'vdev' names adhering to the Xen VBD naming
+ * scheme described in:
+ *
+ * https://xenbits.xen.org/docs/unstable/man/xen-vbd-interface.7.html
+ */
+const PropertyInfo xen_block_prop_vdev = {
+ .name = "str",
+ .description = "Virtual Disk specifier: d*p*/xvd*/hd*/sd*",
+ .get = xen_block_get_vdev,
+ .set = xen_block_set_vdev,
+};
+
+static Property xen_block_props[] = {
+ DEFINE_PROP("vdev", XenBlockDevice, props.vdev,
+ xen_block_prop_vdev, XenBlockVdev),
+ DEFINE_BLOCK_PROPERTIES(XenBlockDevice, props.conf),
+ DEFINE_PROP_UINT32("max-ring-page-order", XenBlockDevice,
+ props.max_ring_page_order, 4),
+ DEFINE_PROP_LINK("iothread", XenBlockDevice, props.iothread,
+ TYPE_IOTHREAD, IOThread *),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void xen_block_class_init(ObjectClass *class, void *data)
+{
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+ XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class);
+
+ xendev_class->backend = "qdisk";
+ xendev_class->device = "vbd";
+ xendev_class->get_name = xen_block_get_name;
+ xendev_class->realize = xen_block_realize;
+ xendev_class->frontend_changed = xen_block_frontend_changed;
+ xendev_class->unrealize = xen_block_unrealize;
+
+ dev_class->props = xen_block_props;
+}
+
+static const TypeInfo xen_block_type_info = {
+ .name = TYPE_XEN_BLOCK_DEVICE,
+ .parent = TYPE_XEN_DEVICE,
+ .instance_size = sizeof(XenBlockDevice),
+ .abstract = true,
+ .class_size = sizeof(XenBlockDeviceClass),
+ .class_init = xen_block_class_init,
+};
+
+static void xen_disk_unrealize(XenBlockDevice *blockdev, Error **errp)
+{
+ trace_xen_disk_unrealize();
+}
+
+static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp)
+{
+ BlockConf *conf = &blockdev->props.conf;
+
+ trace_xen_disk_realize();
+
+ blockdev->device_type = "disk";
+
+ if (!conf->blk) {
+ error_setg(errp, "drive property not set");
+ return;
+ }
+
+ blockdev->info = blk_is_read_only(conf->blk) ? VDISK_READONLY : 0;
+}
+
+static void xen_disk_class_init(ObjectClass *class, void *data)
+{
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+ XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
+
+ blockdev_class->realize = xen_disk_realize;
+ blockdev_class->unrealize = xen_disk_unrealize;
+
+ dev_class->desc = "Xen Disk Device";
+}
+
+static const TypeInfo xen_disk_type_info = {
+ .name = TYPE_XEN_DISK_DEVICE,
+ .parent = TYPE_XEN_BLOCK_DEVICE,
+ .instance_size = sizeof(XenDiskDevice),
+ .class_init = xen_disk_class_init,
+};
+
+static void xen_cdrom_unrealize(XenBlockDevice *blockdev, Error **errp)
+{
+ trace_xen_cdrom_unrealize();
+}
+
+static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp)
+{
+ BlockConf *conf = &blockdev->props.conf;
+
+ trace_xen_cdrom_realize();
+
+ blockdev->device_type = "cdrom";
+
+ if (!conf->blk) {
+ int rc;
+
+ /* Set up an empty drive */
+ conf->blk = blk_new(0, BLK_PERM_ALL);
+
+ rc = blk_attach_dev(conf->blk, DEVICE(blockdev));
+ if (!rc) {
+ error_setg_errno(errp, -rc, "failed to create drive");
+ return;
+ }
+ }
+
+ blockdev->info = VDISK_READONLY | VDISK_CDROM;
+}
+
+static void xen_cdrom_class_init(ObjectClass *class, void *data)
+{
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+ XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class);
+
+ blockdev_class->realize = xen_cdrom_realize;
+ blockdev_class->unrealize = xen_cdrom_unrealize;
+
+ dev_class->desc = "Xen CD-ROM Device";
+}
+
+static const TypeInfo xen_cdrom_type_info = {
+ .name = TYPE_XEN_CDROM_DEVICE,
+ .parent = TYPE_XEN_BLOCK_DEVICE,
+ .instance_size = sizeof(XenCDRomDevice),
+ .class_init = xen_cdrom_class_init,
+};
+
+static void xen_block_register_types(void)
+{
+ type_register_static(&xen_block_type_info);
+ type_register_static(&xen_disk_type_info);
+ type_register_static(&xen_cdrom_type_info);
+}
+
+type_init(xen_block_register_types)
+
+static void xen_block_blockdev_del(const char *node_name, Error **errp)
+{
+ trace_xen_block_blockdev_del(node_name);
+
+ qmp_blockdev_del(node_name, errp);
+}
+
+static char *xen_block_blockdev_add(const char *id, QDict *qdict,
+ Error **errp)
+{
+ const char *driver = qdict_get_try_str(qdict, "driver");
+ BlockdevOptions *options = NULL;
+ Error *local_err = NULL;
+ char *node_name;
+ Visitor *v;
+
+ if (!driver) {
+ error_setg(errp, "no 'driver' parameter");
+ return NULL;
+ }
+
+ node_name = g_strdup_printf("%s-%s", id, driver);
+ qdict_put_str(qdict, "node-name", node_name);
+
+ trace_xen_block_blockdev_add(node_name);
+
+ v = qobject_input_visitor_new(QOBJECT(qdict));
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
+ visit_free(v);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ qmp_blockdev_add(options, &local_err);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto fail;
+ }
+
+ qapi_free_BlockdevOptions(options);
+
+ return node_name;
+
+fail:
+ if (options) {
+ qapi_free_BlockdevOptions(options);
+ }
+ g_free(node_name);
+
+ return NULL;
+}
+
+static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
+{
+ char *node_name = drive->node_name;
+
+ if (node_name) {
+ Error *local_err = NULL;
+
+ xen_block_blockdev_del(node_name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ g_free(node_name);
+ drive->node_name = NULL;
+ }
+ g_free(drive->id);
+ g_free(drive);
+}
+
+static XenBlockDrive *xen_block_drive_create(const char *id,
+ const char *device_type,
+ QDict *opts, Error **errp)
+{
+ const char *params = qdict_get_try_str(opts, "params");
+ const char *mode = qdict_get_try_str(opts, "mode");
+ const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
+ const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
+ char *driver = NULL;
+ char *filename = NULL;
+ XenBlockDrive *drive = NULL;
+ Error *local_err = NULL;
+ QDict *file_layer;
+ QDict *driver_layer;
+
+ if (params) {
+ char **v = g_strsplit(params, ":", 2);
+
+ if (v[1] == NULL) {
+ filename = g_strdup(v[0]);
+ driver = g_strdup("raw");
+ } else {
+ if (strcmp(v[0], "aio") == 0) {
+ driver = g_strdup("raw");
+ } else if (strcmp(v[0], "vhd") == 0) {
+ driver = g_strdup("vpc");
+ } else {
+ driver = g_strdup(v[0]);
+ }
+ filename = g_strdup(v[1]);
+ }
+
+ g_strfreev(v);
+ }
+
+ if (!filename) {
+ error_setg(errp, "no filename");
+ goto done;
+ }
+ assert(driver);
+
+ drive = g_new0(XenBlockDrive, 1);
+ drive->id = g_strdup(id);
+
+ file_layer = qdict_new();
+
+ qdict_put_str(file_layer, "driver", "file");
+ qdict_put_str(file_layer, "filename", filename);
+
+ if (mode && *mode != 'w') {
+ qdict_put_bool(file_layer, "read-only", true);
+ }
+
+ if (direct_io_safe) {
+ unsigned long value;
+
+ if (!qemu_strtoul(direct_io_safe, NULL, 2, &value) && !!value) {
+ QDict *cache_qdict = qdict_new();
+
+ qdict_put_bool(cache_qdict, "direct", true);
+ qdict_put_obj(file_layer, "cache", QOBJECT(cache_qdict));
+
+ qdict_put_str(file_layer, "aio", "native");
+ }
+ }
+
+ if (discard_enable) {
+ unsigned long value;
+
+ if (!qemu_strtoul(discard_enable, NULL, 2, &value) && !!value) {
+ qdict_put_str(file_layer, "discard", "unmap");
+ }
+ }
+
+ /*
+ * It is necessary to turn file locking off as an emulated device
+ * may have already opened the same image file.
+ */
+ qdict_put_str(file_layer, "locking", "off");
+
+ driver_layer = qdict_new();
+
+ qdict_put_str(driver_layer, "driver", driver);
+ qdict_put_obj(driver_layer, "file", QOBJECT(file_layer));
+
+ g_assert(!drive->node_name);
+ drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
+ &local_err);
+
+done:
+ g_free(driver);
+ g_free(filename);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ xen_block_drive_destroy(drive, NULL);
+ return NULL;
+ }
+
+ return drive;
+}
+
+static const char *xen_block_drive_get_node_name(XenBlockDrive *drive)
+{
+ return drive->node_name ? drive->node_name : "";
+}
+
+static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
+ Error **errp)
+{
+ qmp_object_del(iothread->id, errp);
+
+ g_free(iothread->id);
+ g_free(iothread);
+}
+
+static XenBlockIOThread *xen_block_iothread_create(const char *id,
+ Error **errp)
+{
+ XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
+ Error *local_err = NULL;
+
+ iothread->id = g_strdup(id);
+
+ qmp_object_add(TYPE_IOTHREAD, id, false, NULL, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+
+ g_free(iothread->id);
+ g_free(iothread);
+ return NULL;
+ }
+
+ return iothread;
+}
+
+static void xen_block_device_create(XenBackendInstance *backend,
+ QDict *opts, Error **errp)
+{
+ XenBus *xenbus = xen_backend_get_bus(backend);
+ const char *name = xen_backend_get_name(backend);
+ unsigned long number;
+ const char *vdev, *device_type;
+ XenBlockDrive *drive = NULL;
+ XenBlockIOThread *iothread = NULL;
+ XenDevice *xendev = NULL;
+ Error *local_err = NULL;
+ const char *type;
+ XenBlockDevice *blockdev;
+
+ if (qemu_strtoul(name, NULL, 10, &number)) {
+ error_setg(errp, "failed to parse name '%s'", name);
+ goto fail;
+ }
+
+ trace_xen_block_device_create(number);
+
+ vdev = qdict_get_try_str(opts, "dev");
+ if (!vdev) {
+ error_setg(errp, "no dev parameter");
+ goto fail;
+ }
+
+ device_type = qdict_get_try_str(opts, "device-type");
+ if (!device_type) {
+ error_setg(errp, "no device-type parameter");
+ goto fail;
+ }
+
+ if (!strcmp(device_type, "disk")) {
+ type = TYPE_XEN_DISK_DEVICE;
+ } else if (!strcmp(device_type, "cdrom")) {
+ type = TYPE_XEN_CDROM_DEVICE;
+ } else {
+ error_setg(errp, "invalid device-type parameter '%s'", device_type);
+ goto fail;
+ }
+
+ drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
+ if (!drive) {
+ error_propagate_prepend(errp, local_err, "failed to create drive: ");
+ goto fail;
+ }
+
+ iothread = xen_block_iothread_create(vdev, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to create iothread: ");
+ goto fail;
+ }
+
+ xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
+ blockdev = XEN_BLOCK_DEVICE(xendev);
+
+ object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
+ goto fail;
+ }
+
+ object_property_set_str(OBJECT(xendev),
+ xen_block_drive_get_node_name(drive), "drive",
+ &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
+ goto fail;
+ }
+
+ object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
+ &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to set 'iothread': ");
+ goto fail;
+ }
+
+ blockdev->iothread = iothread;
+ blockdev->drive = drive;
+
+ object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "realization of device %s failed: ",
+ type);
+ goto fail;
+ }
+
+ xen_backend_set_device(backend, xendev);
+ return;
+
+fail:
+ if (xendev) {
+ object_unparent(OBJECT(xendev));
+ }
+
+ if (iothread) {
+ xen_block_iothread_destroy(iothread, NULL);
+ }
+
+ if (drive) {
+ xen_block_drive_destroy(drive, NULL);
+ }
+}
+
+static void xen_block_device_destroy(XenBackendInstance *backend,
+ Error **errp)
+{
+ XenDevice *xendev = xen_backend_get_device(backend);
+ XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
+ XenBlockVdev *vdev = &blockdev->props.vdev;
+ XenBlockDrive *drive = blockdev->drive;
+ XenBlockIOThread *iothread = blockdev->iothread;
+
+ trace_xen_block_device_destroy(vdev->number);
+
+ object_unparent(OBJECT(xendev));
+
+ if (iothread) {
+ Error *local_err = NULL;
+
+ xen_block_iothread_destroy(iothread, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to destroy iothread: ");
+ return;
+ }
+ }
+
+ if (drive) {
+ Error *local_err = NULL;
+
+ xen_block_drive_destroy(drive, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to destroy drive: ");
+ }
+ }
+}
+
+static const XenBackendInfo xen_block_backend_info = {
+ .type = "qdisk",
+ .create = xen_block_device_create,
+ .destroy = xen_block_device_destroy,
+};
+
+static void xen_block_register_backend(void)
+{
+ xen_backend_register(&xen_block_backend_info);
+}
+
+xen_backend_init(xen_block_register_backend);
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
deleted file mode 100644
index 36eff94f84..0000000000
--- a/hw/block/xen_disk.c
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * xen paravirt block device backend
- *
- * (c) Gerd Hoffmann <kraxel@redhat.com>
- *
- * 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.
- *
- * This program 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 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/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-
-#include "hw/hw.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_blkif.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/iothread.h"
-#include "sysemu/block-backend.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qstring.h"
-#include "trace.h"
-
-/* ------------------------------------------------------------- */
-
-#define BLOCK_SIZE 512
-#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
-
-struct ioreq {
- blkif_request_t req;
- int16_t status;
-
- /* parsed request */
- off_t start;
- QEMUIOVector v;
- void *buf;
- size_t size;
- int presync;
-
- /* aio status */
- int aio_inflight;
- int aio_errors;
-
- struct XenBlkDev *blkdev;
- QLIST_ENTRY(ioreq) list;
- BlockAcctCookie acct;
-};
-
-#define MAX_RING_PAGE_ORDER 4
-
-struct XenBlkDev {
- struct XenDevice xendev; /* must be first */
- char *params;
- char *mode;
- char *type;
- char *dev;
- char *devtype;
- bool directiosafe;
- const char *fileproto;
- const char *filename;
- unsigned int ring_ref[1 << MAX_RING_PAGE_ORDER];
- unsigned int nr_ring_ref;
- void *sring;
- int64_t file_blk;
- int64_t file_size;
- int protocol;
- blkif_back_rings_t rings;
- int more_work;
-
- /* request lists */
- QLIST_HEAD(inflight_head, ioreq) inflight;
- QLIST_HEAD(finished_head, ioreq) finished;
- QLIST_HEAD(freelist_head, ioreq) freelist;
- int requests_total;
- int requests_inflight;
- int requests_finished;
- unsigned int max_requests;
-
- gboolean feature_discard;
-
- /* qemu block driver */
- DriveInfo *dinfo;
- BlockBackend *blk;
- QEMUBH *bh;
-
- IOThread *iothread;
- AioContext *ctx;
-};
-
-/* ------------------------------------------------------------- */
-
-static void ioreq_reset(struct ioreq *ioreq)
-{
- memset(&ioreq->req, 0, sizeof(ioreq->req));
- ioreq->status = 0;
- ioreq->start = 0;
- ioreq->buf = NULL;
- ioreq->size = 0;
- ioreq->presync = 0;
-
- ioreq->aio_inflight = 0;
- ioreq->aio_errors = 0;
-
- ioreq->blkdev = NULL;
- memset(&ioreq->list, 0, sizeof(ioreq->list));
- memset(&ioreq->acct, 0, sizeof(ioreq->acct));
-
- qemu_iovec_reset(&ioreq->v);
-}
-
-static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
-{
- struct ioreq *ioreq = NULL;
-
- if (QLIST_EMPTY(&blkdev->freelist)) {
- if (blkdev->requests_total >= blkdev->max_requests) {
- goto out;
- }
- /* allocate new struct */
- ioreq = g_malloc0(sizeof(*ioreq));
- ioreq->blkdev = blkdev;
- blkdev->requests_total++;
- qemu_iovec_init(&ioreq->v, 1);
- } else {
- /* get one from freelist */
- ioreq = QLIST_FIRST(&blkdev->freelist);
- QLIST_REMOVE(ioreq, list);
- }
- QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
- blkdev->requests_inflight++;
-
-out:
- return ioreq;
-}
-
-static void ioreq_finish(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- QLIST_REMOVE(ioreq, list);
- QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
- blkdev->requests_inflight--;
- blkdev->requests_finished++;
-}
-
-static void ioreq_release(struct ioreq *ioreq, bool finish)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- QLIST_REMOVE(ioreq, list);
- ioreq_reset(ioreq);
- ioreq->blkdev = blkdev;
- QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
- if (finish) {
- blkdev->requests_finished--;
- } else {
- blkdev->requests_inflight--;
- }
-}
-
-/*
- * translate request into iovec + start offset
- * do sanity checks along the way
- */
-static int ioreq_parse(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- struct XenDevice *xendev = &blkdev->xendev;
- size_t len;
- int i;
-
- xen_pv_printf(xendev, 3,
- "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
- ioreq->req.operation, ioreq->req.nr_segments,
- ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- break;
- case BLKIF_OP_FLUSH_DISKCACHE:
- ioreq->presync = 1;
- if (!ioreq->req.nr_segments) {
- return 0;
- }
- /* fall through */
- case BLKIF_OP_WRITE:
- break;
- case BLKIF_OP_DISCARD:
- return 0;
- default:
- xen_pv_printf(xendev, 0, "error: unknown operation (%d)\n",
- ioreq->req.operation);
- goto err;
- };
-
- if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
- xen_pv_printf(xendev, 0, "error: write req for ro device\n");
- goto err;
- }
-
- ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
- for (i = 0; i < ioreq->req.nr_segments; i++) {
- if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
- xen_pv_printf(xendev, 0, "error: nr_segments too big\n");
- goto err;
- }
- if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
- xen_pv_printf(xendev, 0, "error: first > last sector\n");
- goto err;
- }
- if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
- xen_pv_printf(xendev, 0, "error: page crossing\n");
- goto err;
- }
-
- len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
- ioreq->size += len;
- }
- if (ioreq->start + ioreq->size > blkdev->file_size) {
- xen_pv_printf(xendev, 0, "error: access beyond end of file\n");
- goto err;
- }
- return 0;
-
-err:
- ioreq->status = BLKIF_RSP_ERROR;
- return -1;
-}
-
-static int ioreq_grant_copy(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- struct XenDevice *xendev = &blkdev->xendev;
- XenGrantCopySegment segs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- int i, count, rc;
- int64_t file_blk = blkdev->file_blk;
- bool to_domain = (ioreq->req.operation == BLKIF_OP_READ);
- void *virt = ioreq->buf;
-
- if (ioreq->req.nr_segments == 0) {
- return 0;
- }
-
- count = ioreq->req.nr_segments;
-
- for (i = 0; i < count; i++) {
- if (to_domain) {
- segs[i].dest.foreign.ref = ioreq->req.seg[i].gref;
- segs[i].dest.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
- segs[i].source.virt = virt;
- } else {
- segs[i].source.foreign.ref = ioreq->req.seg[i].gref;
- segs[i].source.foreign.offset = ioreq->req.seg[i].first_sect * file_blk;
- segs[i].dest.virt = virt;
- }
- segs[i].len = (ioreq->req.seg[i].last_sect
- - ioreq->req.seg[i].first_sect + 1) * file_blk;
- virt += segs[i].len;
- }
-
- rc = xen_be_copy_grant_refs(xendev, to_domain, segs, count);
-
- if (rc) {
- xen_pv_printf(xendev, 0,
- "failed to copy data %d\n", rc);
- ioreq->aio_errors++;
- return -1;
- }
-
- return rc;
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
-
-static void qemu_aio_complete(void *opaque, int ret)
-{
- struct ioreq *ioreq = opaque;
- struct XenBlkDev *blkdev = ioreq->blkdev;
- struct XenDevice *xendev = &blkdev->xendev;
-
- aio_context_acquire(blkdev->ctx);
-
- if (ret != 0) {
- xen_pv_printf(xendev, 0, "%s I/O error\n",
- ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
- ioreq->aio_errors++;
- }
-
- ioreq->aio_inflight--;
- if (ioreq->presync) {
- ioreq->presync = 0;
- ioreq_runio_qemu_aio(ioreq);
- goto done;
- }
- if (ioreq->aio_inflight > 0) {
- goto done;
- }
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- /* in case of failure ioreq->aio_errors is increased */
- if (ret == 0) {
- ioreq_grant_copy(ioreq);
- }
- qemu_vfree(ioreq->buf);
- break;
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
- qemu_vfree(ioreq->buf);
- break;
- default:
- break;
- }
-
- ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
- ioreq_finish(ioreq);
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
- case BLKIF_OP_READ:
- if (ioreq->status == BLKIF_RSP_OKAY) {
- block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct);
- } else {
- block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct);
- }
- break;
- case BLKIF_OP_DISCARD:
- default:
- break;
- }
- qemu_bh_schedule(blkdev->bh);
-
-done:
- aio_context_release(blkdev->ctx);
-}
-
-static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number,
- uint64_t nr_sectors)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- int64_t byte_offset;
- int byte_chunk;
- uint64_t byte_remaining, limit;
- uint64_t sec_start = sector_number;
- uint64_t sec_count = nr_sectors;
-
- /* Wrap around, or overflowing byte limit? */
- if (sec_start + sec_count < sec_count ||
- sec_start + sec_count > INT64_MAX >> BDRV_SECTOR_BITS) {
- return false;
- }
-
- limit = BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS;
- byte_offset = sec_start << BDRV_SECTOR_BITS;
- byte_remaining = sec_count << BDRV_SECTOR_BITS;
-
- do {
- byte_chunk = byte_remaining > limit ? limit : byte_remaining;
- ioreq->aio_inflight++;
- blk_aio_pdiscard(blkdev->blk, byte_offset, byte_chunk,
- qemu_aio_complete, ioreq);
- byte_remaining -= byte_chunk;
- byte_offset += byte_chunk;
- } while (byte_remaining > 0);
-
- return true;
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
-
- ioreq->buf = qemu_memalign(XC_PAGE_SIZE, ioreq->size);
- if (ioreq->req.nr_segments &&
- (ioreq->req.operation == BLKIF_OP_WRITE ||
- ioreq->req.operation == BLKIF_OP_FLUSH_DISKCACHE) &&
- ioreq_grant_copy(ioreq)) {
- qemu_vfree(ioreq->buf);
- goto err;
- }
-
- ioreq->aio_inflight++;
- if (ioreq->presync) {
- blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
- return 0;
- }
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size);
- block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
- ioreq->v.size, BLOCK_ACCT_READ);
- ioreq->aio_inflight++;
- blk_aio_preadv(blkdev->blk, ioreq->start, &ioreq->v, 0,
- qemu_aio_complete, ioreq);
- break;
- case BLKIF_OP_WRITE:
- case BLKIF_OP_FLUSH_DISKCACHE:
- if (!ioreq->req.nr_segments) {
- break;
- }
-
- qemu_iovec_add(&ioreq->v, ioreq->buf, ioreq->size);
- block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
- ioreq->v.size,
- ioreq->req.operation == BLKIF_OP_WRITE ?
- BLOCK_ACCT_WRITE : BLOCK_ACCT_FLUSH);
- ioreq->aio_inflight++;
- blk_aio_pwritev(blkdev->blk, ioreq->start, &ioreq->v, 0,
- qemu_aio_complete, ioreq);
- break;
- case BLKIF_OP_DISCARD:
- {
- struct blkif_request_discard *req = (void *)&ioreq->req;
- if (!blk_split_discard(ioreq, req->sector_number, req->nr_sectors)) {
- goto err;
- }
- break;
- }
- default:
- /* unknown operation (shouldn't happen -- parse catches this) */
- goto err;
- }
-
- qemu_aio_complete(ioreq, 0);
-
- return 0;
-
-err:
- ioreq_finish(ioreq);
- ioreq->status = BLKIF_RSP_ERROR;
- return -1;
-}
-
-static int blk_send_response_one(struct ioreq *ioreq)
-{
- struct XenBlkDev *blkdev = ioreq->blkdev;
- int send_notify = 0;
- int have_requests = 0;
- blkif_response_t *resp;
-
- /* Place on the response ring for the relevant domain. */
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.native,
- blkdev->rings.native.rsp_prod_pvt);
- break;
- case BLKIF_PROTOCOL_X86_32:
- resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
- blkdev->rings.x86_32_part.rsp_prod_pvt);
- break;
- case BLKIF_PROTOCOL_X86_64:
- resp = (blkif_response_t *) RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
- blkdev->rings.x86_64_part.rsp_prod_pvt);
- break;
- default:
- return 0;
- }
-
- resp->id = ioreq->req.id;
- resp->operation = ioreq->req.operation;
- resp->status = ioreq->status;
-
- blkdev->rings.common.rsp_prod_pvt++;
-
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
- if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
- /*
- * Tail check for pending requests. Allows frontend to avoid
- * notifications if requests are already in flight (lower
- * overheads and promotes batching).
- */
- RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
- } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
- have_requests = 1;
- }
-
- if (have_requests) {
- blkdev->more_work++;
- }
- return send_notify;
-}
-
-/* walk finished list, send outstanding responses, free requests */
-static void blk_send_response_all(struct XenBlkDev *blkdev)
-{
- struct ioreq *ioreq;
- int send_notify = 0;
-
- while (!QLIST_EMPTY(&blkdev->finished)) {
- ioreq = QLIST_FIRST(&blkdev->finished);
- send_notify += blk_send_response_one(ioreq);
- ioreq_release(ioreq, true);
- }
- if (send_notify) {
- xen_pv_send_notify(&blkdev->xendev);
- }
-}
-
-static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
-{
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
- sizeof(ioreq->req));
- break;
- case BLKIF_PROTOCOL_X86_32:
- blkif_get_x86_32_req(&ioreq->req,
- RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
- break;
- case BLKIF_PROTOCOL_X86_64:
- blkif_get_x86_64_req(&ioreq->req,
- RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
- break;
- }
- /* Prevent the compiler from accessing the on-ring fields instead. */
- barrier();
- return 0;
-}
-
-static void blk_handle_requests(struct XenBlkDev *blkdev)
-{
- RING_IDX rc, rp;
- struct ioreq *ioreq;
-
- blkdev->more_work = 0;
-
- rc = blkdev->rings.common.req_cons;
- rp = blkdev->rings.common.sring->req_prod;
- xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
- blk_send_response_all(blkdev);
- while (rc != rp) {
- /* pull request from ring */
- if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
- break;
- }
- ioreq = ioreq_start(blkdev);
- if (ioreq == NULL) {
- blkdev->more_work++;
- break;
- }
- blk_get_request(blkdev, ioreq, rc);
- blkdev->rings.common.req_cons = ++rc;
-
- /* parse them */
- if (ioreq_parse(ioreq) != 0) {
-
- switch (ioreq->req.operation) {
- case BLKIF_OP_READ:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_READ);
- break;
- case BLKIF_OP_WRITE:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_WRITE);
- break;
- case BLKIF_OP_FLUSH_DISKCACHE:
- block_acct_invalid(blk_get_stats(blkdev->blk),
- BLOCK_ACCT_FLUSH);
- default:
- break;
- };
-
- if (blk_send_response_one(ioreq)) {
- xen_pv_send_notify(&blkdev->xendev);
- }
- ioreq_release(ioreq, false);
- continue;
- }
-
- ioreq_runio_qemu_aio(ioreq);
- }
-
- if (blkdev->more_work && blkdev->requests_inflight < blkdev->max_requests) {
- qemu_bh_schedule(blkdev->bh);
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static void blk_bh(void *opaque)
-{
- struct XenBlkDev *blkdev = opaque;
-
- aio_context_acquire(blkdev->ctx);
- blk_handle_requests(blkdev);
- aio_context_release(blkdev->ctx);
-}
-
-static void blk_alloc(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- Error *err = NULL;
-
- trace_xen_disk_alloc(xendev->name);
-
- QLIST_INIT(&blkdev->inflight);
- QLIST_INIT(&blkdev->finished);
- QLIST_INIT(&blkdev->freelist);
-
- blkdev->iothread = iothread_create(xendev->name, &err);
- assert(!err);
-
- blkdev->ctx = iothread_get_aio_context(blkdev->iothread);
- blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev);
-}
-
-static void blk_parse_discard(struct XenBlkDev *blkdev)
-{
- struct XenDevice *xendev = &blkdev->xendev;
- int enable;
-
- blkdev->feature_discard = true;
-
- if (xenstore_read_be_int(xendev, "discard-enable", &enable) == 0) {
- blkdev->feature_discard = !!enable;
- }
-
- if (blkdev->feature_discard) {
- xenstore_write_be_int(xendev, "feature-discard", 1);
- }
-}
-
-static int blk_init(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int info = 0;
- char *directiosafe = NULL;
-
- trace_xen_disk_init(xendev->name);
-
- /* read xenstore entries */
- if (blkdev->params == NULL) {
- char *h = NULL;
- blkdev->params = xenstore_read_be_str(xendev, "params");
- if (blkdev->params != NULL) {
- h = strchr(blkdev->params, ':');
- }
- if (h != NULL) {
- blkdev->fileproto = blkdev->params;
- blkdev->filename = h+1;
- *h = 0;
- } else {
- blkdev->fileproto = "<unset>";
- blkdev->filename = blkdev->params;
- }
- }
- if (!strcmp("aio", blkdev->fileproto)) {
- blkdev->fileproto = "raw";
- }
- if (!strcmp("vhd", blkdev->fileproto)) {
- blkdev->fileproto = "vpc";
- }
- if (blkdev->mode == NULL) {
- blkdev->mode = xenstore_read_be_str(xendev, "mode");
- }
- if (blkdev->type == NULL) {
- blkdev->type = xenstore_read_be_str(xendev, "type");
- }
- if (blkdev->dev == NULL) {
- blkdev->dev = xenstore_read_be_str(xendev, "dev");
- }
- if (blkdev->devtype == NULL) {
- blkdev->devtype = xenstore_read_be_str(xendev, "device-type");
- }
- directiosafe = xenstore_read_be_str(xendev, "direct-io-safe");
- blkdev->directiosafe = (directiosafe && atoi(directiosafe));
-
- /* do we have all we need? */
- if (blkdev->params == NULL ||
- blkdev->mode == NULL ||
- blkdev->type == NULL ||
- blkdev->dev == NULL) {
- goto out_error;
- }
-
- /* read-only ? */
- if (strcmp(blkdev->mode, "w")) {
- info |= VDISK_READONLY;
- }
-
- /* cdrom ? */
- if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
- info |= VDISK_CDROM;
- }
-
- blkdev->file_blk = BLOCK_SIZE;
-
- /* fill info
- * blk_connect supplies sector-size and sectors
- */
- xenstore_write_be_int(xendev, "feature-flush-cache", 1);
- xenstore_write_be_int(xendev, "info", info);
-
- xenstore_write_be_int(xendev, "max-ring-page-order",
- MAX_RING_PAGE_ORDER);
-
- blk_parse_discard(blkdev);
-
- g_free(directiosafe);
- return 0;
-
-out_error:
- g_free(blkdev->params);
- blkdev->params = NULL;
- g_free(blkdev->mode);
- blkdev->mode = NULL;
- g_free(blkdev->type);
- blkdev->type = NULL;
- g_free(blkdev->dev);
- blkdev->dev = NULL;
- g_free(blkdev->devtype);
- blkdev->devtype = NULL;
- g_free(directiosafe);
- blkdev->directiosafe = false;
- return -1;
-}
-
-static int blk_connect(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- int index, qflags;
- bool readonly = true;
- bool writethrough = true;
- int order, ring_ref;
- unsigned int ring_size, max_grants;
- unsigned int i;
-
- trace_xen_disk_connect(xendev->name);
-
- /* read-only ? */
- if (blkdev->directiosafe) {
- qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO;
- } else {
- qflags = 0;
- writethrough = false;
- }
- if (strcmp(blkdev->mode, "w") == 0) {
- qflags |= BDRV_O_RDWR;
- readonly = false;
- }
- if (blkdev->feature_discard) {
- qflags |= BDRV_O_UNMAP;
- }
-
- /* init qemu block driver */
- index = (xendev->dev - 202 * 256) / 16;
- blkdev->dinfo = drive_get(IF_XEN, 0, index);
- if (!blkdev->dinfo) {
- Error *local_err = NULL;
- QDict *options = NULL;
-
- if (strcmp(blkdev->fileproto, "<unset>")) {
- options = qdict_new();
- qdict_put_str(options, "driver", blkdev->fileproto);
- }
-
- /* setup via xenbus -> create new block driver instance */
- xen_pv_printf(xendev, 2, "create new bdrv (xenbus setup)\n");
- blkdev->blk = blk_new_open(blkdev->filename, NULL, options,
- qflags, &local_err);
- if (!blkdev->blk) {
- xen_pv_printf(xendev, 0, "error: %s\n",
- error_get_pretty(local_err));
- error_free(local_err);
- return -1;
- }
- blk_set_enable_write_cache(blkdev->blk, !writethrough);
- } else {
- /* setup via qemu cmdline -> already setup for us */
- xen_pv_printf(xendev, 2,
- "get configured bdrv (cmdline setup)\n");
- blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo);
- if (blk_is_read_only(blkdev->blk) && !readonly) {
- xen_pv_printf(xendev, 0, "Unexpected read-only drive");
- blkdev->blk = NULL;
- return -1;
- }
- /* blkdev->blk is not create by us, we get a reference
- * so we can blk_unref() unconditionally */
- blk_ref(blkdev->blk);
- }
- blk_attach_dev_legacy(blkdev->blk, blkdev);
- blkdev->file_size = blk_getlength(blkdev->blk);
- if (blkdev->file_size < 0) {
- BlockDriverState *bs = blk_bs(blkdev->blk);
- const char *drv_name = bs ? bdrv_get_format_name(bs) : NULL;
- xen_pv_printf(xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
- (int)blkdev->file_size, strerror(-blkdev->file_size),
- drv_name ?: "-");
- blkdev->file_size = 0;
- }
-
- xen_pv_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
- " size %" PRId64 " (%" PRId64 " MB)\n",
- blkdev->type, blkdev->fileproto, blkdev->filename,
- blkdev->file_size, blkdev->file_size / MiB);
-
- /* Fill in number of sector size and number of sectors */
- xenstore_write_be_int(xendev, "sector-size", blkdev->file_blk);
- xenstore_write_be_int64(xendev, "sectors",
- blkdev->file_size / blkdev->file_blk);
-
- if (xenstore_read_fe_int(xendev, "ring-page-order",
- &order) == -1) {
- blkdev->nr_ring_ref = 1;
-
- if (xenstore_read_fe_int(xendev, "ring-ref",
- &ring_ref) == -1) {
- return -1;
- }
- blkdev->ring_ref[0] = ring_ref;
-
- } else if (order >= 0 && order <= MAX_RING_PAGE_ORDER) {
- blkdev->nr_ring_ref = 1 << order;
-
- for (i = 0; i < blkdev->nr_ring_ref; i++) {
- char *key;
-
- key = g_strdup_printf("ring-ref%u", i);
- if (!key) {
- return -1;
- }
-
- if (xenstore_read_fe_int(xendev, key,
- &ring_ref) == -1) {
- g_free(key);
- return -1;
- }
- blkdev->ring_ref[i] = ring_ref;
-
- g_free(key);
- }
- } else {
- xen_pv_printf(xendev, 0, "invalid ring-page-order: %d\n",
- order);
- return -1;
- }
-
- if (xenstore_read_fe_int(xendev, "event-channel",
- &xendev->remote_port) == -1) {
- return -1;
- }
-
- if (!xendev->protocol) {
- blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_NATIVE) == 0) {
- blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
- blkdev->protocol = BLKIF_PROTOCOL_X86_32;
- } else if (strcmp(xendev->protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
- blkdev->protocol = BLKIF_PROTOCOL_X86_64;
- } else {
- blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
- }
-
- ring_size = XC_PAGE_SIZE * blkdev->nr_ring_ref;
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- {
- blkdev->max_requests = __CONST_RING_SIZE(blkif, ring_size);
- break;
- }
- case BLKIF_PROTOCOL_X86_32:
- {
- blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_32, ring_size);
- break;
- }
- case BLKIF_PROTOCOL_X86_64:
- {
- blkdev->max_requests = __CONST_RING_SIZE(blkif_x86_64, ring_size);
- break;
- }
- default:
- return -1;
- }
-
- /* Add on the number needed for the ring pages */
- max_grants = blkdev->nr_ring_ref;
-
- xen_be_set_max_grant_refs(xendev, max_grants);
- blkdev->sring = xen_be_map_grant_refs(xendev, blkdev->ring_ref,
- blkdev->nr_ring_ref,
- PROT_READ | PROT_WRITE);
- if (!blkdev->sring) {
- return -1;
- }
-
- switch (blkdev->protocol) {
- case BLKIF_PROTOCOL_NATIVE:
- {
- blkif_sring_t *sring_native = blkdev->sring;
- BACK_RING_INIT(&blkdev->rings.native, sring_native, ring_size);
- break;
- }
- case BLKIF_PROTOCOL_X86_32:
- {
- blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
-
- BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, ring_size);
- break;
- }
- case BLKIF_PROTOCOL_X86_64:
- {
- blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
-
- BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, ring_size);
- break;
- }
- }
-
- blk_set_aio_context(blkdev->blk, blkdev->ctx);
-
- xen_be_bind_evtchn(xendev);
-
- xen_pv_printf(xendev, 1, "ok: proto %s, nr-ring-ref %u, "
- "remote port %d, local port %d\n",
- xendev->protocol, blkdev->nr_ring_ref,
- xendev->remote_port, xendev->local_port);
- return 0;
-}
-
-static void blk_disconnect(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
- trace_xen_disk_disconnect(xendev->name);
-
- aio_context_acquire(blkdev->ctx);
-
- if (blkdev->blk) {
- blk_set_aio_context(blkdev->blk, qemu_get_aio_context());
- blk_detach_dev(blkdev->blk, blkdev);
- blk_unref(blkdev->blk);
- blkdev->blk = NULL;
- }
- xen_pv_unbind_evtchn(xendev);
-
- aio_context_release(blkdev->ctx);
-
- if (blkdev->sring) {
- xen_be_unmap_grant_refs(xendev, blkdev->sring,
- blkdev->nr_ring_ref);
- blkdev->sring = NULL;
- }
-}
-
-static int blk_free(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
- struct ioreq *ioreq;
-
- trace_xen_disk_free(xendev->name);
-
- blk_disconnect(xendev);
-
- while (!QLIST_EMPTY(&blkdev->freelist)) {
- ioreq = QLIST_FIRST(&blkdev->freelist);
- QLIST_REMOVE(ioreq, list);
- qemu_iovec_destroy(&ioreq->v);
- g_free(ioreq);
- }
-
- g_free(blkdev->params);
- g_free(blkdev->mode);
- g_free(blkdev->type);
- g_free(blkdev->dev);
- g_free(blkdev->devtype);
- qemu_bh_delete(blkdev->bh);
- iothread_destroy(blkdev->iothread);
- return 0;
-}
-
-static void blk_event(struct XenDevice *xendev)
-{
- struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
- qemu_bh_schedule(blkdev->bh);
-}
-
-struct XenDevOps xen_blkdev_ops = {
- .flags = DEVOPS_FLAG_NEED_GNTDEV,
- .size = sizeof(struct XenBlkDev),
- .alloc = blk_alloc,
- .init = blk_init,
- .initialise = blk_connect,
- .disconnect = blk_disconnect,
- .event = blk_event,
- .free = blk_free,
-};
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index bac11bec58..e1d258b611 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -239,9 +239,10 @@ static const MemoryRegionOps grlib_apbuart_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int grlib_apbuart_init(SysBusDevice *dev)
+static void grlib_apbuart_realize(DeviceState *dev, Error **errp)
{
UART *uart = GRLIB_APB_UART(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
qemu_chr_fe_set_handlers(&uart->chr,
grlib_apbuart_can_receive,
@@ -249,14 +250,12 @@ static int grlib_apbuart_init(SysBusDevice *dev)
grlib_apbuart_event,
NULL, uart, NULL, true);
- sysbus_init_irq(dev, &uart->irq);
+ sysbus_init_irq(sbd, &uart->irq);
memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart,
"uart", UART_REG_SIZE);
- sysbus_init_mmio(dev, &uart->iomem);
-
- return 0;
+ sysbus_init_mmio(sbd, &uart->iomem);
}
static void grlib_apbuart_reset(DeviceState *d)
@@ -280,9 +279,8 @@ static Property grlib_apbuart_properties[] = {
static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = grlib_apbuart_init;
+ dc->realize = grlib_apbuart_realize;
dc->reset = grlib_apbuart_reset;
dc->props = grlib_apbuart_properties;
}
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 02463e3388..7c42a2abfc 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -611,7 +611,7 @@ static void serial_receive1(void *opaque, const uint8_t *buf, int size)
SerialState *s = opaque;
if (s->wakeup) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
}
if(s->fcr & UART_FCR_FE) {
int i;
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 12831561a6..67740b7ee6 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -90,7 +90,7 @@ static void sh_serial_write(void *opaque, hwaddr offs,
#ifdef DEBUG_SERIAL
printf("sh_serial: write offs=0x%02x val=0x%02x\n",
- offs, val);
+ offs, val);
#endif
switch(offs) {
case 0x00: /* SMR */
@@ -98,17 +98,17 @@ static void sh_serial_write(void *opaque, hwaddr offs,
return;
case 0x04: /* BRR */
s->brr = val;
- return;
+ return;
case 0x08: /* SCR */
/* TODO : For SH7751, SCIF mask should be 0xfb. */
s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
if (!(val & (1 << 5)))
s->flags |= SH_SERIAL_FLAG_TEND;
if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
- qemu_set_irq(s->txi, val & (1 << 7));
+ qemu_set_irq(s->txi, val & (1 << 7));
}
if (!(val & (1 << 6))) {
- qemu_set_irq(s->rxi, 0);
+ qemu_set_irq(s->rxi, 0);
}
return;
case 0x0c: /* FTDR / TDR */
@@ -117,9 +117,9 @@ static void sh_serial_write(void *opaque, hwaddr offs,
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
- }
- s->dr = val;
- s->flags &= ~SH_SERIAL_FLAG_TDE;
+ }
+ s->dr = val;
+ s->flags &= ~SH_SERIAL_FLAG_TDE;
return;
#if 0
case 0x14: /* FRDR / RDR */
@@ -210,7 +210,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
break;
case 0x04:
ret = s->brr;
- break;
+ break;
case 0x08:
ret = s->scr;
break;
@@ -288,7 +288,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
}
#ifdef DEBUG_SERIAL
printf("sh_serial: read offs=0x%02x val=0x%x\n",
- offs, ret);
+ offs, ret);
#endif
if (ret & ~((1 << 16) - 1)) {
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index f3363a2952..10392c70e2 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -53,14 +53,13 @@ static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
{
STM32F2XXUsartState *s = opaque;
- s->usart_dr = *buf;
-
if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
/* USART not enabled - drop the chars */
DB_PRINT("Dropping the chars\n");
return;
}
+ s->usart_dr = *buf;
s->usart_sr |= USART_SR_RXNE;
if (s->usart_cr1 & USART_CR1_RXNEIE) {
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 04e3ebe352..d76351d748 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -696,7 +696,7 @@ static void virtio_serial_save_device(VirtIODevice *vdev, QEMUFile *f)
qemu_put_byte(f, port->guest_connected);
qemu_put_byte(f, port->host_connected);
- elem_popped = 0;
+ elem_popped = 0;
if (port->elem) {
elem_popped = 1;
}
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
index 44f7236382..dc6ff0e5b3 100644
--- a/hw/char/xen_console.c
+++ b/hw/char/xen_console.c
@@ -26,7 +26,7 @@
#include "qapi/error.h"
#include "hw/hw.h"
#include "chardev/char-fe.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include <xen/io/console.h>
@@ -39,7 +39,7 @@ struct buffer {
};
struct XenConsole {
- struct XenDevice xendev; /* must be first */
+ struct XenLegacyDevice xendev; /* must be first */
struct buffer buffer;
char console[XEN_BUFSIZE];
int ring_ref;
@@ -60,34 +60,34 @@ static void buffer_append(struct XenConsole *con)
size = prod - cons;
if ((size == 0) || (size > sizeof(intf->out)))
- return;
+ return;
if ((buffer->capacity - buffer->size) < size) {
- buffer->capacity += (size + 1024);
- buffer->data = g_realloc(buffer->data, buffer->capacity);
+ buffer->capacity += (size + 1024);
+ buffer->data = g_realloc(buffer->data, buffer->capacity);
}
while (cons != prod)
- buffer->data[buffer->size++] = intf->out[
- MASK_XENCONS_IDX(cons++, intf->out)];
+ buffer->data[buffer->size++] = intf->out[
+ MASK_XENCONS_IDX(cons++, intf->out)];
xen_mb();
intf->out_cons = cons;
xen_pv_send_notify(&con->xendev);
if (buffer->max_capacity &&
- buffer->size > buffer->max_capacity) {
- /* Discard the middle of the data. */
+ buffer->size > buffer->max_capacity) {
+ /* Discard the middle of the data. */
- size_t over = buffer->size - buffer->max_capacity;
- uint8_t *maxpos = buffer->data + buffer->max_capacity;
+ size_t over = buffer->size - buffer->max_capacity;
+ uint8_t *maxpos = buffer->data + buffer->max_capacity;
- memmove(maxpos - over, maxpos, over);
- buffer->data = g_realloc(buffer->data, buffer->max_capacity);
- buffer->size = buffer->capacity = buffer->max_capacity;
+ memmove(maxpos - over, maxpos, over);
+ buffer->data = g_realloc(buffer->data, buffer->max_capacity);
+ buffer->size = buffer->capacity = buffer->max_capacity;
- if (buffer->consumed > buffer->max_capacity - over)
- buffer->consumed = buffer->max_capacity - over;
+ if (buffer->consumed > buffer->max_capacity - over)
+ buffer->consumed = buffer->max_capacity - over;
}
}
@@ -95,8 +95,8 @@ static void buffer_advance(struct buffer *buffer, size_t len)
{
buffer->consumed += len;
if (buffer->consumed == buffer->size) {
- buffer->consumed = 0;
- buffer->size = 0;
+ buffer->consumed = 0;
+ buffer->size = 0;
}
}
@@ -111,7 +111,7 @@ static int ring_free_bytes(struct XenConsole *con)
space = prod - cons;
if (space > sizeof(intf->in))
- return 0; /* ring is screwed: ignore it */
+ return 0; /* ring is screwed: ignore it */
return (sizeof(intf->in) - space);
}
@@ -132,12 +132,12 @@ static void xencons_receive(void *opaque, const uint8_t *buf, int len)
max = ring_free_bytes(con);
/* The can_receive() func limits this, but check again anyway */
if (max < len)
- len = max;
+ len = max;
prod = intf->in_prod;
for (i = 0; i < len; i++) {
- intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
- buf[i];
+ intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+ buf[i];
}
xen_wmb();
intf->in_prod = prod;
@@ -173,7 +173,7 @@ static void xencons_send(struct XenConsole *con)
/* -------------------------------------------------------------------- */
-static int con_init(struct XenDevice *xendev)
+static int con_init(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
char *type, *dom, label[32];
@@ -222,17 +222,17 @@ out:
return ret;
}
-static int con_initialise(struct XenDevice *xendev)
+static int con_initialise(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
int limit;
if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
- return -1;
+ return -1;
if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
- return -1;
+ return -1;
if (xenstore_read_int(con->console, "limit", &limit) == 0)
- con->buffer.max_capacity = limit;
+ con->buffer.max_capacity = limit;
if (!xendev->dev) {
xen_pfn_t mfn = con->ring_ref;
@@ -244,7 +244,7 @@ static int con_initialise(struct XenDevice *xendev)
PROT_READ | PROT_WRITE);
}
if (!con->sring)
- return -1;
+ return -1;
xen_be_bind_evtchn(&con->xendev);
qemu_chr_fe_set_handlers(&con->chr, xencons_can_receive,
@@ -252,14 +252,14 @@ static int con_initialise(struct XenDevice *xendev)
xen_pv_printf(xendev, 1,
"ring mfn %d, remote port %d, local port %d, limit %zd\n",
- con->ring_ref,
- con->xendev.remote_port,
- con->xendev.local_port,
- con->buffer.max_capacity);
+ con->ring_ref,
+ con->xendev.remote_port,
+ con->xendev.local_port,
+ con->buffer.max_capacity);
return 0;
}
-static void con_disconnect(struct XenDevice *xendev)
+static void con_disconnect(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
@@ -276,13 +276,13 @@ static void con_disconnect(struct XenDevice *xendev)
}
}
-static void con_event(struct XenDevice *xendev)
+static void con_event(struct XenLegacyDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
buffer_append(con);
if (con->buffer.size - con->buffer.consumed)
- xencons_send(con);
+ xencons_send(con);
}
/* -------------------------------------------------------------------- */
diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c
index c1b9c2b104..239f78e2a7 100644
--- a/hw/core/empty_slot.c
+++ b/hw/core/empty_slot.c
@@ -71,21 +71,20 @@ void empty_slot_init(hwaddr addr, uint64_t slot_size)
}
}
-static int empty_slot_init1(SysBusDevice *dev)
+static void empty_slot_realize(DeviceState *dev, Error **errp)
{
EmptySlot *s = EMPTY_SLOT(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &empty_slot_ops, s,
"empty-slot", s->size);
- sysbus_init_mmio(dev, &s->iomem);
- return 0;
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
static void empty_slot_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- k->init = empty_slot_init1;
+ dc->realize = empty_slot_realize;
}
static const TypeInfo empty_slot_info = {
diff --git a/hw/core/loader.c b/hw/core/loader.c
index aa0b3fc867..c4f62fe427 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -74,31 +74,6 @@ int64_t get_image_size(const char *filename)
}
/* return the size or -1 if error */
-/* deprecated, because caller does not specify buffer size! */
-int load_image(const char *filename, uint8_t *addr)
-{
- int fd, size;
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
- size = lseek(fd, 0, SEEK_END);
- if (size == -1) {
- fprintf(stderr, "file %-20s: get size error: %s\n",
- filename, strerror(errno));
- close(fd);
- return -1;
- }
-
- lseek(fd, 0, SEEK_SET);
- if (read(fd, addr, size) != size) {
- close(fd);
- return -1;
- }
- close(fd);
- return size;
-}
-
-/* return the size or -1 if error */
ssize_t load_image_size(const char *filename, void *addr, size_t size)
{
int fd;
@@ -269,26 +244,26 @@ int load_aout(const char *filename, hwaddr addr, int max_sz,
case OMAGIC:
if (e.a_text + e.a_data > max_sz)
goto fail;
- lseek(fd, N_TXTOFF(e), SEEK_SET);
- size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
- if (size < 0)
- goto fail;
- break;
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
+ if (size < 0)
+ goto fail;
+ break;
case NMAGIC:
if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
goto fail;
- lseek(fd, N_TXTOFF(e), SEEK_SET);
- size = read_targphys(filename, fd, addr, e.a_text);
- if (size < 0)
- goto fail;
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read_targphys(filename, fd, addr, e.a_text);
+ if (size < 0)
+ goto fail;
ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
e.a_data);
- if (ret < 0)
- goto fail;
- size += ret;
- break;
+ if (ret < 0)
+ goto fail;
+ size += ret;
+ break;
default:
- goto fail;
+ goto fail;
}
close(fd);
return size;
@@ -638,13 +613,26 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
goto out;
if (hdr->ih_type != image_type) {
- fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
- image_type);
- goto out;
+ if (!(image_type == IH_TYPE_KERNEL &&
+ hdr->ih_type == IH_TYPE_KERNEL_NOLOAD)) {
+ fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
+ image_type);
+ goto out;
+ }
}
/* TODO: Implement other image types. */
switch (hdr->ih_type) {
+ case IH_TYPE_KERNEL_NOLOAD:
+ if (!loadaddr || *loadaddr == LOAD_UIMAGE_LOADADDR_INVALID) {
+ fprintf(stderr, "this image format (kernel_noload) cannot be "
+ "loaded on this machine type");
+ goto out;
+ }
+
+ hdr->ih_load = *loadaddr + sizeof(*hdr);
+ hdr->ih_ep += hdr->ih_load;
+ /* fall through */
case IH_TYPE_KERNEL:
address = hdr->ih_load;
if (translate_fn) {
@@ -1103,8 +1091,8 @@ static void rom_reset(void *unused)
void *host = memory_region_get_ram_ptr(rom->mr);
memcpy(host, rom->data, rom->datasize);
} else {
- cpu_physical_memory_write_rom(rom->as, rom->addr, rom->data,
- rom->datasize);
+ address_space_write_rom(rom->as, rom->addr, MEMTXATTRS_UNSPECIFIED,
+ rom->data, rom->datasize);
}
if (rom->isrom) {
/* rom needs to be written only once */
diff --git a/hw/core/machine.c b/hw/core/machine.c
index da50ad6de7..2629515363 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -21,6 +21,129 @@
#include "sysemu/numa.h"
#include "qemu/error-report.h"
#include "sysemu/qtest.h"
+#include "hw/pci/pci.h"
+
+GlobalProperty hw_compat_3_1[] = {
+ { "pcie-root-port", "x-speed", "2_5" },
+ { "pcie-root-port", "x-width", "1" },
+ { "memory-backend-file", "x-use-canonical-path-for-ramblock-id", "true" },
+ { "memory-backend-memfd", "x-use-canonical-path-for-ramblock-id", "true" },
+ { "tpm-crb", "ppi", "false" },
+ { "tpm-tis", "ppi", "false" },
+};
+const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
+
+GlobalProperty hw_compat_3_0[] = {};
+const size_t hw_compat_3_0_len = G_N_ELEMENTS(hw_compat_3_0);
+
+GlobalProperty hw_compat_2_12[] = {
+ { "migration", "decompress-error-check", "off" },
+ { "hda-audio", "use-timer", "false" },
+ { "cirrus-vga", "global-vmstate", "true" },
+ { "VGA", "global-vmstate", "true" },
+ { "vmware-svga", "global-vmstate", "true" },
+ { "qxl-vga", "global-vmstate", "true" },
+};
+const size_t hw_compat_2_12_len = G_N_ELEMENTS(hw_compat_2_12);
+
+GlobalProperty hw_compat_2_11[] = {
+ { "hpet", "hpet-offset-saved", "false" },
+ { "virtio-blk-pci", "vectors", "2" },
+ { "vhost-user-blk-pci", "vectors", "2" },
+ { "e1000", "migrate_tso_props", "off" },
+};
+const size_t hw_compat_2_11_len = G_N_ELEMENTS(hw_compat_2_11);
+
+GlobalProperty hw_compat_2_10[] = {
+ { "virtio-mouse-device", "wheel-axis", "false" },
+ { "virtio-tablet-device", "wheel-axis", "false" },
+};
+const size_t hw_compat_2_10_len = G_N_ELEMENTS(hw_compat_2_10);
+
+GlobalProperty hw_compat_2_9[] = {
+ { "pci-bridge", "shpc", "off" },
+ { "intel-iommu", "pt", "off" },
+ { "virtio-net-device", "x-mtu-bypass-backend", "off" },
+ { "pcie-root-port", "x-migrate-msix", "false" },
+};
+const size_t hw_compat_2_9_len = G_N_ELEMENTS(hw_compat_2_9);
+
+GlobalProperty hw_compat_2_8[] = {
+ { "fw_cfg_mem", "x-file-slots", "0x10" },
+ { "fw_cfg_io", "x-file-slots", "0x10" },
+ { "pflash_cfi01", "old-multiple-chip-handling", "on" },
+ { "pci-bridge", "shpc", "on" },
+ { TYPE_PCI_DEVICE, "x-pcie-extcap-init", "off" },
+ { "virtio-pci", "x-pcie-deverr-init", "off" },
+ { "virtio-pci", "x-pcie-lnkctl-init", "off" },
+ { "virtio-pci", "x-pcie-pm-init", "off" },
+ { "cirrus-vga", "vgamem_mb", "8" },
+ { "isa-cirrus-vga", "vgamem_mb", "8" },
+};
+const size_t hw_compat_2_8_len = G_N_ELEMENTS(hw_compat_2_8);
+
+GlobalProperty hw_compat_2_7[] = {
+ { "virtio-pci", "page-per-vq", "on" },
+ { "virtio-serial-device", "emergency-write", "off" },
+ { "ioapic", "version", "0x11" },
+ { "intel-iommu", "x-buggy-eim", "true" },
+ { "virtio-pci", "x-ignore-backend-features", "on" },
+};
+const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
+
+GlobalProperty hw_compat_2_6[] = {
+ { "virtio-mmio", "format_transport_address", "off" },
+ /* Optional because not all virtio-pci devices support legacy mode */
+ { "virtio-pci", "disable-modern", "on", .optional = true },
+ { "virtio-pci", "disable-legacy", "off", .optional = true },
+};
+const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
+
+GlobalProperty hw_compat_2_5[] = {
+ { "isa-fdc", "fallback", "144" },
+ { "pvscsi", "x-old-pci-configuration", "on" },
+ { "pvscsi", "x-disable-pcie", "on" },
+ { "vmxnet3", "x-old-msi-offsets", "on" },
+ { "vmxnet3", "x-disable-pcie", "on" },
+};
+const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5);
+
+GlobalProperty hw_compat_2_4[] = {
+ { "virtio-blk-device", "scsi", "true" },
+ { "e1000", "extra_mac_registers", "off" },
+ { "virtio-pci", "x-disable-pcie", "on" },
+ { "virtio-pci", "migrate-extra", "off" },
+ { "fw_cfg_mem", "dma_enabled", "off" },
+ { "fw_cfg_io", "dma_enabled", "off" }
+};
+const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4);
+
+GlobalProperty hw_compat_2_3[] = {
+ { "virtio-blk-pci", "any_layout", "off" },
+ { "virtio-balloon-pci", "any_layout", "off" },
+ { "virtio-serial-pci", "any_layout", "off" },
+ { "virtio-9p-pci", "any_layout", "off" },
+ { "virtio-rng-pci", "any_layout", "off" },
+ { TYPE_PCI_DEVICE, "x-pcie-lnksta-dllla", "off" },
+ { "migration", "send-configuration", "off" },
+ { "migration", "send-section-footer", "off" },
+ { "migration", "store-global-state", "off" },
+};
+const size_t hw_compat_2_3_len = G_N_ELEMENTS(hw_compat_2_3);
+
+GlobalProperty hw_compat_2_2[] = {};
+const size_t hw_compat_2_2_len = G_N_ELEMENTS(hw_compat_2_2);
+
+GlobalProperty hw_compat_2_1[] = {
+ { "intel-hda", "old_msi_addr", "on" },
+ { "VGA", "qemu-extended-regs", "off" },
+ { "secondary-vga", "qemu-extended-regs", "off" },
+ { "virtio-scsi-pci", "any_layout", "off" },
+ { "usb-mouse", "usb_version", "1" },
+ { "usb-kbd", "usb_version", "1" },
+ { "virtio-pci", "virtio-pci-bus-master-bug-migration", "on" },
+};
+const size_t hw_compat_2_1_len = G_N_ELEMENTS(hw_compat_2_1);
static char *machine_get_accel(Object *obj, Error **errp)
{
@@ -591,7 +714,7 @@ static void machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "dump-guest-core",
machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort);
object_class_property_set_description(oc, "dump-guest-core",
- "Include guest memory in a core dump", &error_abort);
+ "Include guest memory in a core dump", &error_abort);
object_class_property_add_bool(oc, "mem-merge",
machine_get_mem_merge, machine_set_mem_merge, &error_abort);
@@ -647,14 +770,17 @@ static void machine_class_base_init(ObjectClass *oc, void *data)
assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX));
mc->name = g_strndup(cname,
strlen(cname) - strlen(TYPE_MACHINE_SUFFIX));
+ mc->compat_props = g_ptr_array_new();
}
}
static void machine_initfn(Object *obj)
{
MachineState *ms = MACHINE(obj);
+ MachineClass *mc = MACHINE_GET_CLASS(obj);
ms->kernel_irqchip_allowed = true;
+ ms->kernel_irqchip_split = mc->default_kernel_irqchip_split;
ms->kvm_shadow_mem = -1;
ms->dump_guest_core = true;
ms->mem_merge = true;
@@ -834,34 +960,6 @@ void machine_run_board_init(MachineState *machine)
machine_class->init(machine);
}
-static void machine_class_finalize(ObjectClass *klass, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(klass);
-
- if (mc->compat_props) {
- g_array_free(mc->compat_props, true);
- }
- g_free(mc->name);
-}
-
-void machine_register_compat_props(MachineState *machine)
-{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- int i;
- GlobalProperty *p;
-
- if (!mc->compat_props) {
- return;
- }
-
- for (i = 0; i < mc->compat_props->len; i++) {
- p = g_array_index(mc->compat_props, GlobalProperty *, i);
- /* Machine compat_props must never cause errors: */
- p->errp = &error_abort;
- qdev_prop_register_global(p);
- }
-}
-
static const TypeInfo machine_info = {
.name = TYPE_MACHINE,
.parent = TYPE_OBJECT,
@@ -869,7 +967,6 @@ static const TypeInfo machine_info = {
.class_size = sizeof(MachineClass),
.class_init = machine_class_init,
.class_base_init = machine_class_base_init,
- .class_finalize = machine_class_finalize,
.instance_size = sizeof(MachineState),
.instance_init = machine_initfn,
.instance_finalize = machine_finalize,
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 8b22fb51c9..b45a7ef54b 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -288,10 +288,6 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
}
for (i = 0; i < queues; i++) {
- if (peers[i] == NULL) {
- err = -ENOENT;
- goto out;
- }
if (peers[i]->peer) {
err = -EEXIST;
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 35072dec1e..5da1439a8b 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -1173,58 +1173,35 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
*ptr = value;
}
-static GList *global_props;
-
-void qdev_prop_register_global(GlobalProperty *prop)
+static GPtrArray *global_props(void)
{
- global_props = g_list_append(global_props, prop);
-}
-
-void register_compat_prop(const char *driver,
- const char *property,
- const char *value)
-{
- GlobalProperty *p = g_new0(GlobalProperty, 1);
-
- /* Any compat_props must never cause error */
- p->errp = &error_abort;
- p->driver = driver;
- p->property = property;
- p->value = value;
- qdev_prop_register_global(p);
-}
+ static GPtrArray *gp;
-void register_compat_props_array(GlobalProperty *prop)
-{
- for (; prop && prop->driver; prop++) {
- register_compat_prop(prop->driver, prop->property, prop->value);
+ if (!gp) {
+ gp = g_ptr_array_new();
}
+
+ return gp;
}
-void qdev_prop_register_global_list(GlobalProperty *props)
+void qdev_prop_register_global(GlobalProperty *prop)
{
- int i;
-
- for (i = 0; props[i].driver != NULL; i++) {
- qdev_prop_register_global(props+i);
- }
+ g_ptr_array_add(global_props(), prop);
}
int qdev_prop_check_globals(void)
{
- GList *l;
- int ret = 0;
+ int i, ret = 0;
- for (l = global_props; l; l = l->next) {
- GlobalProperty *prop = l->data;
+ for (i = 0; i < global_props()->len; i++) {
+ GlobalProperty *prop;
ObjectClass *oc;
DeviceClass *dc;
+
+ prop = g_ptr_array_index(global_props(), i);
if (prop->used) {
continue;
}
- if (!prop->user_provided) {
- continue;
- }
oc = object_class_by_name(prop->driver);
oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
if (!oc) {
@@ -1246,28 +1223,8 @@ int qdev_prop_check_globals(void)
void qdev_prop_set_globals(DeviceState *dev)
{
- GList *l;
-
- for (l = global_props; l; l = l->next) {
- GlobalProperty *prop = l->data;
- Error *err = NULL;
-
- if (object_dynamic_cast(OBJECT(dev), prop->driver) == NULL) {
- continue;
- }
- prop->used = true;
- object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
- if (err != NULL) {
- error_prepend(&err, "can't apply global %s.%s=%s: ",
- prop->driver, prop->property, prop->value);
- if (!dev->hotplugged && prop->errp) {
- error_propagate(prop->errp, err);
- } else {
- assert(prop->user_provided);
- warn_report_err(err);
- }
- }
- }
+ object_apply_global_props(OBJECT(dev), global_props(),
+ dev->hotplugged ? NULL : &error_fatal);
}
/* --- 64bit unsigned int 'size' type --- */
@@ -1327,3 +1284,179 @@ const PropertyInfo qdev_prop_off_auto_pcibar = {
.set = set_enum,
.set_default_value = set_default_value_enum,
};
+
+/* --- PCIELinkSpeed 2_5/5/8/16 -- */
+
+static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
+ int speed;
+
+ switch (*p) {
+ case QEMU_PCI_EXP_LNK_2_5GT:
+ speed = PCIE_LINK_SPEED_2_5;
+ break;
+ case QEMU_PCI_EXP_LNK_5GT:
+ speed = PCIE_LINK_SPEED_5;
+ break;
+ case QEMU_PCI_EXP_LNK_8GT:
+ speed = PCIE_LINK_SPEED_8;
+ break;
+ case QEMU_PCI_EXP_LNK_16GT:
+ speed = PCIE_LINK_SPEED_16;
+ break;
+ default:
+ /* Unreachable */
+ abort();
+ }
+
+ visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
+}
+
+static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
+ int speed;
+ Error *local_err = NULL;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_enum(v, prop->name, &speed, prop->info->enum_table, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ switch (speed) {
+ case PCIE_LINK_SPEED_2_5:
+ *p = QEMU_PCI_EXP_LNK_2_5GT;
+ break;
+ case PCIE_LINK_SPEED_5:
+ *p = QEMU_PCI_EXP_LNK_5GT;
+ break;
+ case PCIE_LINK_SPEED_8:
+ *p = QEMU_PCI_EXP_LNK_8GT;
+ break;
+ case PCIE_LINK_SPEED_16:
+ *p = QEMU_PCI_EXP_LNK_16GT;
+ break;
+ default:
+ /* Unreachable */
+ abort();
+ }
+}
+
+const PropertyInfo qdev_prop_pcie_link_speed = {
+ .name = "PCIELinkSpeed",
+ .description = "2_5/5/8/16",
+ .enum_table = &PCIELinkSpeed_lookup,
+ .get = get_prop_pcielinkspeed,
+ .set = set_prop_pcielinkspeed,
+ .set_default_value = set_default_value_enum,
+};
+
+/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
+
+static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
+ int width;
+
+ switch (*p) {
+ case QEMU_PCI_EXP_LNK_X1:
+ width = PCIE_LINK_WIDTH_1;
+ break;
+ case QEMU_PCI_EXP_LNK_X2:
+ width = PCIE_LINK_WIDTH_2;
+ break;
+ case QEMU_PCI_EXP_LNK_X4:
+ width = PCIE_LINK_WIDTH_4;
+ break;
+ case QEMU_PCI_EXP_LNK_X8:
+ width = PCIE_LINK_WIDTH_8;
+ break;
+ case QEMU_PCI_EXP_LNK_X12:
+ width = PCIE_LINK_WIDTH_12;
+ break;
+ case QEMU_PCI_EXP_LNK_X16:
+ width = PCIE_LINK_WIDTH_16;
+ break;
+ case QEMU_PCI_EXP_LNK_X32:
+ width = PCIE_LINK_WIDTH_32;
+ break;
+ default:
+ /* Unreachable */
+ abort();
+ }
+
+ visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
+}
+
+static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
+ int width;
+ Error *local_err = NULL;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_enum(v, prop->name, &width, prop->info->enum_table, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ switch (width) {
+ case PCIE_LINK_WIDTH_1:
+ *p = QEMU_PCI_EXP_LNK_X1;
+ break;
+ case PCIE_LINK_WIDTH_2:
+ *p = QEMU_PCI_EXP_LNK_X2;
+ break;
+ case PCIE_LINK_WIDTH_4:
+ *p = QEMU_PCI_EXP_LNK_X4;
+ break;
+ case PCIE_LINK_WIDTH_8:
+ *p = QEMU_PCI_EXP_LNK_X8;
+ break;
+ case PCIE_LINK_WIDTH_12:
+ *p = QEMU_PCI_EXP_LNK_X12;
+ break;
+ case PCIE_LINK_WIDTH_16:
+ *p = QEMU_PCI_EXP_LNK_X16;
+ break;
+ case PCIE_LINK_WIDTH_32:
+ *p = QEMU_PCI_EXP_LNK_X32;
+ break;
+ default:
+ /* Unreachable */
+ abort();
+ }
+}
+
+const PropertyInfo qdev_prop_pcie_link_width = {
+ .name = "PCIELinkWidth",
+ .description = "1/2/4/8/12/16/32",
+ .enum_table = &PCIELinkWidth_lookup,
+ .get = get_prop_pcielinkwidth,
+ .set = set_prop_pcielinkwidth,
+ .set_default_value = set_default_value_enum,
+};
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 6b3cc55b27..d59071b8ed 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -158,7 +158,7 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
return dev;
}
-static QTAILQ_HEAD(device_listeners, DeviceListener) device_listeners
+static QTAILQ_HEAD(, DeviceListener) device_listeners
= QTAILQ_HEAD_INITIALIZER(device_listeners);
enum ListenerDirection { Forward, Reverse };
@@ -177,7 +177,7 @@ enum ListenerDirection { Forward, Reverse };
break; \
case Reverse: \
QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \
- device_listeners, link) { \
+ link) { \
if (_listener->_callback) { \
_listener->_callback(_listener, ##_args); \
} \
@@ -970,8 +970,26 @@ static void device_initfn(Object *obj)
QLIST_INIT(&dev->gpios);
}
+void object_apply_compat_props(Object *obj)
+{
+ if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
+ MachineState *m = MACHINE(qdev_get_machine());
+ MachineClass *mc = MACHINE_GET_CLASS(m);
+
+ if (m->accelerator) {
+ AccelClass *ac = ACCEL_GET_CLASS(m->accelerator);
+
+ if (ac->compat_props) {
+ object_apply_global_props(obj, ac->compat_props, &error_abort);
+ }
+ }
+ object_apply_global_props(obj, mc->compat_props, &error_abort);
+ }
+}
+
static void device_post_init(Object *obj)
{
+ object_apply_compat_props(obj);
qdev_prop_set_globals(DEVICE(obj));
}
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 84c8869371..9c477f2bf5 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -35,7 +35,7 @@ typedef struct QEMUResetEntry {
void *opaque;
} QEMUResetEntry;
-static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
+static QTAILQ_HEAD(, QEMUResetEntry) reset_handlers =
QTAILQ_HEAD_INITIALIZER(reset_handlers);
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 7ac36ad3e7..9f9edbcab9 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -201,18 +201,13 @@ void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size)
}
}
-/* TODO remove once all sysbus devices have been converted to realize */
+/* The purpose of preserving this empty realize function
+ * is to prevent the parent_realize field of some subclasses
+ * from being set to NULL to break the normal init/realize
+ * of some devices.
+ */
static void sysbus_realize(DeviceState *dev, Error **errp)
{
- SysBusDevice *sd = SYS_BUS_DEVICE(dev);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
-
- if (!sbc->init) {
- return;
- }
- if (sbc->init(sd) < 0) {
- error_setg(errp, "Device initialization failed");
- }
}
DeviceState *sysbus_create_varargs(const char *name,
diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h
index 34c11a70a6..608022de6e 100644
--- a/hw/core/uboot_image.h
+++ b/hw/core/uboot_image.h
@@ -124,6 +124,7 @@
#define IH_TYPE_SCRIPT 6 /* Script file */
#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */
#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */
+#define IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image (noload) */
/*
* Compression Types
diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs
index cd52d20b65..8db9e8a7b3 100644
--- a/hw/cpu/Makefile.objs
+++ b/hw/cpu/Makefile.objs
@@ -2,4 +2,4 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
obj-$(CONFIG_REALVIEW) += realview_mpcore.o
obj-$(CONFIG_A9MPCORE) += a9mpcore.o
obj-$(CONFIG_A15MPCORE) += a15mpcore.o
-common-obj-y += core.o
+common-obj-y += core.o cluster.o
diff --git a/hw/cpu/cluster.c b/hw/cpu/cluster.c
new file mode 100644
index 0000000000..9d50a235d5
--- /dev/null
+++ b/hw/cpu/cluster.c
@@ -0,0 +1,50 @@
+/*
+ * QEMU CPU cluster
+ *
+ * Copyright (c) 2018 GreenSocs SAS
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 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/gpl-2.0.html>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/cpu/cluster.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+
+static Property cpu_cluster_properties[] = {
+ DEFINE_PROP_UINT32("cluster-id", CPUClusterState, cluster_id, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void cpu_cluster_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = cpu_cluster_properties;
+}
+
+static const TypeInfo cpu_cluster_type_info = {
+ .name = TYPE_CPU_CLUSTER,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(CPUClusterState),
+ .class_init = cpu_cluster_class_init,
+};
+
+static void cpu_cluster_register_types(void)
+{
+ type_register_static(&cpu_cluster_type_info);
+}
+
+type_init(cpu_cluster_register_types)
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 8ad7e5d824..3407adf98d 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -489,18 +489,16 @@ typedef struct {
G364State g364;
} G364SysBusState;
-static int g364fb_sysbus_init(SysBusDevice *sbd)
+static void g364fb_sysbus_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
G364SysBusState *sbs = G364(dev);
G364State *s = &sbs->g364;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
g364fb_init(dev, s);
sysbus_init_irq(sbd, &s->irq);
sysbus_init_mmio(sbd, &s->mem_ctrl);
sysbus_init_mmio(sbd, &s->mem_vram);
-
- return 0;
}
static void g364fb_sysbus_reset(DeviceState *d)
@@ -518,9 +516,8 @@ static Property g364fb_sysbus_properties[] = {
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->realize = g364fb_sysbus_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "G364 framebuffer";
dc->reset = g364fb_sysbus_reset;
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 9087db5dee..8e9a65e75b 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -1189,9 +1189,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
return;
}
trace_qxl_enter_vga_mode(d->id);
-#if SPICE_SERVER_VERSION >= 0x000c03 /* release 0.12.3 */
spice_qxl_driver_unload(&d->ssd.qxl);
-#endif
graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
qemu_spice_create_host_primary(&d->ssd);
diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c
index c0d241ba01..da3229a1f6 100644
--- a/hw/display/ramfb-standalone.c
+++ b/hw/display/ramfb-standalone.c
@@ -1,7 +1,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/loader.h"
-#include "hw/isa/isa.h"
#include "hw/display/ramfb.h"
#include "ui/console.h"
#include "sysemu/sysemu.h"
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 3360be6f84..e1b1e302f2 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -319,7 +319,7 @@ static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
SCR_REG_B(DEBUG);
}
fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
+ (uint32_t) addr, value & 0xff);
}
#undef SCR_REG_B
#undef SCR_REG_W
@@ -358,7 +358,7 @@ static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t val
return;
}
fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
+ (uint32_t) addr, value & 0xff);
}
static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
@@ -421,7 +421,7 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
return;
}
fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
+ (uint32_t) addr, value & 0xff);
}
#define BITS 8
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3ba3f6853c..910a23c12e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -85,10 +85,10 @@ const uint8_t gr_mask[16] = {
#define cbswap_32(__x) \
((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
#ifdef HOST_WORDS_BIGENDIAN
#define PAT(x) cbswap_32(x)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index 55d76405a9..bc6e99c943 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -498,9 +498,9 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
/*
- * the guest can end up emitting fences out of order
- * so we should check all fenced cmds not just the first one.
- */
+ * the guest can end up emitting fences out of order
+ * so we should check all fenced cmds not just the first one.
+ */
if (cmd->cmd_hdr.fence_id > fence) {
continue;
}
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index cece4aa495..bdcd33c925 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -19,6 +19,20 @@
#include "hw/virtio/virtio-pci.h"
#include "hw/virtio/virtio-gpu.h"
+typedef struct VirtIOGPUPCI VirtIOGPUPCI;
+
+/*
+ * virtio-gpu-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
+#define VIRTIO_GPU_PCI(obj) \
+ OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
+
+struct VirtIOGPUPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOGPU vdev;
+};
+
static Property virtio_gpu_pci_properties[] = {
DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
DEFINE_PROP_END_OF_LIST(),
@@ -69,9 +83,8 @@ static void virtio_gpu_initfn(Object *obj)
TYPE_VIRTIO_GPU);
}
-static const TypeInfo virtio_gpu_pci_info = {
- .name = TYPE_VIRTIO_GPU_PCI,
- .parent = TYPE_VIRTIO_PCI,
+static const VirtioPCIDeviceTypeInfo virtio_gpu_pci_info = {
+ .generic_name = TYPE_VIRTIO_GPU_PCI,
.instance_size = sizeof(VirtIOGPUPCI),
.instance_init = virtio_gpu_initfn,
.class_init = virtio_gpu_pci_class_init,
@@ -79,6 +92,6 @@ static const TypeInfo virtio_gpu_pci_info = {
static void virtio_gpu_pci_register_types(void)
{
- type_register_static(&virtio_gpu_pci_info);
+ virtio_pci_types_register(&virtio_gpu_pci_info);
}
type_init(virtio_gpu_pci_register_types)
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index ab2e369b28..1e48009b74 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -3,6 +3,7 @@
#include "hw/pci/pci.h"
#include "vga_int.h"
#include "hw/virtio/virtio-pci.h"
+#include "hw/virtio/virtio-gpu.h"
#include "qapi/error.h"
/*
@@ -207,9 +208,8 @@ static void virtio_vga_inst_initfn(Object *obj)
TYPE_VIRTIO_GPU);
}
-static TypeInfo virtio_vga_info = {
- .name = TYPE_VIRTIO_VGA,
- .parent = TYPE_VIRTIO_PCI,
+static VirtioPCIDeviceTypeInfo virtio_vga_info = {
+ .generic_name = TYPE_VIRTIO_VGA,
.instance_size = sizeof(struct VirtIOVGA),
.instance_init = virtio_vga_inst_initfn,
.class_init = virtio_vga_class_init,
@@ -217,7 +217,7 @@ static TypeInfo virtio_vga_info = {
static void virtio_vga_register_types(void)
{
- type_register_static(&virtio_vga_info);
+ virtio_pci_types_register(&virtio_vga_info);
}
type_init(virtio_vga_register_types)
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 0330dc6f61..6202f1150e 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -30,7 +30,7 @@
#include "hw/hw.h"
#include "ui/input.h"
#include "ui/console.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include <xen/event_channel.h>
#include <xen/io/fbif.h>
@@ -46,7 +46,7 @@
/* -------------------------------------------------------------------- */
struct common {
- struct XenDevice xendev; /* must be first */
+ struct XenLegacyDevice xendev; /* must be first */
void *page;
};
@@ -342,14 +342,14 @@ static QemuInputHandler xenfb_rel_mouse = {
.sync = xenfb_mouse_sync,
};
-static int input_init(struct XenDevice *xendev)
+static int input_init(struct XenLegacyDevice *xendev)
{
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
xenstore_write_be_int(xendev, "feature-raw-pointer", 1);
return 0;
}
-static int input_initialise(struct XenDevice *xendev)
+static int input_initialise(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
int rc;
@@ -361,7 +361,7 @@ static int input_initialise(struct XenDevice *xendev)
return 0;
}
-static void input_connected(struct XenDevice *xendev)
+static void input_connected(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
@@ -395,7 +395,7 @@ static void input_connected(struct XenDevice *xendev)
}
}
-static void input_disconnect(struct XenDevice *xendev)
+static void input_disconnect(struct XenLegacyDevice *xendev)
{
struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
@@ -410,7 +410,7 @@ static void input_disconnect(struct XenDevice *xendev)
common_unbind(&in->c);
}
-static void input_event(struct XenDevice *xendev)
+static void input_event(struct XenLegacyDevice *xendev)
{
struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
struct xenkbd_page *page = xenfb->c.page;
@@ -867,7 +867,7 @@ static void xenfb_handle_events(struct XenFB *xenfb)
page->out_cons = cons;
}
-static int fb_init(struct XenDevice *xendev)
+static int fb_init(struct XenLegacyDevice *xendev)
{
#ifdef XENFB_TYPE_RESIZE
xenstore_write_be_int(xendev, "feature-resize", 1);
@@ -875,7 +875,7 @@ static int fb_init(struct XenDevice *xendev)
return 0;
}
-static int fb_initialise(struct XenDevice *xendev)
+static int fb_initialise(struct XenLegacyDevice *xendev)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
struct xenfb_page *fb_page;
@@ -912,7 +912,7 @@ static int fb_initialise(struct XenDevice *xendev)
return 0;
}
-static void fb_disconnect(struct XenDevice *xendev)
+static void fb_disconnect(struct XenLegacyDevice *xendev)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
@@ -935,7 +935,8 @@ static void fb_disconnect(struct XenDevice *xendev)
fb->bug_trigger = 0;
}
-static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+static void fb_frontend_changed(struct XenLegacyDevice *xendev,
+ const char *node)
{
struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
@@ -953,7 +954,7 @@ static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
}
}
-static void fb_event(struct XenDevice *xendev)
+static void fb_event(struct XenLegacyDevice *xendev)
{
struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c
index b97a6c1767..c89eade029 100644
--- a/hw/dma/puv3_dma.c
+++ b/hw/dma/puv3_dma.c
@@ -76,7 +76,7 @@ static const MemoryRegionOps puv3_dma_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int puv3_dma_init(SysBusDevice *dev)
+static void puv3_dma_realize(DeviceState *dev, Error **errp)
{
PUV3DMAState *s = PUV3_DMA(dev);
int i;
@@ -87,16 +87,14 @@ static int puv3_dma_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma",
PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
static void puv3_dma_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = puv3_dma_init;
+ dc->realize = puv3_dma_realize;
}
static const TypeInfo puv3_dma_info = {
diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c
index f4eb26cf17..d498de8ffe 100644
--- a/hw/dma/pxa2xx_dma.c
+++ b/hw/dma/pxa2xx_dma.c
@@ -228,7 +228,7 @@ static void pxa2xx_dma_run(PXA2xxDMAState *s)
!(ch->state & DCSR_NODESCFETCH))
pxa2xx_dma_descriptor_fetch(s, c);
break;
- }
+ }
}
ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
@@ -283,7 +283,7 @@ static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
case DCSR0 ... DCSR31:
channel = offset >> 2;
- if (s->chan[channel].request)
+ if (s->chan[channel].request)
return s->chan[channel].state | DCSR_REQPEND;
return s->chan[channel].state;
diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c
index 45516241c6..58502721fa 100644
--- a/hw/dma/soc_dma.c
+++ b/hw/dma/soc_dma.c
@@ -345,7 +345,7 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
while (entry < dma->memmap + dma->memmap_size &&
entry->addr <= virt_base)
entry ++;
- }
+ }
memmove(entry + 1, entry,
(uint8_t *) (dma->memmap + dma->memmap_size ++) -
diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index fa0a72e6d0..e5da0cb54f 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -8,3 +8,4 @@ common-obj-$(CONFIG_GPIO_KEY) += gpio_key.o
obj-$(CONFIG_OMAP) += omap_gpio.o
obj-$(CONFIG_IMX) += imx_gpio.o
obj-$(CONFIG_RASPI) += bcm2835_gpio.o
+obj-$(CONFIG_NRF51_SOC) += nrf51_gpio.o
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
index a560e3afd2..1a2478b5a9 100644
--- a/hw/gpio/max7310.c
+++ b/hw/gpio/max7310.c
@@ -118,7 +118,7 @@ static int max7310_tx(I2CSlave *i2c, uint8_t data)
break;
case 0x00: /* Input port - ignore writes */
- break;
+ break;
default:
#ifdef VERBOSE
printf("%s: unknown register %02x\n", __func__, s->command);
diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c
new file mode 100644
index 0000000000..86e047d649
--- /dev/null
+++ b/hw/gpio/nrf51_gpio.c
@@ -0,0 +1,300 @@
+/*
+ * nRF51 System-on-Chip general purpose input/output register definition
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/gpio/nrf51_gpio.h"
+#include "trace.h"
+
+/*
+ * Check if the output driver is connected to the direction switch
+ * given the current configuration and logic level.
+ * It is not differentiated between standard and "high"(-power) drive modes.
+ */
+static bool is_connected(uint32_t config, uint32_t level)
+{
+ bool state;
+ uint32_t drive_config = extract32(config, 8, 3);
+
+ switch (drive_config) {
+ case 0 ... 3:
+ state = true;
+ break;
+ case 4 ... 5:
+ state = level != 0;
+ break;
+ case 6 ... 7:
+ state = level == 0;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ return state;
+}
+
+static void update_output_irq(NRF51GPIOState *s, size_t i,
+ bool connected, bool level)
+{
+ int64_t irq_level = connected ? level : -1;
+ bool old_connected = extract32(s->old_out_connected, i, 1);
+ bool old_level = extract32(s->old_out, i, 1);
+
+ if ((old_connected != connected) || (old_level != level)) {
+ qemu_set_irq(s->output[i], irq_level);
+ trace_nrf51_gpio_update_output_irq(i, irq_level);
+ }
+
+ s->old_out = deposit32(s->old_out, i, 1, level);
+ s->old_out_connected = deposit32(s->old_out_connected, i, 1, connected);
+}
+
+static void update_state(NRF51GPIOState *s)
+{
+ uint32_t pull;
+ size_t i;
+ bool connected_out, dir, connected_in, out, input;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ pull = extract32(s->cnf[i], 2, 2);
+ dir = extract32(s->cnf[i], 0, 1);
+ connected_in = extract32(s->in_mask, i, 1);
+ out = extract32(s->out, i, 1);
+ input = !extract32(s->cnf[i], 1, 1);
+ connected_out = is_connected(s->cnf[i], out) && dir;
+
+ update_output_irq(s, i, connected_out, out);
+
+ /* Pin both driven externally and internally */
+ if (connected_out && connected_in) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
+ }
+
+ /*
+ * Input buffer disconnected from internal/external drives, so
+ * pull-up/pull-down becomes relevant
+ */
+ if (!input || (input && !connected_in && !connected_out)) {
+ if (pull == NRF51_GPIO_PULLDOWN) {
+ s->in = deposit32(s->in, i, 1, 0);
+ } else if (pull == NRF51_GPIO_PULLUP) {
+ s->in = deposit32(s->in, i, 1, 1);
+ }
+ }
+
+ /* Self stimulation through internal output driver */
+ if (connected_out && !connected_in && input) {
+ s->in = deposit32(s->in, i, 1, out);
+ }
+ }
+
+}
+
+/*
+ * Direction is exposed in both the DIR register and the DIR bit
+ * of each PINs CNF configuration register. Reflect bits for pins in DIR
+ * to individual pin configuration registers.
+ */
+static void reflect_dir_bit_in_cnf(NRF51GPIOState *s)
+{
+ size_t i;
+
+ uint32_t value = s->dir;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ s->cnf[i] = (s->cnf[i] & ~(1UL)) | ((value >> i) & 0x01);
+ }
+}
+
+static uint64_t nrf51_gpio_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+ uint64_t r = 0;
+ size_t idx;
+
+ switch (offset) {
+ case NRF51_GPIO_REG_OUT ... NRF51_GPIO_REG_OUTCLR:
+ r = s->out;
+ break;
+
+ case NRF51_GPIO_REG_IN:
+ r = s->in;
+ break;
+
+ case NRF51_GPIO_REG_DIR ... NRF51_GPIO_REG_DIRCLR:
+ r = s->dir;
+ break;
+
+ case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
+ idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
+ r = s->cnf[idx];
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_nrf51_gpio_read(offset, r);
+
+ return r;
+}
+
+static void nrf51_gpio_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+ size_t idx;
+
+ trace_nrf51_gpio_write(offset, value);
+
+ switch (offset) {
+ case NRF51_GPIO_REG_OUT:
+ s->out = value;
+ break;
+
+ case NRF51_GPIO_REG_OUTSET:
+ s->out |= value;
+ break;
+
+ case NRF51_GPIO_REG_OUTCLR:
+ s->out &= ~value;
+ break;
+
+ case NRF51_GPIO_REG_DIR:
+ s->dir = value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_DIRSET:
+ s->dir |= value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_DIRCLR:
+ s->dir &= ~value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
+ idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
+ s->cnf[idx] = value;
+ /*
+ * direction is exposed in both the DIR register and the DIR bit
+ * of each PINs CNF configuration register.
+ */
+ s->dir = (s->dir & ~(1UL << idx)) | ((value & 0x01) << idx);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_state(s);
+}
+
+static const MemoryRegionOps gpio_ops = {
+ .read = nrf51_gpio_read,
+ .write = nrf51_gpio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void nrf51_gpio_set(void *opaque, int line, int value)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+
+ trace_nrf51_gpio_set(line, value);
+
+ assert(line >= 0 && line < NRF51_GPIO_PINS);
+
+ s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
+ if (value >= 0) {
+ s->in = deposit32(s->in, line, 1, value != 0);
+ }
+
+ update_state(s);
+}
+
+static void nrf51_gpio_reset(DeviceState *dev)
+{
+ NRF51GPIOState *s = NRF51_GPIO(dev);
+ size_t i;
+
+ s->out = 0;
+ s->old_out = 0;
+ s->old_out_connected = 0;
+ s->in = 0;
+ s->in_mask = 0;
+ s->dir = 0;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ s->cnf[i] = 0x00000002;
+ }
+}
+
+static const VMStateDescription vmstate_nrf51_gpio = {
+ .name = TYPE_NRF51_GPIO,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(out, NRF51GPIOState),
+ VMSTATE_UINT32(in, NRF51GPIOState),
+ VMSTATE_UINT32(in_mask, NRF51GPIOState),
+ VMSTATE_UINT32(dir, NRF51GPIOState),
+ VMSTATE_UINT32_ARRAY(cnf, NRF51GPIOState, NRF51_GPIO_PINS),
+ VMSTATE_UINT32(old_out, NRF51GPIOState),
+ VMSTATE_UINT32(old_out_connected, NRF51GPIOState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_gpio_init(Object *obj)
+{
+ NRF51GPIOState *s = NRF51_GPIO(obj);
+
+ memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
+ TYPE_NRF51_GPIO, NRF51_GPIO_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_in(DEVICE(s), nrf51_gpio_set, NRF51_GPIO_PINS);
+ qdev_init_gpio_out(DEVICE(s), s->output, NRF51_GPIO_PINS);
+}
+
+static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_nrf51_gpio;
+ dc->reset = nrf51_gpio_reset;
+ dc->desc = "nRF51 GPIO";
+}
+
+static const TypeInfo nrf51_gpio_info = {
+ .name = TYPE_NRF51_GPIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51GPIOState),
+ .instance_init = nrf51_gpio_init,
+ .class_init = nrf51_gpio_class_init
+};
+
+static void nrf51_gpio_register_types(void)
+{
+ type_register_static(&nrf51_gpio_info);
+}
+
+type_init(nrf51_gpio_register_types)
diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c
index 445afccf9f..33241b8564 100644
--- a/hw/gpio/puv3_gpio.c
+++ b/hw/gpio/puv3_gpio.c
@@ -99,36 +99,35 @@ static const MemoryRegionOps puv3_gpio_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int puv3_gpio_init(SysBusDevice *dev)
+static void puv3_gpio_realize(DeviceState *dev, Error **errp)
{
PUV3GPIOState *s = PUV3_GPIO(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
s->reg_GPLR = 0;
s->reg_GPDR = 0;
/* FIXME: these irqs not handled yet */
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
- sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW0]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW1]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW2]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW3]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW4]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW5]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW6]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW7]);
+ sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOHIGH]);
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio",
PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
+ sysbus_init_mmio(sbd, &s->iomem);
}
static void puv3_gpio_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = puv3_gpio_init;
+ dc->realize = puv3_gpio_realize;
}
static const TypeInfo puv3_gpio_info = {
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
new file mode 100644
index 0000000000..cb41a89756
--- /dev/null
+++ b/hw/gpio/trace-events
@@ -0,0 +1,7 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/gpio/nrf51_gpio.c
+nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
+nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
+nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
+nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 \ No newline at end of file
diff --git a/hw/i2c/bitbang_i2c.h b/hw/i2c/bitbang_i2c.h
index 3a7126d5de..9443021710 100644
--- a/hw/i2c/bitbang_i2c.h
+++ b/hw/i2c/bitbang_i2c.h
@@ -3,8 +3,6 @@
#include "hw/i2c/i2c.h"
-typedef struct bitbang_i2c_interface bitbang_i2c_interface;
-
#define BITBANG_I2C_SDA 0
#define BITBANG_I2C_SCL 1
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
index be34fe072c..0a0367ff38 100644
--- a/hw/i2c/i2c-ddc.c
+++ b/hw/i2c/i2c-ddc.c
@@ -56,7 +56,7 @@ static int i2c_ddc_rx(I2CSlave *i2c)
I2CDDCState *s = I2CDDC(i2c);
int value;
- value = s->edid_blob[s->reg];
+ value = s->edid_blob[s->reg % sizeof(s->edid_blob)];
s->reg++;
return value;
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 236a20eaa8..2e21a31f82 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
bool pcihp_bridge_en;
} AcpiBuildPciBusHotplugState;
+typedef struct FwCfgTPMConfig {
+ uint32_t tpmppi_address;
+ uint8_t tpm_version;
+ uint8_t tpmppi_version;
+} QEMU_PACKED FwCfgTPMConfig;
+
static void init_common_fadt_data(Object *o, AcpiFadtData *data)
{
uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
@@ -1796,6 +1802,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
uint32_t nr_mem = machine->ram_slots;
int root_bus_limit = 0xFF;
PCIBus *bus = NULL;
+ TPMIf *tpm = tpm_find();
int i;
dsdt = init_aml_allocator();
@@ -2133,7 +2140,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);
- if (TPM_IS_TIS(tpm_find())) {
+ if (TPM_IS_TIS(tpm)) {
dev = aml_device("ISA.TPM");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
@@ -2147,6 +2154,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
*/
/* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
aml_append(dev, aml_name_decl("_CRS", crs));
+
+ tpm_build_ppi_acpi(tpm, dev);
+
aml_append(scope, dev);
}
@@ -2154,7 +2164,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
- if (TPM_IS_CRB(tpm_find())) {
+ if (TPM_IS_CRB(tpm)) {
dev = aml_device("TPM");
aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
crs = aml_resource_template();
@@ -2166,6 +2176,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(method, aml_return(aml_int(0x0f)));
aml_append(dev, method);
+ tpm_build_ppi_acpi(tpm, dev);
+
aml_append(sb_scope, dev);
}
@@ -2426,7 +2438,7 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker)
IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
assert(iommu);
- if (iommu->intr_supported) {
+ if (x86_iommu_ir_supported(iommu)) {
dmar_flags |= 0x1; /* Flags: 0x1: INT_REMAP */
}
@@ -2499,7 +2511,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
* When interrupt remapping is supported, we add a special IVHD device
* for type IO-APIC.
*/
- if (x86_iommu_get_default()->intr_supported) {
+ if (x86_iommu_ir_supported(x86_iommu_get_default())) {
ivhd_table_len += 8;
}
/* IVHD length */
@@ -2535,7 +2547,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
* Linux IOMMU driver checks for the special IVHD device (type IO-APIC).
* See Linux kernel commit 'c2ff5cf5294bcbd7fa50f7d860e90a66db7e5059'
*/
- if (x86_iommu_get_default()->intr_supported) {
+ if (x86_iommu_ir_supported(x86_iommu_get_default())) {
build_append_int_noprefix(table_data,
(0x1ull << 56) | /* type IOAPIC */
(IOAPIC_SB_DEVID << 40) | /* IOAPIC devid */
@@ -2547,32 +2559,6 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker)
"IVRS", table_data->len - iommu_start, 1, NULL, NULL);
}
-static GArray *
-build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset)
-{
- AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
- unsigned rsdt_pa_size = sizeof(rsdp->rsdt_physical_address);
- unsigned rsdt_pa_offset =
- (char *)&rsdp->rsdt_physical_address - rsdp_table->data;
-
- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16,
- true /* fseg memory */);
-
- memcpy(&rsdp->signature, "RSD PTR ", 8);
- memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6);
- /* Address to be filled by Guest linker */
- bios_linker_loader_add_pointer(linker,
- ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size,
- ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset);
-
- /* Checksum to be filled by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE,
- (char *)rsdp - rsdp_table->data, sizeof *rsdp,
- (char *)&rsdp->checksum - rsdp_table->data);
-
- return rsdp_table;
-}
-
typedef
struct AcpiBuildState {
/* Copy of table in RAM (for patching). */
@@ -2729,7 +2715,25 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
slic_oem.id, slic_oem.table_id);
/* RSDP is in FSEG memory, so allocate it separately */
- build_rsdp(tables->rsdp, tables->linker, rsdt);
+ {
+ AcpiRsdpData rsdp_data = {
+ .revision = 0,
+ .oem_id = ACPI_BUILD_APPNAME6,
+ .xsdt_tbl_offset = NULL,
+ .rsdt_tbl_offset = &rsdt,
+ };
+ build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+ if (!pcmc->rsdp_in_ram) {
+ /* We used to allocate some extra space for RSDP revision 2 but
+ * only used the RSDP revision 0 space. The extra bytes were
+ * zeroed out and not used.
+ * Here we continue wasting those extra 16 bytes to make sure we
+ * don't break migration for machine types 2.2 and older due to
+ * RSDP blob size mismatch.
+ */
+ build_append_int_noprefix(tables->rsdp, 0, 16);
+ }
+ }
/* We'll expose it all to Guest so we want to reduce
* chance of size changes.
@@ -2855,6 +2859,8 @@ void acpi_setup(void)
AcpiBuildTables tables;
AcpiBuildState *build_state;
Object *vmgenid_dev;
+ TPMIf *tpm;
+ static FwCfgTPMConfig tpm_config;
if (!pcms->fw_cfg) {
ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
@@ -2889,6 +2895,17 @@ void acpi_setup(void)
fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
+ tpm = tpm_find();
+ if (tpm && object_property_get_bool(OBJECT(tpm), "ppi", &error_abort)) {
+ tpm_config = (FwCfgTPMConfig) {
+ .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
+ .tpm_version = tpm_get_version(tpm),
+ .tpmppi_version = TPM_PPI_VERSION_1_30
+ };
+ fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
+ &tpm_config, sizeof tpm_config);
+ }
+
vmgenid_dev = find_vmgenid_dev();
if (vmgenid_dev) {
vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 353a810e6b..8ad707aba0 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -1233,7 +1233,7 @@ static int amdvi_int_remap_msi(AMDVIState *iommu,
}
/* validate that we are configure with intremap=on */
- if (!X86_IOMMU_DEVICE(iommu)->intr_supported) {
+ if (!x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu))) {
trace_amdvi_err("Interrupt remapping is enabled in the guest but "
"not in the host. Use intremap=on to enable interrupt "
"remapping in amd-iommu.");
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index d97bcbc2f7..8b72735650 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -524,7 +524,6 @@ static int vtd_get_root_entry(IntelIOMMUState *s, uint8_t index,
addr = s->root + index * sizeof(*re);
if (dma_memory_read(&address_space_memory, addr, re, sizeof(*re))) {
- trace_vtd_re_invalid(re->rsvd, re->val);
re->val = 0;
return -VTD_FR_ROOT_TABLE_INV;
}
@@ -545,7 +544,6 @@ static int vtd_get_context_entry_from_root(VTDRootEntry *root, uint8_t index,
/* we have checked that root entry is present */
addr = (root->val & VTD_ROOT_ENTRY_CTP) + index * sizeof(*ce);
if (dma_memory_read(&address_space_memory, addr, ce, sizeof(*ce))) {
- trace_vtd_re_invalid(root->rsvd, root->val);
return -VTD_FR_CONTEXT_TABLE_INV;
}
ce->lo = le64_to_cpu(ce->lo);
@@ -630,16 +628,20 @@ static inline bool vtd_ce_type_check(X86IOMMUState *x86_iommu,
break;
case VTD_CONTEXT_TT_DEV_IOTLB:
if (!x86_iommu->dt_supported) {
+ error_report_once("%s: DT specified but not supported", __func__);
return false;
}
break;
case VTD_CONTEXT_TT_PASS_THROUGH:
if (!x86_iommu->pt_supported) {
+ error_report_once("%s: PT specified but not supported", __func__);
return false;
}
break;
default:
/* Unknwon type */
+ error_report_once("%s: unknown ce type: %"PRIu32, __func__,
+ vtd_ce_get_type(ce));
return false;
}
return true;
@@ -1003,7 +1005,9 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
}
if (re.rsvd || (re.val & VTD_ROOT_ENTRY_RSVD(s->aw_bits))) {
- trace_vtd_re_invalid(re.rsvd, re.val);
+ error_report_once("%s: invalid root entry: rsvd=0x%"PRIx64
+ ", val=0x%"PRIx64" (reserved nonzero)",
+ __func__, re.rsvd, re.val);
return -VTD_FR_ROOT_ENTRY_RSVD;
}
@@ -1020,19 +1024,23 @@ static int vtd_dev_to_context_entry(IntelIOMMUState *s, uint8_t bus_num,
if ((ce->hi & VTD_CONTEXT_ENTRY_RSVD_HI) ||
(ce->lo & VTD_CONTEXT_ENTRY_RSVD_LO(s->aw_bits))) {
- trace_vtd_ce_invalid(ce->hi, ce->lo);
+ error_report_once("%s: invalid context entry: hi=%"PRIx64
+ ", lo=%"PRIx64" (reserved nonzero)",
+ __func__, ce->hi, ce->lo);
return -VTD_FR_CONTEXT_ENTRY_RSVD;
}
/* Check if the programming of context-entry is valid */
if (!vtd_is_level_supported(s, vtd_ce_get_level(ce))) {
- trace_vtd_ce_invalid(ce->hi, ce->lo);
+ error_report_once("%s: invalid context entry: hi=%"PRIx64
+ ", lo=%"PRIx64" (level %d not supported)",
+ __func__, ce->hi, ce->lo, vtd_ce_get_level(ce));
return -VTD_FR_CONTEXT_ENTRY_INV;
}
/* Do translation type check */
if (!vtd_ce_type_check(x86_iommu, ce)) {
- trace_vtd_ce_invalid(ce->hi, ce->lo);
+ /* Errors dumped in vtd_ce_type_check() */
return -VTD_FR_CONTEXT_ENTRY_INV;
}
@@ -1878,7 +1886,9 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
{
if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
(inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
- trace_vtd_inv_desc_wait_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
+ " (reserved nonzero)", __func__, inv_desc->hi,
+ inv_desc->lo);
return false;
}
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
@@ -1901,7 +1911,9 @@ static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
/* Interrupt flag */
vtd_generate_completion_event(s);
} else {
- trace_vtd_inv_desc_wait_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
+ " (unknown type)", __func__, inv_desc->hi,
+ inv_desc->lo);
return false;
}
return true;
@@ -1913,7 +1925,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
uint16_t sid, fmask;
if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
- trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
+ " (reserved nonzero)", __func__, inv_desc->hi,
+ inv_desc->lo);
return false;
}
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
@@ -1932,7 +1946,9 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
break;
default:
- trace_vtd_inv_desc_cc_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
+ " (invalid type)", __func__, inv_desc->hi,
+ inv_desc->lo);
return false;
}
return true;
@@ -1946,7 +1962,9 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
(inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
- trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64" (reserved bits unzero)\n",
+ __func__, inv_desc->hi, inv_desc->lo);
return false;
}
@@ -1965,14 +1983,20 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
addr = VTD_INV_DESC_IOTLB_ADDR(inv_desc->hi);
am = VTD_INV_DESC_IOTLB_AM(inv_desc->hi);
if (am > VTD_MAMV) {
- trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64" (am=%u > VTD_MAMV=%u)\n",
+ __func__, inv_desc->hi, inv_desc->lo,
+ am, (unsigned)VTD_MAMV);
return false;
}
vtd_iotlb_page_invalidate(s, domain_id, addr, am);
break;
default:
- trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64" (type mismatch: 0x%llx)\n",
+ __func__, inv_desc->hi, inv_desc->lo,
+ inv_desc->lo & VTD_INV_DESC_IOTLB_G);
return false;
}
return true;
@@ -2012,7 +2036,9 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
(inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
- trace_vtd_inv_desc_iotlb_invalid(inv_desc->hi, inv_desc->lo);
+ error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
+ ", lo=%"PRIx64" (reserved nonzero)", __func__,
+ inv_desc->hi, inv_desc->lo);
return false;
}
@@ -2103,7 +2129,9 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
break;
default:
- trace_vtd_inv_desc_invalid(inv_desc.hi, inv_desc.lo);
+ error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
+ " (unknown type)", __func__, inv_desc.hi,
+ inv_desc.lo);
return false;
}
s->iq_head++;
@@ -2540,7 +2568,7 @@ static IOMMUTLBEntry vtd_iommu_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
__func__, pci_bus_num(vtd_as->bus),
VTD_PCI_SLOT(vtd_as->devfn),
VTD_PCI_FUNC(vtd_as->devfn),
- iotlb.iova);
+ addr);
}
return iotlb;
@@ -2628,9 +2656,10 @@ static Property vtd_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false),
- DEFINE_PROP_UINT8("x-aw-bits", IntelIOMMUState, aw_bits,
+ DEFINE_PROP_UINT8("aw-bits", IntelIOMMUState, aw_bits,
VTD_HOST_ADDRESS_WIDTH),
DEFINE_PROP_BOOL("caching-mode", IntelIOMMUState, caching_mode, FALSE),
+ DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -3119,6 +3148,9 @@ static void vtd_init(IntelIOMMUState *s)
s->cap = VTD_CAP_FRO | VTD_CAP_NFR | VTD_CAP_ND |
VTD_CAP_MAMV | VTD_CAP_PSI | VTD_CAP_SLLPS |
VTD_CAP_SAGAW_39bit | VTD_CAP_MGAW(s->aw_bits);
+ if (s->dma_drain) {
+ s->cap |= VTD_CAP_DRAIN;
+ }
if (s->aw_bits == VTD_HOST_AW_48BIT) {
s->cap |= VTD_CAP_SAGAW_48bit;
}
@@ -3137,7 +3169,7 @@ static void vtd_init(IntelIOMMUState *s)
vtd_paging_entry_rsvd_field[7] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits);
vtd_paging_entry_rsvd_field[8] = VTD_SPTE_LPAGE_L4_RSVD_MASK(s->aw_bits);
- if (x86_iommu->intr_supported) {
+ if (x86_iommu_ir_supported(x86_iommu)) {
s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
if (s->intr_eim == ON_OFF_AUTO_ON) {
s->ecap |= VTD_ECAP_EIM;
@@ -3238,14 +3270,14 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
{
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
- if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu->intr_supported) {
+ if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu_ir_supported(x86_iommu)) {
error_setg(errp, "eim=on cannot be selected without intremap=on");
return false;
}
if (s->intr_eim == ON_OFF_AUTO_AUTO) {
s->intr_eim = (kvm_irqchip_in_kernel() || s->buggy_eim)
- && x86_iommu->intr_supported ?
+ && x86_iommu_ir_supported(x86_iommu) ?
ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) {
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index d084099ed9..00e9edbc66 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -203,6 +203,9 @@
#define VTD_CAP_MAMV (VTD_MAMV << 48)
#define VTD_CAP_PSI (1ULL << 39)
#define VTD_CAP_SLLPS ((1ULL << 34) | (1ULL << 35))
+#define VTD_CAP_DRAIN_WRITE (1ULL << 54)
+#define VTD_CAP_DRAIN_READ (1ULL << 55)
+#define VTD_CAP_DRAIN (VTD_CAP_DRAIN_READ | VTD_CAP_DRAIN_WRITE)
#define VTD_CAP_CM (1ULL << 7)
/* Supported Adjusted Guest Address Widths */
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
index 5b40d75439..e453692199 100644
--- a/hw/i386/kvm/ioapic.c
+++ b/hw/i386/kvm/ioapic.c
@@ -163,7 +163,7 @@ static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo kvm_ioapic_info = {
- .name = "kvm-ioapic",
+ .name = TYPE_KVM_IOAPIC,
.parent = TYPE_IOAPIC_COMMON,
.instance_size = sizeof(KVMIOAPICState),
.class_init = kvm_ioapic_class_init,
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 1a4344f5fc..62340687e8 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -343,7 +343,11 @@ int load_multiboot(FWCfgState *fw_cfg,
mbs.mb_buf_size = TARGET_PAGE_ALIGN(mb_mod_length + mbs.mb_buf_size);
mbs.mb_buf = g_realloc(mbs.mb_buf, mbs.mb_buf_size);
- load_image(one_file, (unsigned char *)mbs.mb_buf + offs);
+ if (load_image_size(one_file, (unsigned char *)mbs.mb_buf + offs,
+ mbs.mb_buf_size - offs) < 0) {
+ error_report("Error loading file '%s'", one_file);
+ exit(1);
+ }
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
mbs.mb_buf_phys + offs + mb_mod_length, c);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index f095725dba..73d688f842 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -37,7 +37,7 @@
#include "hw/pci/pci_bus.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/timer/hpet.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "hw/loader.h"
#include "elf.h"
#include "multiboot.h"
@@ -72,6 +72,7 @@
#include "qapi/visitor.h"
#include "qom/cpu.h"
#include "hw/nmi.h"
+#include "hw/usb.h"
#include "hw/i386/intel_iommu.h"
#include "hw/net/ne2000-isa.h"
@@ -109,6 +110,231 @@ static struct e820_entry *e820_table;
static unsigned e820_entries;
struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
+GlobalProperty pc_compat_3_1[] = {
+ { "intel-iommu", "dma-drain", "off" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "off" },
+ { "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "off" },
+ { "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "off" },
+ { "Skylake-Client" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Skylake-Client-IBRS" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Skylake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Skylake-Server-IBRS" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Cascadelake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Icelake-Client" "-" TYPE_X86_CPU, "mpx", "on" },
+ { "Icelake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
+};
+const size_t pc_compat_3_1_len = G_N_ELEMENTS(pc_compat_3_1);
+
+GlobalProperty pc_compat_3_0[] = {
+ { TYPE_X86_CPU, "x-hv-synic-kvm-only", "on" },
+ { "Skylake-Server" "-" TYPE_X86_CPU, "pku", "off" },
+ { "Skylake-Server-IBRS" "-" TYPE_X86_CPU, "pku", "off" },
+};
+const size_t pc_compat_3_0_len = G_N_ELEMENTS(pc_compat_3_0);
+
+GlobalProperty pc_compat_2_12[] = {
+ { TYPE_X86_CPU, "legacy-cache", "on" },
+ { TYPE_X86_CPU, "topoext", "off" },
+ { "EPYC-" TYPE_X86_CPU, "xlevel", "0x8000000a" },
+ { "EPYC-IBPB-" TYPE_X86_CPU, "xlevel", "0x8000000a" },
+};
+const size_t pc_compat_2_12_len = G_N_ELEMENTS(pc_compat_2_12);
+
+GlobalProperty pc_compat_2_11[] = {
+ { TYPE_X86_CPU, "x-migrate-smi-count", "off" },
+ { "Skylake-Server" "-" TYPE_X86_CPU, "clflushopt", "off" },
+};
+const size_t pc_compat_2_11_len = G_N_ELEMENTS(pc_compat_2_11);
+
+GlobalProperty pc_compat_2_10[] = {
+ { TYPE_X86_CPU, "x-hv-max-vps", "0x40" },
+ { "i440FX-pcihost", "x-pci-hole64-fix", "off" },
+ { "q35-pcihost", "x-pci-hole64-fix", "off" },
+};
+const size_t pc_compat_2_10_len = G_N_ELEMENTS(pc_compat_2_10);
+
+GlobalProperty pc_compat_2_9[] = {
+ { "mch", "extended-tseg-mbytes", "0" },
+};
+const size_t pc_compat_2_9_len = G_N_ELEMENTS(pc_compat_2_9);
+
+GlobalProperty pc_compat_2_8[] = {
+ { TYPE_X86_CPU, "tcg-cpuid", "off" },
+ { "kvmclock", "x-mach-use-reliable-get-clock", "off" },
+ { "ICH9-LPC", "x-smi-broadcast", "off" },
+ { TYPE_X86_CPU, "vmware-cpuid-freq", "off" },
+ { "Haswell-" TYPE_X86_CPU, "stepping", "1" },
+};
+const size_t pc_compat_2_8_len = G_N_ELEMENTS(pc_compat_2_8);
+
+GlobalProperty pc_compat_2_7[] = {
+ { TYPE_X86_CPU, "l3-cache", "off" },
+ { TYPE_X86_CPU, "full-cpuid-auto-level", "off" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "family", "15" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "model", "6" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "stepping", "1" },
+ { "isa-pcspk", "migrate", "off" },
+};
+const size_t pc_compat_2_7_len = G_N_ELEMENTS(pc_compat_2_7);
+
+GlobalProperty pc_compat_2_6[] = {
+ { TYPE_X86_CPU, "cpuid-0xb", "off" },
+ { "vmxnet3", "romfile", "" },
+ { TYPE_X86_CPU, "fill-mtrr-mask", "off" },
+ { "apic-common", "legacy-instance-id", "on", }
+};
+const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6);
+
+GlobalProperty pc_compat_2_5[] = {};
+const size_t pc_compat_2_5_len = G_N_ELEMENTS(pc_compat_2_5);
+
+GlobalProperty pc_compat_2_4[] = {
+ PC_CPU_MODEL_IDS("2.4.0")
+ { "Haswell-" TYPE_X86_CPU, "abm", "off" },
+ { "Haswell-noTSX-" TYPE_X86_CPU, "abm", "off" },
+ { "Broadwell-" TYPE_X86_CPU, "abm", "off" },
+ { "Broadwell-noTSX-" TYPE_X86_CPU, "abm", "off" },
+ { "host" "-" TYPE_X86_CPU, "host-cache-info", "on" },
+ { TYPE_X86_CPU, "check", "off" },
+ { "qemu64" "-" TYPE_X86_CPU, "sse4a", "on" },
+ { "qemu64" "-" TYPE_X86_CPU, "abm", "on" },
+ { "qemu64" "-" TYPE_X86_CPU, "popcnt", "on" },
+ { "qemu32" "-" TYPE_X86_CPU, "popcnt", "on" },
+ { "Opteron_G2" "-" TYPE_X86_CPU, "rdtscp", "on" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "on" },
+ { "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "on" },
+ { "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "on", }
+};
+const size_t pc_compat_2_4_len = G_N_ELEMENTS(pc_compat_2_4);
+
+GlobalProperty pc_compat_2_3[] = {
+ PC_CPU_MODEL_IDS("2.3.0")
+ { TYPE_X86_CPU, "arat", "off" },
+ { "qemu64" "-" TYPE_X86_CPU, "min-level", "4" },
+ { "kvm64" "-" TYPE_X86_CPU, "min-level", "5" },
+ { "pentium3" "-" TYPE_X86_CPU, "min-level", "2" },
+ { "n270" "-" TYPE_X86_CPU, "min-level", "5" },
+ { "Conroe" "-" TYPE_X86_CPU, "min-level", "4" },
+ { "Penryn" "-" TYPE_X86_CPU, "min-level", "4" },
+ { "Nehalem" "-" TYPE_X86_CPU, "min-level", "4" },
+ { "n270" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Penryn" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Conroe" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Nehalem" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Westmere" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "SandyBridge" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "IvyBridge" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Haswell" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Haswell-noTSX" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Broadwell" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { "Broadwell-noTSX" "-" TYPE_X86_CPU, "min-xlevel", "0x8000000a" },
+ { TYPE_X86_CPU, "kvm-no-smi-migration", "on" },
+};
+const size_t pc_compat_2_3_len = G_N_ELEMENTS(pc_compat_2_3);
+
+GlobalProperty pc_compat_2_2[] = {
+ PC_CPU_MODEL_IDS("2.2.0")
+ { "kvm64" "-" TYPE_X86_CPU, "vme", "off" },
+ { "kvm32" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Conroe" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Penryn" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Nehalem" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Westmere" "-" TYPE_X86_CPU, "vme", "off" },
+ { "SandyBridge" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Haswell" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Broadwell" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Opteron_G1" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Opteron_G2" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Opteron_G3" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Opteron_G4" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Opteron_G5" "-" TYPE_X86_CPU, "vme", "off" },
+ { "Haswell" "-" TYPE_X86_CPU, "f16c", "off" },
+ { "Haswell" "-" TYPE_X86_CPU, "rdrand", "off" },
+ { "Broadwell" "-" TYPE_X86_CPU, "f16c", "off" },
+ { "Broadwell" "-" TYPE_X86_CPU, "rdrand", "off" },
+};
+const size_t pc_compat_2_2_len = G_N_ELEMENTS(pc_compat_2_2);
+
+GlobalProperty pc_compat_2_1[] = {
+ PC_CPU_MODEL_IDS("2.1.0")
+ { "coreduo" "-" TYPE_X86_CPU, "vmx", "on" },
+ { "core2duo" "-" TYPE_X86_CPU, "vmx", "on" },
+};
+const size_t pc_compat_2_1_len = G_N_ELEMENTS(pc_compat_2_1);
+
+GlobalProperty pc_compat_2_0[] = {
+ PC_CPU_MODEL_IDS("2.0.0")
+ { "virtio-scsi-pci", "any_layout", "off" },
+ { "PIIX4_PM", "memory-hotplug-support", "off" },
+ { "apic", "version", "0x11" },
+ { "nec-usb-xhci", "superspeed-ports-first", "off" },
+ { "nec-usb-xhci", "force-pcie-endcap", "on" },
+ { "pci-serial", "prog_if", "0" },
+ { "pci-serial-2x", "prog_if", "0" },
+ { "pci-serial-4x", "prog_if", "0" },
+ { "virtio-net-pci", "guest_announce", "off" },
+ { "ICH9-LPC", "memory-hotplug-support", "off" },
+ { "xio3130-downstream", COMPAT_PROP_PCP, "off" },
+ { "ioh3420", COMPAT_PROP_PCP, "off" },
+};
+const size_t pc_compat_2_0_len = G_N_ELEMENTS(pc_compat_2_0);
+
+GlobalProperty pc_compat_1_7[] = {
+ PC_CPU_MODEL_IDS("1.7.0")
+ { TYPE_USB_DEVICE, "msos-desc", "no" },
+ { "PIIX4_PM", "acpi-pci-hotplug-with-bridge-support", "off" },
+ { "hpet", HPET_INTCAP, "4" },
+};
+const size_t pc_compat_1_7_len = G_N_ELEMENTS(pc_compat_1_7);
+
+GlobalProperty pc_compat_1_6[] = {
+ PC_CPU_MODEL_IDS("1.6.0")
+ { "e1000", "mitigation", "off" },
+ { "qemu64-" TYPE_X86_CPU, "model", "2" },
+ { "qemu32-" TYPE_X86_CPU, "model", "3" },
+ { "i440FX-pcihost", "short_root_bus", "1" },
+ { "q35-pcihost", "short_root_bus", "1" },
+};
+const size_t pc_compat_1_6_len = G_N_ELEMENTS(pc_compat_1_6);
+
+GlobalProperty pc_compat_1_5[] = {
+ PC_CPU_MODEL_IDS("1.5.0")
+ { "Conroe-" TYPE_X86_CPU, "model", "2" },
+ { "Conroe-" TYPE_X86_CPU, "min-level", "2" },
+ { "Penryn-" TYPE_X86_CPU, "model", "2" },
+ { "Penryn-" TYPE_X86_CPU, "min-level", "2" },
+ { "Nehalem-" TYPE_X86_CPU, "model", "2" },
+ { "Nehalem-" TYPE_X86_CPU, "min-level", "2" },
+ { "virtio-net-pci", "any_layout", "off" },
+ { TYPE_X86_CPU, "pmu", "on" },
+ { "i440FX-pcihost", "short_root_bus", "0" },
+ { "q35-pcihost", "short_root_bus", "0" },
+};
+const size_t pc_compat_1_5_len = G_N_ELEMENTS(pc_compat_1_5);
+
+GlobalProperty pc_compat_1_4[] = {
+ PC_CPU_MODEL_IDS("1.4.0")
+ { "scsi-hd", "discard_granularity", "0" },
+ { "scsi-cd", "discard_granularity", "0" },
+ { "scsi-disk", "discard_granularity", "0" },
+ { "ide-hd", "discard_granularity", "0" },
+ { "ide-cd", "discard_granularity", "0" },
+ { "ide-drive", "discard_granularity", "0" },
+ { "virtio-blk-pci", "discard_granularity", "0" },
+ /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string: */
+ { "virtio-serial-pci", "vectors", "0xFFFFFFFF" },
+ { "virtio-net-pci", "ctrl_guest_offloads", "off" },
+ { "e1000", "romfile", "pxe-e1000.rom" },
+ { "ne2k_pci", "romfile", "pxe-ne2k_pci.rom" },
+ { "pcnet", "romfile", "pxe-pcnet.rom" },
+ { "rtl8139", "romfile", "pxe-rtl8139.rom" },
+ { "virtio-net-pci", "romfile", "pxe-virtio.rom" },
+ { "486-" TYPE_X86_CPU, "model", "0" },
+ { "n270" "-" TYPE_X86_CPU, "movbe", "off" },
+ { "Westmere" "-" TYPE_X86_CPU, "pclmulqdq", "off" },
+};
+const size_t pc_compat_1_4_len = G_N_ELEMENTS(pc_compat_1_4);
+
void gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
@@ -839,10 +1065,9 @@ static void load_linux(PCMachineState *pcms,
{
uint16_t protocol;
int setup_size, kernel_size, cmdline_size;
- int64_t initrd_size = 0;
int dtb_size, setup_data_offset;
uint32_t initrd_max;
- uint8_t header[8192], *setup, *kernel, *initrd_data;
+ uint8_t header[8192], *setup, *kernel;
hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0;
FILE *f;
char *vmode;
@@ -965,27 +1190,30 @@ static void load_linux(PCMachineState *pcms,
/* load initrd */
if (initrd_filename) {
+ gsize initrd_size;
+ gchar *initrd_data;
+ GError *gerr = NULL;
+
if (protocol < 0x200) {
fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
exit(1);
}
- initrd_size = get_image_size(initrd_filename);
- if (initrd_size < 0) {
+ if (!g_file_get_contents(initrd_filename, &initrd_data,
+ &initrd_size, &gerr)) {
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
- initrd_filename, strerror(errno));
+ initrd_filename, gerr->message);
exit(1);
- } else if (initrd_size >= initrd_max) {
+ }
+ if (initrd_size >= initrd_max) {
fprintf(stderr, "qemu: initrd is too large, cannot support."
- "(max: %"PRIu32", need %"PRId64")\n", initrd_max, initrd_size);
+ "(max: %"PRIu32", need %"PRId64")\n",
+ initrd_max, (uint64_t)initrd_size);
exit(1);
}
initrd_addr = (initrd_max-initrd_size) & ~4095;
- initrd_data = g_malloc(initrd_size);
- load_image(initrd_filename, initrd_data);
-
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
@@ -1242,7 +1470,7 @@ void pc_machine_done(Notifier *notifier, void *data)
if (pcms->apic_id_limit > 255 && !xen_enabled()) {
IntelIOMMUState *iommu = INTEL_IOMMU_DEVICE(x86_iommu_get_default());
- if (!iommu || !iommu->x86_iommu.intr_supported ||
+ if (!iommu || !x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu)) ||
iommu->intr_eim != ON_OFF_AUTO_ON) {
error_report("current -smp configuration requires "
"Extended Interrupt Mode enabled. "
@@ -1663,9 +1891,9 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
unsigned int i;
if (kvm_ioapic_in_kernel()) {
- dev = qdev_create(NULL, "kvm-ioapic");
+ dev = qdev_create(NULL, TYPE_KVM_IOAPIC);
} else {
- dev = qdev_create(NULL, "ioapic");
+ dev = qdev_create(NULL, TYPE_IOAPIC);
}
if (parent_name) {
object_property_add_child(object_resolve_path(parent_name, NULL),
@@ -2222,42 +2450,42 @@ static bool pc_machine_get_smbus(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- return pcms->smbus;
+ return pcms->smbus_enabled;
}
static void pc_machine_set_smbus(Object *obj, bool value, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- pcms->smbus = value;
+ pcms->smbus_enabled = value;
}
static bool pc_machine_get_sata(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- return pcms->sata;
+ return pcms->sata_enabled;
}
static void pc_machine_set_sata(Object *obj, bool value, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- pcms->sata = value;
+ pcms->sata_enabled = value;
}
static bool pc_machine_get_pit(Object *obj, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- return pcms->pit;
+ return pcms->pit_enabled;
}
static void pc_machine_set_pit(Object *obj, bool value, Error **errp)
{
PCMachineState *pcms = PC_MACHINE(obj);
- pcms->pit = value;
+ pcms->pit_enabled = value;
}
static void pc_machine_initfn(Object *obj)
@@ -2271,9 +2499,9 @@ static void pc_machine_initfn(Object *obj)
pcms->acpi_nvdimm_state.is_enabled = false;
/* acpi build is enabled by default if machine supports it */
pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
- pcms->smbus = true;
- pcms->sata = true;
- pcms->pit = true;
+ pcms->smbus_enabled = true;
+ pcms->sata_enabled = true;
+ pcms->pit_enabled = true;
}
static void pc_machine_reset(void)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7092d6d13f..63c84e3827 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -30,7 +30,7 @@
#include "hw/i386/pc.h"
#include "hw/i386/apic.h"
#include "hw/display/ramfb.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_ids.h"
#include "hw/usb.h"
@@ -239,7 +239,8 @@ static void pc_init1(MachineState *machine,
/* init basic PC hardware */
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true,
- (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit, 0x4);
+ (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled,
+ 0x4);
pc_nic_init(pcmc, isa_bus, pci_bus);
@@ -309,7 +310,7 @@ static void pc_init1(MachineState *machine,
* HW_COMPAT_*, PC_COMPAT_*, or * pc_*_machine_options().
*/
-static void pc_compat_2_3(MachineState *machine)
+static void pc_compat_2_3_fn(MachineState *machine)
{
PCMachineState *pcms = PC_MACHINE(machine);
if (kvm_enabled()) {
@@ -317,47 +318,46 @@ static void pc_compat_2_3(MachineState *machine)
}
}
-static void pc_compat_2_2(MachineState *machine)
+static void pc_compat_2_2_fn(MachineState *machine)
{
- pc_compat_2_3(machine);
- machine->suppress_vmdesc = true;
+ pc_compat_2_3_fn(machine);
}
-static void pc_compat_2_1(MachineState *machine)
+static void pc_compat_2_1_fn(MachineState *machine)
{
- pc_compat_2_2(machine);
+ pc_compat_2_2_fn(machine);
x86_cpu_change_kvm_default("svm", NULL);
}
-static void pc_compat_2_0(MachineState *machine)
+static void pc_compat_2_0_fn(MachineState *machine)
{
- pc_compat_2_1(machine);
+ pc_compat_2_1_fn(machine);
}
-static void pc_compat_1_7(MachineState *machine)
+static void pc_compat_1_7_fn(MachineState *machine)
{
- pc_compat_2_0(machine);
+ pc_compat_2_0_fn(machine);
x86_cpu_change_kvm_default("x2apic", NULL);
}
-static void pc_compat_1_6(MachineState *machine)
+static void pc_compat_1_6_fn(MachineState *machine)
{
- pc_compat_1_7(machine);
+ pc_compat_1_7_fn(machine);
}
-static void pc_compat_1_5(MachineState *machine)
+static void pc_compat_1_5_fn(MachineState *machine)
{
- pc_compat_1_6(machine);
+ pc_compat_1_6_fn(machine);
}
-static void pc_compat_1_4(MachineState *machine)
+static void pc_compat_1_4_fn(MachineState *machine)
{
- pc_compat_1_5(machine);
+ pc_compat_1_5_fn(machine);
}
static void pc_compat_1_3(MachineState *machine)
{
- pc_compat_1_4(machine);
+ pc_compat_1_4_fn(machine);
enable_compat_apic_id_mode();
}
@@ -368,7 +368,7 @@ static void pc_compat_1_2(MachineState *machine)
x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
}
-/* PC compat function for pc-0.10 to pc-0.13 */
+/* PC compat function for pc-0.12 and pc-0.13 */
static void pc_compat_0_13(MachineState *machine)
{
pc_compat_1_2(machine);
@@ -428,22 +428,33 @@ static void pc_i440fx_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
}
-static void pc_i440fx_3_1_machine_options(MachineClass *m)
+static void pc_i440fx_4_0_machine_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = 1;
}
+DEFINE_I440FX_MACHINE(v4_0, "pc-i440fx-4.0", NULL,
+ pc_i440fx_4_0_machine_options);
+
+static void pc_i440fx_3_1_machine_options(MachineClass *m)
+{
+ pc_i440fx_4_0_machine_options(m);
+ m->is_default = 0;
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len);
+ compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len);
+}
+
DEFINE_I440FX_MACHINE(v3_1, "pc-i440fx-3.1", NULL,
pc_i440fx_3_1_machine_options);
static void pc_i440fx_3_0_machine_options(MachineClass *m)
{
pc_i440fx_3_1_machine_options(m);
- m->is_default = 0;
- m->alias = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_3_0);
+ compat_props_add(m->compat_props, hw_compat_3_0, hw_compat_3_0_len);
+ compat_props_add(m->compat_props, pc_compat_3_0, pc_compat_3_0_len);
}
DEFINE_I440FX_MACHINE(v3_0, "pc-i440fx-3.0", NULL,
@@ -452,7 +463,8 @@ DEFINE_I440FX_MACHINE(v3_0, "pc-i440fx-3.0", NULL,
static void pc_i440fx_2_12_machine_options(MachineClass *m)
{
pc_i440fx_3_0_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_12);
+ compat_props_add(m->compat_props, hw_compat_2_12, hw_compat_2_12_len);
+ compat_props_add(m->compat_props, pc_compat_2_12, pc_compat_2_12_len);
}
DEFINE_I440FX_MACHINE(v2_12, "pc-i440fx-2.12", NULL,
@@ -461,7 +473,8 @@ DEFINE_I440FX_MACHINE(v2_12, "pc-i440fx-2.12", NULL,
static void pc_i440fx_2_11_machine_options(MachineClass *m)
{
pc_i440fx_2_12_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_11);
+ compat_props_add(m->compat_props, hw_compat_2_11, hw_compat_2_11_len);
+ compat_props_add(m->compat_props, pc_compat_2_11, pc_compat_2_11_len);
}
DEFINE_I440FX_MACHINE(v2_11, "pc-i440fx-2.11", NULL,
@@ -470,7 +483,8 @@ DEFINE_I440FX_MACHINE(v2_11, "pc-i440fx-2.11", NULL,
static void pc_i440fx_2_10_machine_options(MachineClass *m)
{
pc_i440fx_2_11_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_10);
+ compat_props_add(m->compat_props, hw_compat_2_10, hw_compat_2_10_len);
+ compat_props_add(m->compat_props, pc_compat_2_10, pc_compat_2_10_len);
m->auto_enable_numa_with_memhp = false;
}
@@ -480,7 +494,8 @@ DEFINE_I440FX_MACHINE(v2_10, "pc-i440fx-2.10", NULL,
static void pc_i440fx_2_9_machine_options(MachineClass *m)
{
pc_i440fx_2_10_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_9);
+ compat_props_add(m->compat_props, hw_compat_2_9, hw_compat_2_9_len);
+ compat_props_add(m->compat_props, pc_compat_2_9, pc_compat_2_9_len);
m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
}
@@ -490,108 +505,114 @@ DEFINE_I440FX_MACHINE(v2_9, "pc-i440fx-2.9", NULL,
static void pc_i440fx_2_8_machine_options(MachineClass *m)
{
pc_i440fx_2_9_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_8);
+ compat_props_add(m->compat_props, hw_compat_2_8, hw_compat_2_8_len);
+ compat_props_add(m->compat_props, pc_compat_2_8, pc_compat_2_8_len);
}
DEFINE_I440FX_MACHINE(v2_8, "pc-i440fx-2.8", NULL,
pc_i440fx_2_8_machine_options);
-
static void pc_i440fx_2_7_machine_options(MachineClass *m)
{
pc_i440fx_2_8_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_7);
+ compat_props_add(m->compat_props, hw_compat_2_7, hw_compat_2_7_len);
+ compat_props_add(m->compat_props, pc_compat_2_7, pc_compat_2_7_len);
}
DEFINE_I440FX_MACHINE(v2_7, "pc-i440fx-2.7", NULL,
pc_i440fx_2_7_machine_options);
-
static void pc_i440fx_2_6_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_7_machine_options(m);
pcmc->legacy_cpu_hotplug = true;
pcmc->linuxboot_dma_enabled = false;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
+ compat_props_add(m->compat_props, hw_compat_2_6, hw_compat_2_6_len);
+ compat_props_add(m->compat_props, pc_compat_2_6, pc_compat_2_6_len);
}
DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL,
pc_i440fx_2_6_machine_options);
-
static void pc_i440fx_2_5_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_6_machine_options(m);
pcmc->save_tsc_khz = false;
m->legacy_fw_cfg_order = 1;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
+ compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len);
+ compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len);
}
DEFINE_I440FX_MACHINE(v2_5, "pc-i440fx-2.5", NULL,
pc_i440fx_2_5_machine_options);
-
static void pc_i440fx_2_4_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_5_machine_options(m);
m->hw_version = "2.4.0";
pcmc->broken_reserved_end = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
+ compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len);
+ compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len);
}
DEFINE_I440FX_MACHINE(v2_4, "pc-i440fx-2.4", NULL,
pc_i440fx_2_4_machine_options)
-
static void pc_i440fx_2_3_machine_options(MachineClass *m)
{
pc_i440fx_2_4_machine_options(m);
m->hw_version = "2.3.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_3);
+ compat_props_add(m->compat_props, hw_compat_2_3, hw_compat_2_3_len);
+ compat_props_add(m->compat_props, pc_compat_2_3, pc_compat_2_3_len);
}
-DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3,
+DEFINE_I440FX_MACHINE(v2_3, "pc-i440fx-2.3", pc_compat_2_3_fn,
pc_i440fx_2_3_machine_options);
-
static void pc_i440fx_2_2_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_3_machine_options(m);
m->hw_version = "2.2.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_2);
+ m->default_machine_opts = "firmware=bios-256k.bin,suppress-vmdesc=on";
+ compat_props_add(m->compat_props, hw_compat_2_2, hw_compat_2_2_len);
+ compat_props_add(m->compat_props, pc_compat_2_2, pc_compat_2_2_len);
pcmc->rsdp_in_ram = false;
}
-DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2,
+DEFINE_I440FX_MACHINE(v2_2, "pc-i440fx-2.2", pc_compat_2_2_fn,
pc_i440fx_2_2_machine_options);
-
static void pc_i440fx_2_1_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_2_machine_options(m);
m->hw_version = "2.1.0";
m->default_display = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_1);
+ compat_props_add(m->compat_props, hw_compat_2_1, hw_compat_2_1_len);
+ compat_props_add(m->compat_props, pc_compat_2_1, pc_compat_2_1_len);
pcmc->smbios_uuid_encoded = false;
pcmc->enforce_aligned_dimm = false;
}
-DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1,
+DEFINE_I440FX_MACHINE(v2_1, "pc-i440fx-2.1", pc_compat_2_1_fn,
pc_i440fx_2_1_machine_options);
-
-
static void pc_i440fx_2_0_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_1_machine_options(m);
m->hw_version = "2.0.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_0);
+ compat_props_add(m->compat_props, pc_compat_2_0, pc_compat_2_0_len);
pcmc->smbios_legacy_mode = true;
pcmc->has_reserved_memory = false;
/* This value depends on the actual DSDT and SSDT compiled into
@@ -614,400 +635,216 @@ static void pc_i440fx_2_0_machine_options(MachineClass *m)
pcmc->acpi_data_size = 0x10000;
}
-DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0,
+DEFINE_I440FX_MACHINE(v2_0, "pc-i440fx-2.0", pc_compat_2_0_fn,
pc_i440fx_2_0_machine_options);
-
static void pc_i440fx_1_7_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_2_0_machine_options(m);
m->hw_version = "1.7.0";
m->default_machine_opts = NULL;
m->option_rom_has_mr = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_7);
+ compat_props_add(m->compat_props, pc_compat_1_7, pc_compat_1_7_len);
pcmc->smbios_defaults = false;
pcmc->gigabyte_align = false;
pcmc->legacy_acpi_table_size = 6414;
}
-DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7,
+DEFINE_I440FX_MACHINE(v1_7, "pc-i440fx-1.7", pc_compat_1_7_fn,
pc_i440fx_1_7_machine_options);
-
static void pc_i440fx_1_6_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_i440fx_1_7_machine_options(m);
m->hw_version = "1.6.0";
m->rom_file_has_mr = false;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_6);
+ compat_props_add(m->compat_props, pc_compat_1_6, pc_compat_1_6_len);
pcmc->has_acpi_build = false;
}
-DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6,
+DEFINE_I440FX_MACHINE(v1_6, "pc-i440fx-1.6", pc_compat_1_6_fn,
pc_i440fx_1_6_machine_options);
-
static void pc_i440fx_1_5_machine_options(MachineClass *m)
{
pc_i440fx_1_6_machine_options(m);
m->hw_version = "1.5.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_5);
+ compat_props_add(m->compat_props, pc_compat_1_5, pc_compat_1_5_len);
}
-DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5,
+DEFINE_I440FX_MACHINE(v1_5, "pc-i440fx-1.5", pc_compat_1_5_fn,
pc_i440fx_1_5_machine_options);
-
static void pc_i440fx_1_4_machine_options(MachineClass *m)
{
pc_i440fx_1_5_machine_options(m);
m->hw_version = "1.4.0";
m->hot_add_cpu = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_4);
+ compat_props_add(m->compat_props, pc_compat_1_4, pc_compat_1_4_len);
}
-DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
+DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4_fn,
pc_i440fx_1_4_machine_options);
-
-#define PC_COMPAT_1_3 \
- PC_CPU_MODEL_IDS("1.3.0") \
- {\
- .driver = "usb-tablet",\
- .property = "usb_version",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-net-pci",\
- .property = "ctrl_mac_addr",\
- .value = "off", \
- },{ \
- .driver = "virtio-net-pci", \
- .property = "mq", \
- .value = "off", \
- }, {\
- .driver = "e1000",\
- .property = "autonegotiation",\
- .value = "off",\
- },
-
-
static void pc_i440fx_1_3_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("1.3.0")
+ { "usb-tablet", "usb_version", "1" },
+ { "virtio-net-pci", "ctrl_mac_addr", "off" },
+ { "virtio-net-pci", "mq", "off" },
+ { "e1000", "autonegotiation", "off" },
+ };
+
pc_i440fx_1_4_machine_options(m);
m->hw_version = "1.3.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_3);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
pc_i440fx_1_3_machine_options);
-#define PC_COMPAT_1_2 \
- PC_CPU_MODEL_IDS("1.2.0") \
- {\
- .driver = "nec-usb-xhci",\
- .property = "msi",\
- .value = "off",\
- },{\
- .driver = "nec-usb-xhci",\
- .property = "msix",\
- .value = "off",\
- },{\
- .driver = "ivshmem",\
- .property = "use64",\
- .value = "0",\
- },{\
- .driver = "qxl",\
- .property = "revision",\
- .value = stringify(3),\
- },{\
- .driver = "qxl-vga",\
- .property = "revision",\
- .value = stringify(3),\
- },{\
- .driver = "VGA",\
- .property = "mmio",\
- .value = "off",\
- },
-
static void pc_i440fx_1_2_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("1.2.0")
+ { "nec-usb-xhci", "msi", "off" },
+ { "nec-usb-xhci", "msix", "off" },
+ { "qxl", "revision", "3" },
+ { "qxl-vga", "revision", "3" },
+ { "VGA", "mmio", "off" },
+ };
+
pc_i440fx_1_3_machine_options(m);
m->hw_version = "1.2.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_2);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
pc_i440fx_1_2_machine_options);
-#define PC_COMPAT_1_1 \
- PC_CPU_MODEL_IDS("1.1.0") \
- {\
- .driver = "virtio-scsi-pci",\
- .property = "hotplug",\
- .value = "off",\
- },{\
- .driver = "virtio-scsi-pci",\
- .property = "param_change",\
- .value = "off",\
- },{\
- .driver = "VGA",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "vmware-svga",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "qxl-vga",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "qxl",\
- .property = "vgamem_mb",\
- .value = stringify(8),\
- },{\
- .driver = "virtio-blk-pci",\
- .property = "config-wce",\
- .value = "off",\
- },
-
static void pc_i440fx_1_1_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("1.1.0")
+ { "virtio-scsi-pci", "hotplug", "off" },
+ { "virtio-scsi-pci", "param_change", "off" },
+ { "VGA", "vgamem_mb", "8" },
+ { "vmware-svga", "vgamem_mb", "8" },
+ { "qxl-vga", "vgamem_mb", "8" },
+ { "qxl", "vgamem_mb", "8" },
+ { "virtio-blk-pci", "config-wce", "off" },
+ };
+
pc_i440fx_1_2_machine_options(m);
m->hw_version = "1.1.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_1);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
pc_i440fx_1_1_machine_options);
-
-#define PC_COMPAT_1_0 \
- PC_CPU_MODEL_IDS("1.0") \
- {\
- .driver = TYPE_ISA_FDC,\
- .property = "check_media_rate",\
- .value = "off",\
- }, {\
- .driver = "virtio-balloon-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_MEMORY_RAM),\
- },{\
- .driver = "apic-common",\
- .property = "vapic",\
- .value = "off",\
- },{\
- .driver = TYPE_USB_DEVICE,\
- .property = "full-path",\
- .value = "no",\
- },
-
static void pc_i440fx_1_0_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("1.0")
+ { TYPE_ISA_FDC, "check_media_rate", "off" },
+ { "virtio-balloon-pci", "class", stringify(PCI_CLASS_MEMORY_RAM) },
+ { "apic-common", "vapic", "off" },
+ { TYPE_USB_DEVICE, "full-path", "no" },
+ };
+
pc_i440fx_1_1_machine_options(m);
m->hw_version = "1.0";
- SET_MACHINE_COMPAT(m, PC_COMPAT_1_0);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
pc_i440fx_1_0_machine_options);
-#define PC_COMPAT_0_15 \
- PC_CPU_MODEL_IDS("0.15")
-
static void pc_i440fx_0_15_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("0.15")
+ };
+
pc_i440fx_1_0_machine_options(m);
m->hw_version = "0.15";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
+ m->deprecation_reason = "use a newer machine type instead";
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
pc_i440fx_0_15_machine_options);
-#define PC_COMPAT_0_14 \
- PC_CPU_MODEL_IDS("0.14") \
- {\
- .driver = "virtio-blk-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-net-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "virtio-balloon-pci",\
- .property = "event_idx",\
- .value = "off",\
- },{\
- .driver = "qxl",\
- .property = "revision",\
- .value = stringify(2),\
- },{\
- .driver = "qxl-vga",\
- .property = "revision",\
- .value = stringify(2),\
- },
-
static void pc_i440fx_0_14_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("0.14")
+ { "virtio-blk-pci", "event_idx", "off" },
+ { "virtio-serial-pci", "event_idx", "off" },
+ { "virtio-net-pci", "event_idx", "off" },
+ { "virtio-balloon-pci", "event_idx", "off" },
+ { "qxl", "revision", "2" },
+ { "qxl-vga", "revision", "2" },
+ };
+
pc_i440fx_0_15_machine_options(m);
m->hw_version = "0.14";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_14);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
pc_i440fx_0_14_machine_options);
-
-#define PC_COMPAT_0_13 \
- PC_CPU_MODEL_IDS("0.13") \
- {\
- .driver = TYPE_PCI_DEVICE,\
- .property = "command_serr_enable",\
- .value = "off",\
- },{\
- .driver = "AC97",\
- .property = "use_broken_id",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-9p-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "VGA",\
- .property = "rombar",\
- .value = stringify(0),\
- },{\
- .driver = "vmware-svga",\
- .property = "rombar",\
- .value = stringify(0),\
- },
-
static void pc_i440fx_0_13_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("0.13")
+ { TYPE_PCI_DEVICE, "command_serr_enable", "off" },
+ { "AC97", "use_broken_id", "1" },
+ { "virtio-9p-pci", "vectors", "0" },
+ { "VGA", "rombar", "0" },
+ { "vmware-svga", "rombar", "0" },
+ };
+
pc_i440fx_0_14_machine_options(m);
m->hw_version = "0.13";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_13);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
pcmc->kvmclock_enabled = false;
}
DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
pc_i440fx_0_13_machine_options);
-
-#define PC_COMPAT_0_12 \
- PC_CPU_MODEL_IDS("0.12") \
- {\
- .driver = "virtio-serial-pci",\
- .property = "max_ports",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "usb-mouse",\
- .property = "serial",\
- .value = "1",\
- },{\
- .driver = "usb-tablet",\
- .property = "serial",\
- .value = "1",\
- },{\
- .driver = "usb-kbd",\
- .property = "serial",\
- .value = "1",\
- },
-
static void pc_i440fx_0_12_machine_options(MachineClass *m)
{
+ static GlobalProperty compat[] = {
+ PC_CPU_MODEL_IDS("0.12")
+ { "virtio-serial-pci", "max_ports", "1" },
+ { "virtio-serial-pci", "vectors", "0" },
+ { "usb-mouse", "serial", "1" },
+ { "usb-tablet", "serial", "1" },
+ { "usb-kbd", "serial", "1" },
+ };
+
pc_i440fx_0_13_machine_options(m);
m->hw_version = "0.12";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_12);
+ compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
pc_i440fx_0_12_machine_options);
-
-#define PC_COMPAT_0_11 \
- PC_CPU_MODEL_IDS("0.11") \
- {\
- .driver = "virtio-blk-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = TYPE_PCI_DEVICE,\
- .property = "rombar",\
- .value = stringify(0),\
- },{\
- .driver = "ide-drive",\
- .property = "ver",\
- .value = "0.11",\
- },{\
- .driver = "scsi-disk",\
- .property = "ver",\
- .value = "0.11",\
- },
-
-static void pc_i440fx_0_11_machine_options(MachineClass *m)
-{
- pc_i440fx_0_12_machine_options(m);
- m->hw_version = "0.11";
- m->deprecation_reason = "use a newer machine type instead";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_11);
-}
-
-DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
- pc_i440fx_0_11_machine_options);
-
-
-#define PC_COMPAT_0_10 \
- PC_CPU_MODEL_IDS("0.10") \
- {\
- .driver = "virtio-blk-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_STORAGE_OTHER),\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "class",\
- .value = stringify(PCI_CLASS_DISPLAY_OTHER),\
- },{\
- .driver = "virtio-net-pci",\
- .property = "vectors",\
- .value = stringify(0),\
- },{\
- .driver = "ide-drive",\
- .property = "ver",\
- .value = "0.10",\
- },{\
- .driver = "scsi-disk",\
- .property = "ver",\
- .value = "0.10",\
- },
-
-static void pc_i440fx_0_10_machine_options(MachineClass *m)
-{
- pc_i440fx_0_11_machine_options(m);
- m->hw_version = "0.10";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_10);
-}
-
-DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13,
- pc_i440fx_0_10_machine_options);
-
typedef struct {
uint16_t gpu_device_id;
uint16_t pch_device_id;
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 4702bb13c4..b7b7959934 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -47,7 +47,7 @@
#include "hw/i386/amd_iommu.h"
#include "hw/i386/intel_iommu.h"
#include "hw/display/ramfb.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci.h"
#include "hw/usb.h"
@@ -58,6 +58,59 @@
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
+struct ehci_companions {
+ const char *name;
+ int func;
+ int port;
+};
+
+static const struct ehci_companions ich9_1d[] = {
+ { .name = "ich9-usb-uhci1", .func = 0, .port = 0 },
+ { .name = "ich9-usb-uhci2", .func = 1, .port = 2 },
+ { .name = "ich9-usb-uhci3", .func = 2, .port = 4 },
+};
+
+static const struct ehci_companions ich9_1a[] = {
+ { .name = "ich9-usb-uhci4", .func = 0, .port = 0 },
+ { .name = "ich9-usb-uhci5", .func = 1, .port = 2 },
+ { .name = "ich9-usb-uhci6", .func = 2, .port = 4 },
+};
+
+static int ehci_create_ich9_with_companions(PCIBus *bus, int slot)
+{
+ const struct ehci_companions *comp;
+ PCIDevice *ehci, *uhci;
+ BusState *usbbus;
+ const char *name;
+ int i;
+
+ switch (slot) {
+ case 0x1d:
+ name = "ich9-usb-ehci1";
+ comp = ich9_1d;
+ break;
+ case 0x1a:
+ name = "ich9-usb-ehci2";
+ comp = ich9_1a;
+ break;
+ default:
+ return -1;
+ }
+
+ ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name);
+ qdev_init_nofail(&ehci->qdev);
+ usbbus = QLIST_FIRST(&ehci->qdev.child_bus);
+
+ for (i = 0; i < 3; i++) {
+ uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func),
+ true, comp[i].name);
+ qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
+ qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
+ qdev_init_nofail(&uhci->qdev);
+ }
+ return 0;
+}
+
/* PC hardware initialisation */
static void pc_q35_init(MachineState *machine)
{
@@ -236,13 +289,13 @@ static void pc_q35_init(MachineState *machine)
/* init basic PC hardware */
pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy,
- (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit,
+ (pcms->vmport != ON_OFF_AUTO_ON), pcms->pit_enabled,
0xff0104);
/* connect pm stuff to lpc */
ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
- if (pcms->sata) {
+ if (pcms->sata_enabled) {
/* ahci and SATA device, for q35 1 ahci controller is built-in */
ahci = pci_create_simple_multifunction(host_bus,
PCI_DEVFN(ICH9_SATA1_DEV,
@@ -262,7 +315,7 @@ static void pc_q35_init(MachineState *machine)
ehci_create_ich9_with_companions(host_bus, 0x1d);
}
- if (pcms->smbus) {
+ if (pcms->smbus_enabled) {
/* TODO: Populate SPD eeprom data. */
smbus_eeprom_init(ich9_smb_init(host_bus,
PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
@@ -304,6 +357,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->units_per_default_bus = 1;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
+ m->default_kernel_irqchip_split = true;
m->no_floppy = 1;
machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE);
machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
@@ -311,20 +365,32 @@ static void pc_q35_machine_options(MachineClass *m)
m->max_cpus = 288;
}
-static void pc_q35_3_1_machine_options(MachineClass *m)
+static void pc_q35_4_0_machine_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
}
+DEFINE_Q35_MACHINE(v4_0, "pc-q35-4.0", NULL,
+ pc_q35_4_0_machine_options);
+
+static void pc_q35_3_1_machine_options(MachineClass *m)
+{
+ pc_q35_4_0_machine_options(m);
+ m->default_kernel_irqchip_split = false;
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_3_1, hw_compat_3_1_len);
+ compat_props_add(m->compat_props, pc_compat_3_1, pc_compat_3_1_len);
+}
+
DEFINE_Q35_MACHINE(v3_1, "pc-q35-3.1", NULL,
pc_q35_3_1_machine_options);
static void pc_q35_3_0_machine_options(MachineClass *m)
{
pc_q35_3_1_machine_options(m);
- m->alias = NULL;
- SET_MACHINE_COMPAT(m, PC_COMPAT_3_0);
+ compat_props_add(m->compat_props, hw_compat_3_0, hw_compat_3_0_len);
+ compat_props_add(m->compat_props, pc_compat_3_0, pc_compat_3_0_len);
}
DEFINE_Q35_MACHINE(v3_0, "pc-q35-3.0", NULL,
@@ -333,7 +399,8 @@ DEFINE_Q35_MACHINE(v3_0, "pc-q35-3.0", NULL,
static void pc_q35_2_12_machine_options(MachineClass *m)
{
pc_q35_3_0_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_12);
+ compat_props_add(m->compat_props, hw_compat_2_12, hw_compat_2_12_len);
+ compat_props_add(m->compat_props, pc_compat_2_12, pc_compat_2_12_len);
}
DEFINE_Q35_MACHINE(v2_12, "pc-q35-2.12", NULL,
@@ -345,7 +412,8 @@ static void pc_q35_2_11_machine_options(MachineClass *m)
pc_q35_2_12_machine_options(m);
pcmc->default_nic_model = "e1000";
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_11);
+ compat_props_add(m->compat_props, hw_compat_2_11, hw_compat_2_11_len);
+ compat_props_add(m->compat_props, pc_compat_2_11, pc_compat_2_11_len);
}
DEFINE_Q35_MACHINE(v2_11, "pc-q35-2.11", NULL,
@@ -354,7 +422,8 @@ DEFINE_Q35_MACHINE(v2_11, "pc-q35-2.11", NULL,
static void pc_q35_2_10_machine_options(MachineClass *m)
{
pc_q35_2_11_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_10);
+ compat_props_add(m->compat_props, hw_compat_2_10, hw_compat_2_10_len);
+ compat_props_add(m->compat_props, pc_compat_2_10, pc_compat_2_10_len);
m->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
m->auto_enable_numa_with_memhp = false;
}
@@ -365,7 +434,8 @@ DEFINE_Q35_MACHINE(v2_10, "pc-q35-2.10", NULL,
static void pc_q35_2_9_machine_options(MachineClass *m)
{
pc_q35_2_10_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_9);
+ compat_props_add(m->compat_props, hw_compat_2_9, hw_compat_2_9_len);
+ compat_props_add(m->compat_props, pc_compat_2_9, pc_compat_2_9_len);
}
DEFINE_Q35_MACHINE(v2_9, "pc-q35-2.9", NULL,
@@ -374,7 +444,8 @@ DEFINE_Q35_MACHINE(v2_9, "pc-q35-2.9", NULL,
static void pc_q35_2_8_machine_options(MachineClass *m)
{
pc_q35_2_9_machine_options(m);
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_8);
+ compat_props_add(m->compat_props, hw_compat_2_8, hw_compat_2_8_len);
+ compat_props_add(m->compat_props, pc_compat_2_8, pc_compat_2_8_len);
}
DEFINE_Q35_MACHINE(v2_8, "pc-q35-2.8", NULL,
@@ -384,7 +455,8 @@ static void pc_q35_2_7_machine_options(MachineClass *m)
{
pc_q35_2_8_machine_options(m);
m->max_cpus = 255;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_7);
+ compat_props_add(m->compat_props, hw_compat_2_7, hw_compat_2_7_len);
+ compat_props_add(m->compat_props, pc_compat_2_7, pc_compat_2_7_len);
}
DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
@@ -393,10 +465,12 @@ DEFINE_Q35_MACHINE(v2_7, "pc-q35-2.7", NULL,
static void pc_q35_2_6_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_q35_2_7_machine_options(m);
pcmc->legacy_cpu_hotplug = true;
pcmc->linuxboot_dma_enabled = false;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_6);
+ compat_props_add(m->compat_props, hw_compat_2_6, hw_compat_2_6_len);
+ compat_props_add(m->compat_props, pc_compat_2_6, pc_compat_2_6_len);
}
DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL,
@@ -405,10 +479,12 @@ DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL,
static void pc_q35_2_5_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_q35_2_6_machine_options(m);
pcmc->save_tsc_khz = false;
m->legacy_fw_cfg_order = 1;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
+ compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len);
+ compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len);
}
DEFINE_Q35_MACHINE(v2_5, "pc-q35-2.5", NULL,
@@ -417,10 +493,12 @@ DEFINE_Q35_MACHINE(v2_5, "pc-q35-2.5", NULL,
static void pc_q35_2_4_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
+
pc_q35_2_5_machine_options(m);
m->hw_version = "2.4.0";
pcmc->broken_reserved_end = true;
- SET_MACHINE_COMPAT(m, PC_COMPAT_2_4);
+ compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len);
+ compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len);
}
DEFINE_Q35_MACHINE(v2_4, "pc-q35-2.4", NULL,
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index 6ac347d18c..77244fc384 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -5,19 +5,15 @@ x86_iommu_iec_notify(bool global, uint32_t index, uint32_t mask) "Notify IEC inv
# hw/i386/intel_iommu.c
vtd_inv_desc(const char *type, uint64_t hi, uint64_t lo) "invalidate desc type %s high 0x%"PRIx64" low 0x%"PRIx64
-vtd_inv_desc_invalid(uint64_t hi, uint64_t lo) "invalid inv desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_cc_domain(uint16_t domain) "context invalidate domain 0x%"PRIx16
vtd_inv_desc_cc_global(void) "context invalidate globally"
vtd_inv_desc_cc_device(uint8_t bus, uint8_t dev, uint8_t fn) "context invalidate device %02"PRIx8":%02"PRIx8".%02"PRIx8
vtd_inv_desc_cc_devices(uint16_t sid, uint16_t fmask) "context invalidate devices sid 0x%"PRIx16" fmask 0x%"PRIx16
-vtd_inv_desc_cc_invalid(uint64_t hi, uint64_t lo) "invalid context-cache desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_iotlb_global(void) "iotlb invalidate global"
vtd_inv_desc_iotlb_domain(uint16_t domain) "iotlb invalidate whole domain 0x%"PRIx16
vtd_inv_desc_iotlb_pages(uint16_t domain, uint64_t addr, uint8_t mask) "iotlb invalidate domain 0x%"PRIx16" addr 0x%"PRIx64" mask 0x%"PRIx8
-vtd_inv_desc_iotlb_invalid(uint64_t hi, uint64_t lo) "invalid iotlb desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_wait_sw(uint64_t addr, uint32_t data) "wait invalidate status write addr 0x%"PRIx64" data 0x%"PRIx32
vtd_inv_desc_wait_irq(const char *msg) "%s"
-vtd_inv_desc_wait_invalid(uint64_t hi, uint64_t lo) "invalid wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_wait_write_fail(uint64_t hi, uint64_t lo) "write fail for wait desc hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_inv_desc_iec(uint32_t granularity, uint32_t index, uint32_t mask) "granularity 0x%"PRIx32" index 0x%"PRIx32" mask 0x%"PRIx32
vtd_inv_qi_enable(bool enable) "enabled %d"
@@ -27,9 +23,7 @@ vtd_inv_qi_tail(uint16_t head) "write tail %d"
vtd_inv_qi_fetch(void) ""
vtd_context_cache_reset(void) ""
vtd_re_not_present(uint8_t bus) "Root entry bus %"PRIu8" not present"
-vtd_re_invalid(uint64_t hi, uint64_t lo) "invalid root entry hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_ce_not_present(uint8_t bus, uint8_t devfn) "Context entry bus %"PRIu8" devfn %"PRIu8" not present"
-vtd_ce_invalid(uint64_t hi, uint64_t lo) "invalid context entry hi 0x%"PRIx64" lo 0x%"PRIx64
vtd_iotlb_page_hit(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page hit sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16
vtd_iotlb_page_update(uint16_t sid, uint64_t addr, uint64_t slpte, uint16_t domain) "IOTLB page update sid 0x%"PRIx16" iova 0x%"PRIx64" slpte 0x%"PRIx64" domain 0x%"PRIx16
vtd_iotlb_cc_hit(uint8_t bus, uint8_t devfn, uint64_t high, uint64_t low, uint32_t gen) "IOTLB context hit bus 0x%"PRIx8" devfn 0x%"PRIx8" high 0x%"PRIx64" low 0x%"PRIx64" gen %"PRIu32
diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c
index abc3c03158..d1534c1ae0 100644
--- a/hw/i386/x86-iommu.c
+++ b/hw/i386/x86-iommu.c
@@ -112,6 +112,7 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
PCMachineState *pcms =
PC_MACHINE(object_dynamic_cast(OBJECT(ms), TYPE_PC_MACHINE));
QLIST_INIT(&x86_iommu->iec_notifiers);
+ bool irq_all_kernel = kvm_irqchip_in_kernel() && !kvm_irqchip_is_split();
if (!pcms || !pcms->bus) {
error_setg(errp, "Machine-type '%s' not supported by IOMMU",
@@ -119,9 +120,14 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
return;
}
+ /* If the user didn't specify IR, choose a default value for it */
+ if (x86_iommu->intr_supported == ON_OFF_AUTO_AUTO) {
+ x86_iommu->intr_supported = irq_all_kernel ?
+ ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
+ }
+
/* Both Intel and AMD IOMMU IR only support "kernel-irqchip={off|split}" */
- if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
- !kvm_irqchip_is_split()) {
+ if (x86_iommu_ir_supported(x86_iommu) && irq_all_kernel) {
error_setg(errp, "Interrupt Remapping cannot work with "
"kernel-irqchip=on, please use 'split|off'.");
return;
@@ -135,7 +141,8 @@ static void x86_iommu_realize(DeviceState *dev, Error **errp)
}
static Property x86_iommu_properties[] = {
- DEFINE_PROP_BOOL("intremap", X86IOMMUState, intr_supported, false),
+ DEFINE_PROP_ON_OFF_AUTO("intremap", X86IOMMUState,
+ intr_supported, ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("device-iotlb", X86IOMMUState, dt_supported, false),
DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true),
DEFINE_PROP_END_OF_LIST(),
@@ -148,6 +155,11 @@ static void x86_iommu_class_init(ObjectClass *klass, void *data)
dc->props = x86_iommu_properties;
}
+bool x86_iommu_ir_supported(X86IOMMUState *s)
+{
+ return s->intr_supported == ON_OFF_AUTO_ON;
+}
+
static const TypeInfo x86_iommu_info = {
.name = TYPE_X86_IOMMU_DEVICE,
.parent = TYPE_SYS_BUS_DEVICE,
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 935a3676c8..2939122e7c 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -16,7 +16,8 @@
#include "hw/i386/pc.h"
#include "hw/i386/apic-msidef.h"
#include "hw/xen/xen_common.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
+#include "hw/xen/xen-bus.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-misc.h"
#include "qemu/error-report.h"
@@ -570,7 +571,7 @@ static void xen_io_del(MemoryListener *listener,
}
static void xen_device_realize(DeviceListener *listener,
- DeviceState *dev)
+ DeviceState *dev)
{
XenIOState *state = container_of(listener, XenIOState, device_listener);
@@ -588,7 +589,7 @@ static void xen_device_realize(DeviceListener *listener,
}
static void xen_device_unrealize(DeviceListener *listener,
- DeviceState *dev)
+ DeviceState *dev)
{
XenIOState *state = container_of(listener, XenIOState, device_listener);
@@ -1405,6 +1406,11 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
state->wakeup.notify = xen_wakeup_notifier;
qemu_register_wakeup_notifier(&state->wakeup);
+ /*
+ * Register wake-up support in QMP query-current-machine API
+ */
+ qemu_register_wakeup_support();
+
rc = xen_map_ioreq_server(state);
if (rc < 0) {
goto err;
@@ -1479,6 +1485,8 @@ void xen_hvm_init(PCMachineState *pcms, MemoryRegion **ram_memory)
QLIST_INIT(&state->dev_list);
device_listener_register(&state->device_listener);
+ xen_bus_init();
+
/* Initialize backend core & drivers */
if (xen_be_init() != 0) {
error_report("xen backend core setup failed");
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index 4e4f069a24..349f72d00c 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -14,7 +14,7 @@
#include <sys/resource.h>
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "qemu/bitmap.h"
#include <xen/hvm/params.h>
@@ -71,7 +71,7 @@ typedef struct MapCacheRev {
typedef struct MapCache {
MapCacheEntry *entry;
unsigned long nr_buckets;
- QTAILQ_HEAD(map_cache_head, MapCacheRev) locked_entries;
+ QTAILQ_HEAD(, MapCacheRev) locked_entries;
/* For most cases (>99.9%), the page address is the same. */
MapCacheEntry *last_entry;
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index deb7a0c374..16afb54fee 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -30,7 +30,7 @@
#include "hw/pci/pci.h"
#include "hw/irq.h"
#include "hw/xen/xen_common.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "trace.h"
#include "exec/address-spaces.h"
#include "sysemu/block-backend.h"
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 04e22e751d..c3d779db6e 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -575,16 +575,16 @@ int64_t ide_get_sector(IDEState *s)
int64_t sector_num;
if (s->select & 0x40) {
/* lba */
- if (!s->lba48) {
- sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
- (s->lcyl << 8) | s->sector;
- } else {
- sector_num = ((int64_t)s->hob_hcyl << 40) |
- ((int64_t) s->hob_lcyl << 32) |
- ((int64_t) s->hob_sector << 24) |
- ((int64_t) s->hcyl << 16) |
- ((int64_t) s->lcyl << 8) | s->sector;
- }
+ if (!s->lba48) {
+ sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
+ (s->lcyl << 8) | s->sector;
+ } else {
+ sector_num = ((int64_t)s->hob_hcyl << 40) |
+ ((int64_t) s->hob_lcyl << 32) |
+ ((int64_t) s->hob_sector << 24) |
+ ((int64_t) s->hcyl << 16) |
+ ((int64_t) s->lcyl << 8) | s->sector;
+ }
} else {
sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
(s->select & 0x0f) * s->sectors + (s->sector - 1);
@@ -596,19 +596,19 @@ void ide_set_sector(IDEState *s, int64_t sector_num)
{
unsigned int cyl, r;
if (s->select & 0x40) {
- if (!s->lba48) {
+ if (!s->lba48) {
s->select = (s->select & 0xf0) | (sector_num >> 24);
s->hcyl = (sector_num >> 16);
s->lcyl = (sector_num >> 8);
s->sector = (sector_num);
- } else {
- s->sector = sector_num;
- s->lcyl = sector_num >> 8;
- s->hcyl = sector_num >> 16;
- s->hob_sector = sector_num >> 24;
- s->hob_lcyl = sector_num >> 32;
- s->hob_hcyl = sector_num >> 40;
- }
+ } else {
+ s->sector = sector_num;
+ s->lcyl = sector_num >> 8;
+ s->hcyl = sector_num >> 16;
+ s->hob_sector = sector_num >> 24;
+ s->hob_lcyl = sector_num >> 32;
+ s->hob_hcyl = sector_num >> 40;
+ }
} else {
cyl = sector_num / (s->heads * s->sectors);
r = sector_num % (s->heads * s->sectors);
@@ -1188,17 +1188,17 @@ static void ide_cmd_lba48_transform(IDEState *s, int lba48)
* full sector count in ->nsector and ignore ->hob_nsector from now
*/
if (!s->lba48) {
- if (!s->nsector)
- s->nsector = 256;
+ if (!s->nsector)
+ s->nsector = 256;
} else {
- if (!s->nsector && !s->hob_nsector)
- s->nsector = 65536;
- else {
- int lo = s->nsector;
- int hi = s->hob_nsector;
+ if (!s->nsector && !s->hob_nsector)
+ s->nsector = 65536;
+ else {
+ int lo = s->nsector;
+ int hi = s->hob_nsector;
- s->nsector = (hi << 8) | lo;
- }
+ s->nsector = (hi << 8) | lo;
+ }
}
}
@@ -1258,35 +1258,35 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
bus->ifs[1].feature = val;
break;
case ATA_IOPORT_WR_SECTOR_COUNT:
- ide_clear_hob(bus);
- bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
- bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
+ ide_clear_hob(bus);
+ bus->ifs[0].hob_nsector = bus->ifs[0].nsector;
+ bus->ifs[1].hob_nsector = bus->ifs[1].nsector;
bus->ifs[0].nsector = val;
bus->ifs[1].nsector = val;
break;
case ATA_IOPORT_WR_SECTOR_NUMBER:
- ide_clear_hob(bus);
- bus->ifs[0].hob_sector = bus->ifs[0].sector;
- bus->ifs[1].hob_sector = bus->ifs[1].sector;
+ ide_clear_hob(bus);
+ bus->ifs[0].hob_sector = bus->ifs[0].sector;
+ bus->ifs[1].hob_sector = bus->ifs[1].sector;
bus->ifs[0].sector = val;
bus->ifs[1].sector = val;
break;
case ATA_IOPORT_WR_CYLINDER_LOW:
- ide_clear_hob(bus);
- bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
- bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
+ ide_clear_hob(bus);
+ bus->ifs[0].hob_lcyl = bus->ifs[0].lcyl;
+ bus->ifs[1].hob_lcyl = bus->ifs[1].lcyl;
bus->ifs[0].lcyl = val;
bus->ifs[1].lcyl = val;
break;
case ATA_IOPORT_WR_CYLINDER_HIGH:
- ide_clear_hob(bus);
- bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
- bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
+ ide_clear_hob(bus);
+ bus->ifs[0].hob_hcyl = bus->ifs[0].hcyl;
+ bus->ifs[1].hob_hcyl = bus->ifs[1].hcyl;
bus->ifs[0].hcyl = val;
bus->ifs[1].hcyl = val;
break;
case ATA_IOPORT_WR_DEVICE_HEAD:
- /* FIXME: HOB readback uses bit 7 */
+ /* FIXME: HOB readback uses bit 7 */
bus->ifs[0].select = (val & ~0x10) | 0xa0;
bus->ifs[1].select = (val | 0x10) | 0xa0;
/* select drive */
@@ -2146,7 +2146,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
} else if (!hob) {
ret = s->error;
} else {
- ret = s->hob_feature;
+ ret = s->hob_feature;
}
break;
case ATA_IOPORT_RR_SECTOR_COUNT:
@@ -2155,7 +2155,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
} else if (!hob) {
ret = s->nsector & 0xff;
} else {
- ret = s->hob_nsector;
+ ret = s->hob_nsector;
}
break;
case ATA_IOPORT_RR_SECTOR_NUMBER:
@@ -2164,7 +2164,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
} else if (!hob) {
ret = s->sector;
} else {
- ret = s->hob_sector;
+ ret = s->hob_sector;
}
break;
case ATA_IOPORT_RR_CYLINDER_LOW:
@@ -2173,7 +2173,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
} else if (!hob) {
ret = s->lcyl;
} else {
- ret = s->hob_lcyl;
+ ret = s->hob_lcyl;
}
break;
case ATA_IOPORT_RR_CYLINDER_HIGH:
@@ -2182,7 +2182,7 @@ uint32_t ide_ioport_read(void *opaque, uint32_t addr)
} else if (!hob) {
ret = s->hcyl;
} else {
- ret = s->hob_hcyl;
+ ret = s->hob_hcyl;
}
break;
case ATA_IOPORT_RR_DEVICE_HEAD:
@@ -2847,7 +2847,7 @@ static const VMStateDescription vmstate_ide_drive_pio_state = {
.fields = (VMStateField[]) {
VMSTATE_INT32(req_nb_sectors, IDEState),
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
- vmstate_info_uint8, uint8_t),
+ vmstate_info_uint8, uint8_t),
VMSTATE_INT32(cur_io_buffer_offset, IDEState),
VMSTATE_INT32(cur_io_buffer_len, IDEState),
VMSTATE_UINT8(end_transfer_fn_idx, IDEState),
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index fe1ceeb0cd..b75154f99f 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "hw/isa/isa.h"
#include "sysemu/dma.h"
#include "qemu/error-report.h"
#include "hw/ide/pci.h"
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index a3afe1fd29..885c16e938 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -26,7 +26,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "hw/isa/isa.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "sysemu/blockdev.h"
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 238f038d72..987d99c5ec 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -26,7 +26,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "hw/isa/isa.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
index 74da30d9ca..cffbf586d4 100644
--- a/hw/input/lm832x.c
+++ b/hw/input/lm832x.c
@@ -66,7 +66,7 @@ typedef struct {
struct {
uint16_t file[256];
- uint8_t faddr;
+ uint8_t faddr;
uint8_t addr[3];
QEMUTimer *tm[3];
} pwm;
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
index ef8f47cd83..8766a17d9e 100644
--- a/hw/input/milkymist-softusb.c
+++ b/hw/input/milkymist-softusb.c
@@ -245,32 +245,31 @@ static void milkymist_softusb_reset(DeviceState *d)
s->regs[R_CTRL] = CTRL_RESET;
}
-static int milkymist_softusb_init(SysBusDevice *dev)
+static void milkymist_softusb_realize(DeviceState *dev, Error **errp)
{
MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s,
"milkymist-softusb", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
+ sysbus_init_mmio(sbd, &s->regs_region);
/* register pmem and dmem */
memory_region_init_ram_nomigrate(&s->pmem, OBJECT(s), "milkymist-softusb.pmem",
s->pmem_size, &error_fatal);
vmstate_register_ram_global(&s->pmem);
s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
- sysbus_init_mmio(dev, &s->pmem);
+ sysbus_init_mmio(sbd, &s->pmem);
memory_region_init_ram_nomigrate(&s->dmem, OBJECT(s), "milkymist-softusb.dmem",
s->dmem_size, &error_fatal);
vmstate_register_ram_global(&s->dmem);
s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
- sysbus_init_mmio(dev, &s->dmem);
+ sysbus_init_mmio(sbd, &s->dmem);
hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
-
- return 0;
}
static const VMStateDescription vmstate_milkymist_softusb = {
@@ -296,9 +295,8 @@ static Property milkymist_softusb_properties[] = {
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->realize = milkymist_softusb_realize;
dc->reset = milkymist_softusb_reset;
dc->vmsd = &vmstate_milkymist_softusb;
dc->props = milkymist_softusb_properties;
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 07c8801387..3e66713b47 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -55,7 +55,7 @@
#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
#define KBD_CCMD_WRITE_OBUF 0xD2
#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
- initiated by the auxiliary device */
+ initiated by the auxiliary device */
#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
diff --git a/hw/input/pl050.c b/hw/input/pl050.c
index be9cd57b17..15bffbfcad 100644
--- a/hw/input/pl050.c
+++ b/hw/input/pl050.c
@@ -139,19 +139,19 @@ static const MemoryRegionOps pl050_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int pl050_initfn(SysBusDevice *dev)
+static void pl050_realize(DeviceState *dev, Error **errp)
{
PL050State *s = PL050(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &pl050_ops, s, "pl050", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
if (s->is_mouse) {
s->dev = ps2_mouse_init(pl050_update, s);
} else {
s->dev = ps2_kbd_init(pl050_update, s);
}
- return 0;
}
static void pl050_keyboard_init(Object *obj)
@@ -183,9 +183,8 @@ static const TypeInfo pl050_mouse_info = {
static void pl050_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc);
- sdc->init = pl050_initfn;
+ dc->realize = pl050_realize;
dc->vmsd = &vmstate_pl050;
}
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
index eb33ee9b6f..d3161f1e7c 100644
--- a/hw/input/ps2.c
+++ b/hw/input/ps2.c
@@ -255,7 +255,7 @@ static void ps2_put_keycode(void *opaque, int keycode)
PS2KbdState *s = opaque;
trace_ps2_put_keycode(opaque, keycode);
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
if (s->translate) {
if (keycode == 0xf0) {
@@ -285,7 +285,7 @@ static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
return;
}
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
assert(evt->type == INPUT_EVENT_KIND_KEY);
qcode = qemu_input_key_value_to_qcode(key->key);
@@ -748,7 +748,7 @@ static void ps2_mouse_sync(DeviceState *dev)
}
if (s->mouse_buttons) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
}
if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
/* if not remote, send event. Multiple events are sent if
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
index 1cad57f644..ded0db9351 100644
--- a/hw/input/tsc210x.c
+++ b/hw/input/tsc210x.c
@@ -577,7 +577,7 @@ static void tsc2102_control_register_write(
case 0x01: /* Status / Keypad Control */
if ((s->model & 0xff00) == 0x2100)
s->pin_func = value >> 14;
- else {
+ else {
s->kb.scan = (value >> 14) & 1;
s->kb.debounce = (value >> 11) & 7;
if (s->kb.intr && s->kb.scan) {
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 0e9963f5ee..301a8e972d 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -37,6 +37,8 @@ obj-$(CONFIG_SH4) += sh_intc.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
+obj-$(CONFIG_XIVE) += xive.o
+obj-$(CONFIG_XIVE_SPAPR) += spapr_xive.o
obj-$(CONFIG_POWERNV) += xics_pnv.o
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
obj-$(CONFIG_S390_FLIC) += s390_flic.o
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 97ffdd820f..6ea619c360 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -122,9 +122,10 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type)
}
vapic_state.irr = vector & 0xff;
- cpu_physical_memory_write_rom(&address_space_memory,
- s->vapic_paddr + start,
- ((void *)&vapic_state) + start, length);
+ address_space_write_rom(&address_space_memory,
+ s->vapic_paddr + start,
+ MEMTXATTRS_UNSPECIFIED,
+ ((void *)&vapic_state) + start, length);
}
}
@@ -441,7 +442,7 @@ static int apic_find_dest(uint8_t dest)
for (i = 0; i < MAX_APICS; i++) {
apic = local_apics[i];
- if (apic && apic->id == dest)
+ if (apic && apic->id == dest)
return i;
if (!apic)
break;
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index 068a8e8e9b..cbad6037f1 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -85,8 +85,8 @@ static bool icv_access(CPUARMState *env, int hcr_flags)
* * access if NS EL1 and either IMO or FMO == 1:
* CTLR, DIR, PMR, RPR
*/
- bool flagmatch = ((hcr_flags & HCR_IMO) && arm_hcr_el2_imo(env)) ||
- ((hcr_flags & HCR_FMO) && arm_hcr_el2_fmo(env));
+ uint64_t hcr_el2 = arm_hcr_el2_eff(env);
+ bool flagmatch = hcr_el2 & hcr_flags & (HCR_IMO | HCR_FMO);
return flagmatch && arm_current_el(env) == 1
&& !arm_is_secure_below_el3(env);
@@ -1552,8 +1552,9 @@ static void icc_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
/* No need to include !IsSecure in route_*_to_el2 as it's only
* tested in cases where we know !IsSecure is true.
*/
- route_fiq_to_el2 = arm_hcr_el2_fmo(env);
- route_irq_to_el2 = arm_hcr_el2_imo(env);
+ uint64_t hcr_el2 = arm_hcr_el2_eff(env);
+ route_fiq_to_el2 = hcr_el2 & HCR_FMO;
+ route_irq_to_el2 = hcr_el2 & HCR_IMO;
switch (arm_current_el(env)) {
case 3:
@@ -1895,8 +1896,8 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
if ((env->cp15.scr_el3 & (SCR_FIQ | SCR_IRQ)) == (SCR_FIQ | SCR_IRQ)) {
switch (el) {
case 1:
- if (arm_is_secure_below_el3(env) ||
- (arm_hcr_el2_imo(env) == 0 && arm_hcr_el2_fmo(env) == 0)) {
+ /* Note that arm_hcr_el2_eff takes secure state into account. */
+ if ((arm_hcr_el2_eff(env) & (HCR_IMO | HCR_FMO)) == 0) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -1936,8 +1937,8 @@ static CPAccessResult gicv3_dir_access(CPUARMState *env,
static CPAccessResult gicv3_sgi_access(CPUARMState *env,
const ARMCPRegInfo *ri, bool isread)
{
- if ((arm_hcr_el2_imo(env) || arm_hcr_el2_fmo(env)) &&
- arm_current_el(env) == 1 && !arm_is_secure_below_el3(env)) {
+ if (arm_current_el(env) == 1 &&
+ (arm_hcr_el2_eff(env) & (HCR_IMO | HCR_FMO)) != 0) {
/* Takes priority over a possible EL3 trap */
return CP_ACCESS_TRAP_EL2;
}
@@ -1961,7 +1962,7 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
if (env->cp15.scr_el3 & SCR_FIQ) {
switch (el) {
case 1:
- if (arm_is_secure_below_el3(env) || !arm_hcr_el2_fmo(env)) {
+ if ((arm_hcr_el2_eff(env) & HCR_FMO) == 0) {
r = CP_ACCESS_TRAP_EL3;
}
break;
@@ -2000,7 +2001,7 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
if (env->cp15.scr_el3 & SCR_IRQ) {
switch (el) {
case 1:
- if (arm_is_secure_below_el3(env) || !arm_hcr_el2_imo(env)) {
+ if ((arm_hcr_el2_eff(env) & HCR_IMO) == 0) {
r = CP_ACCESS_TRAP_EL3;
}
break;
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 4e529729b4..9d75f84d3b 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -429,7 +429,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo ioapic_info = {
- .name = "ioapic",
+ .name = TYPE_IOAPIC,
.parent = TYPE_IOAPIC_COMMON,
.instance_size = sizeof(IOAPICCommonState),
.class_init = ioapic_class_init,
diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c
index ef8488aacc..69ddc8c19a 100644
--- a/hw/intc/puv3_intc.c
+++ b/hw/intc/puv3_intc.c
@@ -101,10 +101,10 @@ static const MemoryRegionOps puv3_intc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int puv3_intc_init(SysBusDevice *sbd)
+static void puv3_intc_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
PUV3INTCState *s = PUV3_INTC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR);
sysbus_init_irq(sbd, &s->parent_irq);
@@ -115,15 +115,12 @@ static int puv3_intc_init(SysBusDevice *sbd)
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
PUV3_REGS_OFFSET);
sysbus_init_mmio(sbd, &s->iomem);
-
- return 0;
}
static void puv3_intc_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
- sdc->init = puv3_intc_init;
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = puv3_intc_realize;
}
static const TypeInfo puv3_intc_info = {
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
new file mode 100644
index 0000000000..d391177ab8
--- /dev/null
+++ b/hw/intc/spapr_xive.c
@@ -0,0 +1,1481 @@
+/*
+ * QEMU PowerPC sPAPR XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "target/ppc/cpu.h"
+#include "sysemu/cpus.h"
+#include "monitor/monitor.h"
+#include "hw/ppc/fdt.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_xive.h"
+#include "hw/ppc/xive.h"
+#include "hw/ppc/xive_regs.h"
+
+/*
+ * XIVE Virtualization Controller BAR and Thread Managment BAR that we
+ * use for the ESB pages and the TIMA pages
+ */
+#define SPAPR_XIVE_VC_BASE 0x0006010000000000ull
+#define SPAPR_XIVE_TM_BASE 0x0006030203180000ull
+
+/*
+ * The allocation of VP blocks is a complex operation in OPAL and the
+ * VP identifiers have a relation with the number of HW chips, the
+ * size of the VP blocks, VP grouping, etc. The QEMU sPAPR XIVE
+ * controller model does not have the same constraints and can use a
+ * simple mapping scheme of the CPU vcpu_id
+ *
+ * These identifiers are never returned to the OS.
+ */
+
+#define SPAPR_XIVE_NVT_BASE 0x400
+
+/*
+ * The sPAPR machine has a unique XIVE IC device. Assign a fixed value
+ * to the controller block id value. It can nevertheless be changed
+ * for testing purpose.
+ */
+#define SPAPR_XIVE_BLOCK_ID 0x0
+
+/*
+ * sPAPR NVT and END indexing helpers
+ */
+static uint32_t spapr_xive_nvt_to_target(uint8_t nvt_blk, uint32_t nvt_idx)
+{
+ return nvt_idx - SPAPR_XIVE_NVT_BASE;
+}
+
+static void spapr_xive_cpu_to_nvt(PowerPCCPU *cpu,
+ uint8_t *out_nvt_blk, uint32_t *out_nvt_idx)
+{
+ assert(cpu);
+
+ if (out_nvt_blk) {
+ *out_nvt_blk = SPAPR_XIVE_BLOCK_ID;
+ }
+
+ if (out_nvt_blk) {
+ *out_nvt_idx = SPAPR_XIVE_NVT_BASE + cpu->vcpu_id;
+ }
+}
+
+static int spapr_xive_target_to_nvt(uint32_t target,
+ uint8_t *out_nvt_blk, uint32_t *out_nvt_idx)
+{
+ PowerPCCPU *cpu = spapr_find_cpu(target);
+
+ if (!cpu) {
+ return -1;
+ }
+
+ spapr_xive_cpu_to_nvt(cpu, out_nvt_blk, out_nvt_idx);
+ return 0;
+}
+
+/*
+ * sPAPR END indexing uses a simple mapping of the CPU vcpu_id, 8
+ * priorities per CPU
+ */
+static void spapr_xive_cpu_to_end(PowerPCCPU *cpu, uint8_t prio,
+ uint8_t *out_end_blk, uint32_t *out_end_idx)
+{
+ assert(cpu);
+
+ if (out_end_blk) {
+ *out_end_blk = SPAPR_XIVE_BLOCK_ID;
+ }
+
+ if (out_end_idx) {
+ *out_end_idx = (cpu->vcpu_id << 3) + prio;
+ }
+}
+
+static int spapr_xive_target_to_end(uint32_t target, uint8_t prio,
+ uint8_t *out_end_blk, uint32_t *out_end_idx)
+{
+ PowerPCCPU *cpu = spapr_find_cpu(target);
+
+ if (!cpu) {
+ return -1;
+ }
+
+ spapr_xive_cpu_to_end(cpu, prio, out_end_blk, out_end_idx);
+ return 0;
+}
+
+/*
+ * On sPAPR machines, use a simplified output for the XIVE END
+ * structure dumping only the information related to the OS EQ.
+ */
+static void spapr_xive_end_pic_print_info(sPAPRXive *xive, XiveEND *end,
+ Monitor *mon)
+{
+ uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
+ uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
+ uint32_t qentries = 1 << (qsize + 10);
+ uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6);
+ uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
+
+ monitor_printf(mon, "%3d/%d % 6d/%5d ^%d",
+ spapr_xive_nvt_to_target(0, nvt),
+ priority, qindex, qentries, qgen);
+
+ xive_end_queue_pic_print_info(end, 6, mon);
+ monitor_printf(mon, "]");
+}
+
+void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon)
+{
+ XiveSource *xsrc = &xive->source;
+ int i;
+
+ monitor_printf(mon, " LSIN PQ EISN CPU/PRIO EQ\n");
+
+ for (i = 0; i < xive->nr_irqs; i++) {
+ uint8_t pq = xive_source_esb_get(xsrc, i);
+ XiveEAS *eas = &xive->eat[i];
+
+ if (!xive_eas_is_valid(eas)) {
+ continue;
+ }
+
+ monitor_printf(mon, " %08x %s %c%c%c %s %08x ", i,
+ xive_source_irq_is_lsi(xsrc, i) ? "LSI" : "MSI",
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
+ xsrc->status[i] & XIVE_STATUS_ASSERTED ? 'A' : ' ',
+ xive_eas_is_masked(eas) ? "M" : " ",
+ (int) xive_get_field64(EAS_END_DATA, eas->w));
+
+ if (!xive_eas_is_masked(eas)) {
+ uint32_t end_idx = xive_get_field64(EAS_END_INDEX, eas->w);
+ XiveEND *end;
+
+ assert(end_idx < xive->nr_ends);
+ end = &xive->endt[end_idx];
+
+ if (xive_end_is_valid(end)) {
+ spapr_xive_end_pic_print_info(xive, end, mon);
+ }
+ }
+ monitor_printf(mon, "\n");
+ }
+}
+
+static void spapr_xive_map_mmio(sPAPRXive *xive)
+{
+ sysbus_mmio_map(SYS_BUS_DEVICE(xive), 0, xive->vc_base);
+ sysbus_mmio_map(SYS_BUS_DEVICE(xive), 1, xive->end_base);
+ sysbus_mmio_map(SYS_BUS_DEVICE(xive), 2, xive->tm_base);
+}
+
+void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable)
+{
+ memory_region_set_enabled(&xive->source.esb_mmio, enable);
+ memory_region_set_enabled(&xive->tm_mmio, enable);
+
+ /* Disable the END ESBs until a guest OS makes use of them */
+ memory_region_set_enabled(&xive->end_source.esb_mmio, false);
+}
+
+/*
+ * When a Virtual Processor is scheduled to run on a HW thread, the
+ * hypervisor pushes its identifier in the OS CAM line. Emulate the
+ * same behavior under QEMU.
+ */
+void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx)
+{
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+ uint32_t nvt_cam;
+
+ spapr_xive_cpu_to_nvt(POWERPC_CPU(tctx->cs), &nvt_blk, &nvt_idx);
+
+ nvt_cam = cpu_to_be32(TM_QW1W2_VO | xive_nvt_cam_line(nvt_blk, nvt_idx));
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &nvt_cam, 4);
+}
+
+static void spapr_xive_end_reset(XiveEND *end)
+{
+ memset(end, 0, sizeof(*end));
+
+ /* switch off the escalation and notification ESBs */
+ end->w1 = cpu_to_be32(END_W1_ESe_Q | END_W1_ESn_Q);
+}
+
+static void spapr_xive_reset(void *dev)
+{
+ sPAPRXive *xive = SPAPR_XIVE(dev);
+ int i;
+
+ /*
+ * The XiveSource has its own reset handler, which mask off all
+ * IRQs (!P|Q)
+ */
+
+ /* Mask all valid EASs in the IRQ number space. */
+ for (i = 0; i < xive->nr_irqs; i++) {
+ XiveEAS *eas = &xive->eat[i];
+ if (xive_eas_is_valid(eas)) {
+ eas->w = cpu_to_be64(EAS_VALID | EAS_MASKED);
+ } else {
+ eas->w = 0;
+ }
+ }
+
+ /* Clear all ENDs */
+ for (i = 0; i < xive->nr_ends; i++) {
+ spapr_xive_end_reset(&xive->endt[i]);
+ }
+}
+
+static void spapr_xive_instance_init(Object *obj)
+{
+ sPAPRXive *xive = SPAPR_XIVE(obj);
+
+ object_initialize(&xive->source, sizeof(xive->source), TYPE_XIVE_SOURCE);
+ object_property_add_child(obj, "source", OBJECT(&xive->source), NULL);
+
+ object_initialize(&xive->end_source, sizeof(xive->end_source),
+ TYPE_XIVE_END_SOURCE);
+ object_property_add_child(obj, "end_source", OBJECT(&xive->end_source),
+ NULL);
+}
+
+static void spapr_xive_realize(DeviceState *dev, Error **errp)
+{
+ sPAPRXive *xive = SPAPR_XIVE(dev);
+ XiveSource *xsrc = &xive->source;
+ XiveENDSource *end_xsrc = &xive->end_source;
+ Error *local_err = NULL;
+
+ if (!xive->nr_irqs) {
+ error_setg(errp, "Number of interrupt needs to be greater 0");
+ return;
+ }
+
+ if (!xive->nr_ends) {
+ error_setg(errp, "Number of interrupt needs to be greater 0");
+ return;
+ }
+
+ /*
+ * Initialize the internal sources, for IPIs and virtual devices.
+ */
+ object_property_set_int(OBJECT(xsrc), xive->nr_irqs, "nr-irqs",
+ &error_fatal);
+ object_property_add_const_link(OBJECT(xsrc), "xive", OBJECT(xive),
+ &error_fatal);
+ object_property_set_bool(OBJECT(xsrc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /*
+ * Initialize the END ESB source
+ */
+ object_property_set_int(OBJECT(end_xsrc), xive->nr_irqs, "nr-ends",
+ &error_fatal);
+ object_property_add_const_link(OBJECT(end_xsrc), "xive", OBJECT(xive),
+ &error_fatal);
+ object_property_set_bool(OBJECT(end_xsrc), true, "realized", &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /* Set the mapping address of the END ESB pages after the source ESBs */
+ xive->end_base = xive->vc_base + (1ull << xsrc->esb_shift) * xsrc->nr_irqs;
+
+ /*
+ * Allocate the routing tables
+ */
+ xive->eat = g_new0(XiveEAS, xive->nr_irqs);
+ xive->endt = g_new0(XiveEND, xive->nr_ends);
+
+ /* TIMA initialization */
+ memory_region_init_io(&xive->tm_mmio, OBJECT(xive), &xive_tm_ops, xive,
+ "xive.tima", 4ull << TM_SHIFT);
+
+ /* Define all XIVE MMIO regions on SysBus */
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xsrc->esb_mmio);
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &end_xsrc->esb_mmio);
+ sysbus_init_mmio(SYS_BUS_DEVICE(xive), &xive->tm_mmio);
+
+ /* Map all regions */
+ spapr_xive_map_mmio(xive);
+
+ qemu_register_reset(spapr_xive_reset, dev);
+}
+
+static int spapr_xive_get_eas(XiveRouter *xrtr, uint8_t eas_blk,
+ uint32_t eas_idx, XiveEAS *eas)
+{
+ sPAPRXive *xive = SPAPR_XIVE(xrtr);
+
+ if (eas_idx >= xive->nr_irqs) {
+ return -1;
+ }
+
+ *eas = xive->eat[eas_idx];
+ return 0;
+}
+
+static int spapr_xive_get_end(XiveRouter *xrtr,
+ uint8_t end_blk, uint32_t end_idx, XiveEND *end)
+{
+ sPAPRXive *xive = SPAPR_XIVE(xrtr);
+
+ if (end_idx >= xive->nr_ends) {
+ return -1;
+ }
+
+ memcpy(end, &xive->endt[end_idx], sizeof(XiveEND));
+ return 0;
+}
+
+static int spapr_xive_write_end(XiveRouter *xrtr, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ uint8_t word_number)
+{
+ sPAPRXive *xive = SPAPR_XIVE(xrtr);
+
+ if (end_idx >= xive->nr_ends) {
+ return -1;
+ }
+
+ memcpy(&xive->endt[end_idx], end, sizeof(XiveEND));
+ return 0;
+}
+
+static int spapr_xive_get_nvt(XiveRouter *xrtr,
+ uint8_t nvt_blk, uint32_t nvt_idx, XiveNVT *nvt)
+{
+ uint32_t vcpu_id = spapr_xive_nvt_to_target(nvt_blk, nvt_idx);
+ PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
+
+ if (!cpu) {
+ /* TODO: should we assert() if we can find a NVT ? */
+ return -1;
+ }
+
+ /*
+ * sPAPR does not maintain a NVT table. Return that the NVT is
+ * valid if we have found a matching CPU
+ */
+ nvt->w0 = cpu_to_be32(NVT_W0_VALID);
+ return 0;
+}
+
+static int spapr_xive_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk,
+ uint32_t nvt_idx, XiveNVT *nvt,
+ uint8_t word_number)
+{
+ /*
+ * We don't need to write back to the NVTs because the sPAPR
+ * machine should never hit a non-scheduled NVT. It should never
+ * get called.
+ */
+ g_assert_not_reached();
+}
+
+static const VMStateDescription vmstate_spapr_xive_end = {
+ .name = TYPE_SPAPR_XIVE "/end",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(w0, XiveEND),
+ VMSTATE_UINT32(w1, XiveEND),
+ VMSTATE_UINT32(w2, XiveEND),
+ VMSTATE_UINT32(w3, XiveEND),
+ VMSTATE_UINT32(w4, XiveEND),
+ VMSTATE_UINT32(w5, XiveEND),
+ VMSTATE_UINT32(w6, XiveEND),
+ VMSTATE_UINT32(w7, XiveEND),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_spapr_xive_eas = {
+ .name = TYPE_SPAPR_XIVE "/eas",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(w, XiveEAS),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_spapr_xive = {
+ .name = TYPE_SPAPR_XIVE,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(eat, sPAPRXive, nr_irqs,
+ vmstate_spapr_xive_eas, XiveEAS),
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(endt, sPAPRXive, nr_ends,
+ vmstate_spapr_xive_end, XiveEND),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static Property spapr_xive_properties[] = {
+ DEFINE_PROP_UINT32("nr-irqs", sPAPRXive, nr_irqs, 0),
+ DEFINE_PROP_UINT32("nr-ends", sPAPRXive, nr_ends, 0),
+ DEFINE_PROP_UINT64("vc-base", sPAPRXive, vc_base, SPAPR_XIVE_VC_BASE),
+ DEFINE_PROP_UINT64("tm-base", sPAPRXive, tm_base, SPAPR_XIVE_TM_BASE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_xive_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass);
+
+ dc->desc = "sPAPR XIVE Interrupt Controller";
+ dc->props = spapr_xive_properties;
+ dc->realize = spapr_xive_realize;
+ dc->vmsd = &vmstate_spapr_xive;
+
+ xrc->get_eas = spapr_xive_get_eas;
+ xrc->get_end = spapr_xive_get_end;
+ xrc->write_end = spapr_xive_write_end;
+ xrc->get_nvt = spapr_xive_get_nvt;
+ xrc->write_nvt = spapr_xive_write_nvt;
+}
+
+static const TypeInfo spapr_xive_info = {
+ .name = TYPE_SPAPR_XIVE,
+ .parent = TYPE_XIVE_ROUTER,
+ .instance_init = spapr_xive_instance_init,
+ .instance_size = sizeof(sPAPRXive),
+ .class_init = spapr_xive_class_init,
+};
+
+static void spapr_xive_register_types(void)
+{
+ type_register_static(&spapr_xive_info);
+}
+
+type_init(spapr_xive_register_types)
+
+bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi)
+{
+ XiveSource *xsrc = &xive->source;
+
+ if (lisn >= xive->nr_irqs) {
+ return false;
+ }
+
+ xive->eat[lisn].w |= cpu_to_be64(EAS_VALID);
+ xive_source_irq_set(xsrc, lisn, lsi);
+ return true;
+}
+
+bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn)
+{
+ XiveSource *xsrc = &xive->source;
+
+ if (lisn >= xive->nr_irqs) {
+ return false;
+ }
+
+ xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
+ xive_source_irq_set(xsrc, lisn, false);
+ return true;
+}
+
+/*
+ * XIVE hcalls
+ *
+ * The terminology used by the XIVE hcalls is the following :
+ *
+ * TARGET vCPU number
+ * EQ Event Queue assigned by OS to receive event data
+ * ESB page for source interrupt management
+ * LISN Logical Interrupt Source Number identifying a source in the
+ * machine
+ * EISN Effective Interrupt Source Number used by guest OS to
+ * identify source in the guest
+ *
+ * The EAS, END, NVT structures are not exposed.
+ */
+
+/*
+ * Linux hosts under OPAL reserve priority 7 for their own escalation
+ * interrupts (DD2.X POWER9). So we only allow the guest to use
+ * priorities [0..6].
+ */
+static bool spapr_xive_priority_is_reserved(uint8_t priority)
+{
+ switch (priority) {
+ case 0 ... 6:
+ return false;
+ case 7: /* OPAL escalation queue */
+ default:
+ return true;
+ }
+}
+
+/*
+ * The H_INT_GET_SOURCE_INFO hcall() is used to obtain the logical
+ * real address of the MMIO page through which the Event State Buffer
+ * entry associated with the value of the "lisn" parameter is managed.
+ *
+ * Parameters:
+ * Input
+ * - R4: "flags"
+ * Bits 0-63 reserved
+ * - R5: "lisn" is per "interrupts", "interrupt-map", or
+ * "ibm,xive-lisn-ranges" properties, or as returned by the
+ * ibm,query-interrupt-source-number RTAS call, or as returned
+ * by the H_ALLOCATE_VAS_WINDOW hcall
+ *
+ * Output
+ * - R4: "flags"
+ * Bits 0-59: Reserved
+ * Bit 60: H_INT_ESB must be used for Event State Buffer
+ * management
+ * Bit 61: 1 == LSI 0 == MSI
+ * Bit 62: the full function page supports trigger
+ * Bit 63: Store EOI Supported
+ * - R5: Logical Real address of full function Event State Buffer
+ * management page, -1 if H_INT_ESB hcall flag is set to 1.
+ * - R6: Logical Real Address of trigger only Event State Buffer
+ * management page or -1.
+ * - R7: Power of 2 page size for the ESB management pages returned in
+ * R5 and R6.
+ */
+
+#define SPAPR_XIVE_SRC_H_INT_ESB PPC_BIT(60) /* ESB manage with H_INT_ESB */
+#define SPAPR_XIVE_SRC_LSI PPC_BIT(61) /* Virtual LSI type */
+#define SPAPR_XIVE_SRC_TRIGGER PPC_BIT(62) /* Trigger and management
+ on same page */
+#define SPAPR_XIVE_SRC_STORE_EOI PPC_BIT(63) /* Store EOI support */
+
+static target_ulong h_int_get_source_info(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ XiveSource *xsrc = &xive->source;
+ target_ulong flags = args[0];
+ target_ulong lisn = args[1];
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags) {
+ return H_PARAMETER;
+ }
+
+ if (lisn >= xive->nr_irqs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ if (!xive_eas_is_valid(&xive->eat[lisn])) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ /*
+ * All sources are emulated under the main XIVE object and share
+ * the same characteristics.
+ */
+ args[0] = 0;
+ if (!xive_source_esb_has_2page(xsrc)) {
+ args[0] |= SPAPR_XIVE_SRC_TRIGGER;
+ }
+ if (xsrc->esb_flags & XIVE_SRC_STORE_EOI) {
+ args[0] |= SPAPR_XIVE_SRC_STORE_EOI;
+ }
+
+ /*
+ * Force the use of the H_INT_ESB hcall in case of an LSI
+ * interrupt. This is necessary under KVM to re-trigger the
+ * interrupt if the level is still asserted
+ */
+ if (xive_source_irq_is_lsi(xsrc, lisn)) {
+ args[0] |= SPAPR_XIVE_SRC_H_INT_ESB | SPAPR_XIVE_SRC_LSI;
+ }
+
+ if (!(args[0] & SPAPR_XIVE_SRC_H_INT_ESB)) {
+ args[1] = xive->vc_base + xive_source_esb_mgmt(xsrc, lisn);
+ } else {
+ args[1] = -1;
+ }
+
+ if (xive_source_esb_has_2page(xsrc) &&
+ !(args[0] & SPAPR_XIVE_SRC_H_INT_ESB)) {
+ args[2] = xive->vc_base + xive_source_esb_page(xsrc, lisn);
+ } else {
+ args[2] = -1;
+ }
+
+ if (xive_source_esb_has_2page(xsrc)) {
+ args[3] = xsrc->esb_shift - 1;
+ } else {
+ args[3] = xsrc->esb_shift;
+ }
+
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_SET_SOURCE_CONFIG hcall() is used to assign a Logical
+ * Interrupt Source to a target. The Logical Interrupt Source is
+ * designated with the "lisn" parameter and the target is designated
+ * with the "target" and "priority" parameters. Upon return from the
+ * hcall(), no additional interrupts will be directed to the old EQ.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-61: Reserved
+ * Bit 62: set the "eisn" in the EAS
+ * Bit 63: masks the interrupt source in the hardware interrupt
+ * control structure. An interrupt masked by this mechanism will
+ * be dropped, but it's source state bits will still be
+ * set. There is no race-free way of unmasking and restoring the
+ * source. Thus this should only be used in interrupts that are
+ * also masked at the source, and only in cases where the
+ * interrupt is not meant to be used for a large amount of time
+ * because no valid target exists for it for example
+ * - R5: "lisn" is per "interrupts", "interrupt-map", or
+ * "ibm,xive-lisn-ranges" properties, or as returned by the
+ * ibm,query-interrupt-source-number RTAS call, or as returned by
+ * the H_ALLOCATE_VAS_WINDOW hcall
+ * - R6: "target" is per "ibm,ppc-interrupt-server#s" or
+ * "ibm,ppc-interrupt-gserver#s"
+ * - R7: "priority" is a valid priority not in
+ * "ibm,plat-res-int-priorities"
+ * - R8: "eisn" is the guest EISN associated with the "lisn"
+ *
+ * Output:
+ * - None
+ */
+
+#define SPAPR_XIVE_SRC_SET_EISN PPC_BIT(62)
+#define SPAPR_XIVE_SRC_MASK PPC_BIT(63)
+
+static target_ulong h_int_set_source_config(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ XiveEAS eas, new_eas;
+ target_ulong flags = args[0];
+ target_ulong lisn = args[1];
+ target_ulong target = args[2];
+ target_ulong priority = args[3];
+ target_ulong eisn = args[4];
+ uint8_t end_blk;
+ uint32_t end_idx;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags & ~(SPAPR_XIVE_SRC_SET_EISN | SPAPR_XIVE_SRC_MASK)) {
+ return H_PARAMETER;
+ }
+
+ if (lisn >= xive->nr_irqs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ eas = xive->eat[lisn];
+ if (!xive_eas_is_valid(&eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ /* priority 0xff is used to reset the EAS */
+ if (priority == 0xff) {
+ new_eas.w = cpu_to_be64(EAS_VALID | EAS_MASKED);
+ goto out;
+ }
+
+ if (flags & SPAPR_XIVE_SRC_MASK) {
+ new_eas.w = eas.w | cpu_to_be64(EAS_MASKED);
+ } else {
+ new_eas.w = eas.w & cpu_to_be64(~EAS_MASKED);
+ }
+
+ if (spapr_xive_priority_is_reserved(priority)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: priority " TARGET_FMT_ld
+ " is reserved\n", priority);
+ return H_P4;
+ }
+
+ /*
+ * Validate that "target" is part of the list of threads allocated
+ * to the partition. For that, find the END corresponding to the
+ * target.
+ */
+ if (spapr_xive_target_to_end(target, priority, &end_blk, &end_idx)) {
+ return H_P3;
+ }
+
+ new_eas.w = xive_set_field64(EAS_END_BLOCK, new_eas.w, end_blk);
+ new_eas.w = xive_set_field64(EAS_END_INDEX, new_eas.w, end_idx);
+
+ if (flags & SPAPR_XIVE_SRC_SET_EISN) {
+ new_eas.w = xive_set_field64(EAS_END_DATA, new_eas.w, eisn);
+ }
+
+out:
+ xive->eat[lisn] = new_eas;
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_GET_SOURCE_CONFIG hcall() is used to determine to which
+ * target/priority pair is assigned to the specified Logical Interrupt
+ * Source.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63 Reserved
+ * - R5: "lisn" is per "interrupts", "interrupt-map", or
+ * "ibm,xive-lisn-ranges" properties, or as returned by the
+ * ibm,query-interrupt-source-number RTAS call, or as
+ * returned by the H_ALLOCATE_VAS_WINDOW hcall
+ *
+ * Output:
+ * - R4: Target to which the specified Logical Interrupt Source is
+ * assigned
+ * - R5: Priority to which the specified Logical Interrupt Source is
+ * assigned
+ * - R6: EISN for the specified Logical Interrupt Source (this will be
+ * equivalent to the LISN if not changed by H_INT_SET_SOURCE_CONFIG)
+ */
+static target_ulong h_int_get_source_config(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ target_ulong flags = args[0];
+ target_ulong lisn = args[1];
+ XiveEAS eas;
+ XiveEND *end;
+ uint8_t nvt_blk;
+ uint32_t end_idx, nvt_idx;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags) {
+ return H_PARAMETER;
+ }
+
+ if (lisn >= xive->nr_irqs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ eas = xive->eat[lisn];
+ if (!xive_eas_is_valid(&eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ /* EAS_END_BLOCK is unused on sPAPR */
+ end_idx = xive_get_field64(EAS_END_INDEX, eas.w);
+
+ assert(end_idx < xive->nr_ends);
+ end = &xive->endt[end_idx];
+
+ nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end->w6);
+ nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end->w6);
+ args[0] = spapr_xive_nvt_to_target(nvt_blk, nvt_idx);
+
+ if (xive_eas_is_masked(&eas)) {
+ args[1] = 0xff;
+ } else {
+ args[1] = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
+ }
+
+ args[2] = xive_get_field64(EAS_END_DATA, eas.w);
+
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_GET_QUEUE_INFO hcall() is used to get the logical real
+ * address of the notification management page associated with the
+ * specified target and priority.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63 Reserved
+ * - R5: "target" is per "ibm,ppc-interrupt-server#s" or
+ * "ibm,ppc-interrupt-gserver#s"
+ * - R6: "priority" is a valid priority not in
+ * "ibm,plat-res-int-priorities"
+ *
+ * Output:
+ * - R4: Logical real address of notification page
+ * - R5: Power of 2 page size of the notification page
+ */
+static target_ulong h_int_get_queue_info(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ XiveENDSource *end_xsrc = &xive->end_source;
+ target_ulong flags = args[0];
+ target_ulong target = args[1];
+ target_ulong priority = args[2];
+ XiveEND *end;
+ uint8_t end_blk;
+ uint32_t end_idx;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags) {
+ return H_PARAMETER;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ if (spapr_xive_priority_is_reserved(priority)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: priority " TARGET_FMT_ld
+ " is reserved\n", priority);
+ return H_P3;
+ }
+
+ /*
+ * Validate that "target" is part of the list of threads allocated
+ * to the partition. For that, find the END corresponding to the
+ * target.
+ */
+ if (spapr_xive_target_to_end(target, priority, &end_blk, &end_idx)) {
+ return H_P2;
+ }
+
+ assert(end_idx < xive->nr_ends);
+ end = &xive->endt[end_idx];
+
+ args[0] = xive->end_base + (1ull << (end_xsrc->esb_shift + 1)) * end_idx;
+ if (xive_end_is_enqueue(end)) {
+ args[1] = xive_get_field32(END_W0_QSIZE, end->w0) + 12;
+ } else {
+ args[1] = 0;
+ }
+
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_SET_QUEUE_CONFIG hcall() is used to set or reset a EQ for
+ * a given "target" and "priority". It is also used to set the
+ * notification config associated with the EQ. An EQ size of 0 is
+ * used to reset the EQ config for a given target and priority. If
+ * resetting the EQ config, the END associated with the given "target"
+ * and "priority" will be changed to disable queueing.
+ *
+ * Upon return from the hcall(), no additional interrupts will be
+ * directed to the old EQ (if one was set). The old EQ (if one was
+ * set) should be investigated for interrupts that occurred prior to
+ * or during the hcall().
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-62: Reserved
+ * Bit 63: Unconditional Notify (n) per the XIVE spec
+ * - R5: "target" is per "ibm,ppc-interrupt-server#s" or
+ * "ibm,ppc-interrupt-gserver#s"
+ * - R6: "priority" is a valid priority not in
+ * "ibm,plat-res-int-priorities"
+ * - R7: "eventQueue": The logical real address of the start of the EQ
+ * - R8: "eventQueueSize": The power of 2 EQ size per "ibm,xive-eq-sizes"
+ *
+ * Output:
+ * - None
+ */
+
+#define SPAPR_XIVE_END_ALWAYS_NOTIFY PPC_BIT(63)
+
+static target_ulong h_int_set_queue_config(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ target_ulong flags = args[0];
+ target_ulong target = args[1];
+ target_ulong priority = args[2];
+ target_ulong qpage = args[3];
+ target_ulong qsize = args[4];
+ XiveEND end;
+ uint8_t end_blk, nvt_blk;
+ uint32_t end_idx, nvt_idx;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags & ~SPAPR_XIVE_END_ALWAYS_NOTIFY) {
+ return H_PARAMETER;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ if (spapr_xive_priority_is_reserved(priority)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: priority " TARGET_FMT_ld
+ " is reserved\n", priority);
+ return H_P3;
+ }
+
+ /*
+ * Validate that "target" is part of the list of threads allocated
+ * to the partition. For that, find the END corresponding to the
+ * target.
+ */
+
+ if (spapr_xive_target_to_end(target, priority, &end_blk, &end_idx)) {
+ return H_P2;
+ }
+
+ assert(end_idx < xive->nr_ends);
+ memcpy(&end, &xive->endt[end_idx], sizeof(XiveEND));
+
+ switch (qsize) {
+ case 12:
+ case 16:
+ case 21:
+ case 24:
+ end.w2 = cpu_to_be32((qpage >> 32) & 0x0fffffff);
+ end.w3 = cpu_to_be32(qpage & 0xffffffff);
+ end.w0 |= cpu_to_be32(END_W0_ENQUEUE);
+ end.w0 = xive_set_field32(END_W0_QSIZE, end.w0, qsize - 12);
+ break;
+ case 0:
+ /* reset queue and disable queueing */
+ spapr_xive_end_reset(&end);
+ goto out;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid EQ size %"PRIx64"\n",
+ qsize);
+ return H_P5;
+ }
+
+ if (qsize) {
+ hwaddr plen = 1 << qsize;
+ void *eq;
+
+ /*
+ * Validate the guest EQ. We should also check that the queue
+ * has been zeroed by the OS.
+ */
+ eq = address_space_map(CPU(cpu)->as, qpage, &plen, true,
+ MEMTXATTRS_UNSPECIFIED);
+ if (plen != 1 << qsize) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to map EQ @0x%"
+ HWADDR_PRIx "\n", qpage);
+ return H_P4;
+ }
+ address_space_unmap(CPU(cpu)->as, eq, plen, true, plen);
+ }
+
+ /* "target" should have been validated above */
+ if (spapr_xive_target_to_nvt(target, &nvt_blk, &nvt_idx)) {
+ g_assert_not_reached();
+ }
+
+ /*
+ * Ensure the priority and target are correctly set (they will not
+ * be right after allocation)
+ */
+ end.w6 = xive_set_field32(END_W6_NVT_BLOCK, 0ul, nvt_blk) |
+ xive_set_field32(END_W6_NVT_INDEX, 0ul, nvt_idx);
+ end.w7 = xive_set_field32(END_W7_F0_PRIORITY, 0ul, priority);
+
+ if (flags & SPAPR_XIVE_END_ALWAYS_NOTIFY) {
+ end.w0 |= cpu_to_be32(END_W0_UCOND_NOTIFY);
+ } else {
+ end.w0 &= cpu_to_be32((uint32_t)~END_W0_UCOND_NOTIFY);
+ }
+
+ /*
+ * The generation bit for the END starts at 1 and The END page
+ * offset counter starts at 0.
+ */
+ end.w1 = cpu_to_be32(END_W1_GENERATION) |
+ xive_set_field32(END_W1_PAGE_OFF, 0ul, 0ul);
+ end.w0 |= cpu_to_be32(END_W0_VALID);
+
+ /*
+ * TODO: issue syncs required to ensure all in-flight interrupts
+ * are complete on the old END
+ */
+
+out:
+ /* Update END */
+ memcpy(&xive->endt[end_idx], &end, sizeof(XiveEND));
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_GET_QUEUE_CONFIG hcall() is used to get a EQ for a given
+ * target and priority.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-62: Reserved
+ * Bit 63: Debug: Return debug data
+ * - R5: "target" is per "ibm,ppc-interrupt-server#s" or
+ * "ibm,ppc-interrupt-gserver#s"
+ * - R6: "priority" is a valid priority not in
+ * "ibm,plat-res-int-priorities"
+ *
+ * Output:
+ * - R4: "flags":
+ * Bits 0-61: Reserved
+ * Bit 62: The value of Event Queue Generation Number (g) per
+ * the XIVE spec if "Debug" = 1
+ * Bit 63: The value of Unconditional Notify (n) per the XIVE spec
+ * - R5: The logical real address of the start of the EQ
+ * - R6: The power of 2 EQ size per "ibm,xive-eq-sizes"
+ * - R7: The value of Event Queue Offset Counter per XIVE spec
+ * if "Debug" = 1, else 0
+ *
+ */
+
+#define SPAPR_XIVE_END_DEBUG PPC_BIT(63)
+
+static target_ulong h_int_get_queue_config(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ target_ulong flags = args[0];
+ target_ulong target = args[1];
+ target_ulong priority = args[2];
+ XiveEND *end;
+ uint8_t end_blk;
+ uint32_t end_idx;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags & ~SPAPR_XIVE_END_DEBUG) {
+ return H_PARAMETER;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ if (spapr_xive_priority_is_reserved(priority)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: priority " TARGET_FMT_ld
+ " is reserved\n", priority);
+ return H_P3;
+ }
+
+ /*
+ * Validate that "target" is part of the list of threads allocated
+ * to the partition. For that, find the END corresponding to the
+ * target.
+ */
+ if (spapr_xive_target_to_end(target, priority, &end_blk, &end_idx)) {
+ return H_P2;
+ }
+
+ assert(end_idx < xive->nr_ends);
+ end = &xive->endt[end_idx];
+
+ args[0] = 0;
+ if (xive_end_is_notify(end)) {
+ args[0] |= SPAPR_XIVE_END_ALWAYS_NOTIFY;
+ }
+
+ if (xive_end_is_enqueue(end)) {
+ args[1] = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ args[2] = xive_get_field32(END_W0_QSIZE, end->w0) + 12;
+ } else {
+ args[1] = 0;
+ args[2] = 0;
+ }
+
+ /* TODO: do we need any locking on the END ? */
+ if (flags & SPAPR_XIVE_END_DEBUG) {
+ /* Load the event queue generation number into the return flags */
+ args[0] |= (uint64_t)xive_get_field32(END_W1_GENERATION, end->w1) << 62;
+
+ /* Load R7 with the event queue offset counter */
+ args[3] = xive_get_field32(END_W1_PAGE_OFF, end->w1);
+ } else {
+ args[3] = 0;
+ }
+
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_SET_OS_REPORTING_LINE hcall() is used to set the
+ * reporting cache line pair for the calling thread. The reporting
+ * cache lines will contain the OS interrupt context when the OS
+ * issues a CI store byte to @TIMA+0xC10 to acknowledge the OS
+ * interrupt. The reporting cache lines can be reset by inputting -1
+ * in "reportingLine". Issuing the CI store byte without reporting
+ * cache lines registered will result in the data not being accessible
+ * to the OS.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63: Reserved
+ * - R5: "reportingLine": The logical real address of the reporting cache
+ * line pair
+ *
+ * Output:
+ * - None
+ */
+static target_ulong h_int_set_os_reporting_line(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ /* TODO: H_INT_SET_OS_REPORTING_LINE */
+ return H_FUNCTION;
+}
+
+/*
+ * The H_INT_GET_OS_REPORTING_LINE hcall() is used to get the logical
+ * real address of the reporting cache line pair set for the input
+ * "target". If no reporting cache line pair has been set, -1 is
+ * returned.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63: Reserved
+ * - R5: "target" is per "ibm,ppc-interrupt-server#s" or
+ * "ibm,ppc-interrupt-gserver#s"
+ * - R6: "reportingLine": The logical real address of the reporting
+ * cache line pair
+ *
+ * Output:
+ * - R4: The logical real address of the reporting line if set, else -1
+ */
+static target_ulong h_int_get_os_reporting_line(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ /* TODO: H_INT_GET_OS_REPORTING_LINE */
+ return H_FUNCTION;
+}
+
+/*
+ * The H_INT_ESB hcall() is used to issue a load or store to the ESB
+ * page for the input "lisn". This hcall is only supported for LISNs
+ * that have the ESB hcall flag set to 1 when returned from hcall()
+ * H_INT_GET_SOURCE_INFO.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-62: Reserved
+ * bit 63: Store: Store=1, store operation, else load operation
+ * - R5: "lisn" is per "interrupts", "interrupt-map", or
+ * "ibm,xive-lisn-ranges" properties, or as returned by the
+ * ibm,query-interrupt-source-number RTAS call, or as
+ * returned by the H_ALLOCATE_VAS_WINDOW hcall
+ * - R6: "esbOffset" is the offset into the ESB page for the load or
+ * store operation
+ * - R7: "storeData" is the data to write for a store operation
+ *
+ * Output:
+ * - R4: The value of the load if load operation, else -1
+ */
+
+#define SPAPR_XIVE_ESB_STORE PPC_BIT(63)
+
+static target_ulong h_int_esb(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ XiveEAS eas;
+ target_ulong flags = args[0];
+ target_ulong lisn = args[1];
+ target_ulong offset = args[2];
+ target_ulong data = args[3];
+ hwaddr mmio_addr;
+ XiveSource *xsrc = &xive->source;
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags & ~SPAPR_XIVE_ESB_STORE) {
+ return H_PARAMETER;
+ }
+
+ if (lisn >= xive->nr_irqs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ eas = xive->eat[lisn];
+ if (!xive_eas_is_valid(&eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ if (offset > (1ull << xsrc->esb_shift)) {
+ return H_P3;
+ }
+
+ mmio_addr = xive->vc_base + xive_source_esb_mgmt(xsrc, lisn) + offset;
+
+ if (dma_memory_rw(&address_space_memory, mmio_addr, &data, 8,
+ (flags & SPAPR_XIVE_ESB_STORE))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to access ESB @0x%"
+ HWADDR_PRIx "\n", mmio_addr);
+ return H_HARDWARE;
+ }
+ args[0] = (flags & SPAPR_XIVE_ESB_STORE) ? -1 : data;
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_SYNC hcall() is used to issue hardware syncs that will
+ * ensure any in flight events for the input lisn are in the event
+ * queue.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63: Reserved
+ * - R5: "lisn" is per "interrupts", "interrupt-map", or
+ * "ibm,xive-lisn-ranges" properties, or as returned by the
+ * ibm,query-interrupt-source-number RTAS call, or as
+ * returned by the H_ALLOCATE_VAS_WINDOW hcall
+ *
+ * Output:
+ * - None
+ */
+static target_ulong h_int_sync(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ XiveEAS eas;
+ target_ulong flags = args[0];
+ target_ulong lisn = args[1];
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags) {
+ return H_PARAMETER;
+ }
+
+ if (lisn >= xive->nr_irqs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ eas = xive->eat[lisn];
+ if (!xive_eas_is_valid(&eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Invalid LISN " TARGET_FMT_lx "\n",
+ lisn);
+ return H_P2;
+ }
+
+ /*
+ * H_STATE should be returned if a H_INT_RESET is in progress.
+ * This is not needed when running the emulation under QEMU
+ */
+
+ /* This is not real hardware. Nothing to be done */
+ return H_SUCCESS;
+}
+
+/*
+ * The H_INT_RESET hcall() is used to reset all of the partition's
+ * interrupt exploitation structures to their initial state. This
+ * means losing all previously set interrupt state set via
+ * H_INT_SET_SOURCE_CONFIG and H_INT_SET_QUEUE_CONFIG.
+ *
+ * Parameters:
+ * Input:
+ * - R4: "flags"
+ * Bits 0-63: Reserved
+ *
+ * Output:
+ * - None
+ */
+static target_ulong h_int_reset(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ sPAPRXive *xive = spapr->xive;
+ target_ulong flags = args[0];
+
+ if (!spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ return H_FUNCTION;
+ }
+
+ if (flags) {
+ return H_PARAMETER;
+ }
+
+ device_reset(DEVICE(xive));
+ return H_SUCCESS;
+}
+
+void spapr_xive_hcall_init(sPAPRMachineState *spapr)
+{
+ spapr_register_hypercall(H_INT_GET_SOURCE_INFO, h_int_get_source_info);
+ spapr_register_hypercall(H_INT_SET_SOURCE_CONFIG, h_int_set_source_config);
+ spapr_register_hypercall(H_INT_GET_SOURCE_CONFIG, h_int_get_source_config);
+ spapr_register_hypercall(H_INT_GET_QUEUE_INFO, h_int_get_queue_info);
+ spapr_register_hypercall(H_INT_SET_QUEUE_CONFIG, h_int_set_queue_config);
+ spapr_register_hypercall(H_INT_GET_QUEUE_CONFIG, h_int_get_queue_config);
+ spapr_register_hypercall(H_INT_SET_OS_REPORTING_LINE,
+ h_int_set_os_reporting_line);
+ spapr_register_hypercall(H_INT_GET_OS_REPORTING_LINE,
+ h_int_get_os_reporting_line);
+ spapr_register_hypercall(H_INT_ESB, h_int_esb);
+ spapr_register_hypercall(H_INT_SYNC, h_int_sync);
+ spapr_register_hypercall(H_INT_RESET, h_int_reset);
+}
+
+void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+ uint32_t phandle)
+{
+ sPAPRXive *xive = spapr->xive;
+ int node;
+ uint64_t timas[2 * 2];
+ /* Interrupt number ranges for the IPIs */
+ uint32_t lisn_ranges[] = {
+ cpu_to_be32(0),
+ cpu_to_be32(nr_servers),
+ };
+ /*
+ * EQ size - the sizes of pages supported by the system 4K, 64K,
+ * 2M, 16M. We only advertise 64K for the moment.
+ */
+ uint32_t eq_sizes[] = {
+ cpu_to_be32(16), /* 64K */
+ };
+ /*
+ * The following array is in sync with the reserved priorities
+ * defined by the 'spapr_xive_priority_is_reserved' routine.
+ */
+ uint32_t plat_res_int_priorities[] = {
+ cpu_to_be32(7), /* start */
+ cpu_to_be32(0xf8), /* count */
+ };
+ gchar *nodename;
+
+ /* Thread Interrupt Management Area : User (ring 3) and OS (ring 2) */
+ timas[0] = cpu_to_be64(xive->tm_base +
+ XIVE_TM_USER_PAGE * (1ull << TM_SHIFT));
+ timas[1] = cpu_to_be64(1ull << TM_SHIFT);
+ timas[2] = cpu_to_be64(xive->tm_base +
+ XIVE_TM_OS_PAGE * (1ull << TM_SHIFT));
+ timas[3] = cpu_to_be64(1ull << TM_SHIFT);
+
+ nodename = g_strdup_printf("interrupt-controller@%" PRIx64,
+ xive->tm_base + XIVE_TM_USER_PAGE * (1 << TM_SHIFT));
+ _FDT(node = fdt_add_subnode(fdt, 0, nodename));
+ g_free(nodename);
+
+ _FDT(fdt_setprop_string(fdt, node, "device_type", "power-ivpe"));
+ _FDT(fdt_setprop(fdt, node, "reg", timas, sizeof(timas)));
+
+ _FDT(fdt_setprop_string(fdt, node, "compatible", "ibm,power-ivpe"));
+ _FDT(fdt_setprop(fdt, node, "ibm,xive-eq-sizes", eq_sizes,
+ sizeof(eq_sizes)));
+ _FDT(fdt_setprop(fdt, node, "ibm,xive-lisn-ranges", lisn_ranges,
+ sizeof(lisn_ranges)));
+
+ /* For Linux to link the LSIs to the interrupt controller. */
+ _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0));
+ _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2));
+
+ /* For SLOF */
+ _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
+ _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
+
+ /*
+ * The "ibm,plat-res-int-priorities" property defines the priority
+ * ranges reserved by the hypervisor
+ */
+ _FDT(fdt_setprop(fdt, 0, "ibm,plat-res-int-priorities",
+ plat_res_int_priorities, sizeof(plat_res_int_priorities)));
+}
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 406efee064..16e8ffa2aa 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -461,7 +461,7 @@ static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val)
ics_simple_resend_lsi(ics, srcno);
}
-static void ics_simple_set_irq(void *opaque, int srcno, int val)
+void ics_simple_set_irq(void *opaque, int srcno, int val)
{
ICSState *ics = (ICSState *)opaque;
@@ -571,8 +571,6 @@ static void ics_simple_realize(DeviceState *dev, Error **errp)
return;
}
- ics->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
-
qemu_register_reset(ics_simple_reset_handler, ics);
}
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index e8fa9a53ae..dff1330050 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -34,6 +34,7 @@
#include "sysemu/kvm.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h"
+#include "hw/ppc/xics_spapr.h"
#include "kvm_ppc.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
@@ -298,7 +299,7 @@ static int ics_set_kvm_state(ICSState *ics, int version_id)
return 0;
}
-static void ics_kvm_set_irq(void *opaque, int srcno, int val)
+void ics_kvm_set_irq(void *opaque, int srcno, int val)
{
ICSState *ics = opaque;
struct kvm_irq_level args;
@@ -344,7 +345,6 @@ static void ics_kvm_realize(DeviceState *dev, Error **errp)
error_propagate(errp, local_err);
return;
}
- ics->qirqs = qemu_allocate_irqs(ics_kvm_set_irq, ics, ics->nr_irqs);
qemu_register_reset(ics_kvm_reset_handler, ics);
}
diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c
index 2e27b92b87..de6cc15b64 100644
--- a/hw/intc/xics_spapr.c
+++ b/hw/intc/xics_spapr.c
@@ -32,6 +32,7 @@
#include "qemu/timer.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h"
+#include "hw/ppc/xics_spapr.h"
#include "hw/ppc/fdt.h"
#include "qapi/visitor.h"
@@ -44,7 +45,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
target_ulong cppr = args[0];
- icp_set_cppr(ICP(cpu->intc), cppr);
+ icp_set_cppr(cpu->icp, cppr);
return H_SUCCESS;
}
@@ -65,7 +66,7 @@ static target_ulong h_ipi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- uint32_t xirr = icp_accept(ICP(cpu->intc));
+ uint32_t xirr = icp_accept(cpu->icp);
args[0] = xirr;
return H_SUCCESS;
@@ -74,7 +75,7 @@ static target_ulong h_xirr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
static target_ulong h_xirr_x(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- uint32_t xirr = icp_accept(ICP(cpu->intc));
+ uint32_t xirr = icp_accept(cpu->icp);
args[0] = xirr;
args[1] = cpu_get_host_ticks();
@@ -86,7 +87,7 @@ static target_ulong h_eoi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
{
target_ulong xirr = args[0];
- icp_eoi(ICP(cpu->intc), xirr);
+ icp_eoi(cpu->icp, xirr);
return H_SUCCESS;
}
@@ -94,7 +95,7 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
uint32_t mfrr;
- uint32_t xirr = icp_ipoll(ICP(cpu->intc), &mfrr);
+ uint32_t xirr = icp_ipoll(cpu->icp, &mfrr);
args[0] = xirr;
args[1] = mfrr;
@@ -244,7 +245,8 @@ void xics_spapr_init(sPAPRMachineState *spapr)
spapr_register_hypercall(H_IPOLL, h_ipoll);
}
-void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle)
+void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+ uint32_t phandle)
{
uint32_t interrupt_server_ranges_prop[] = {
0, cpu_to_be32(nr_servers),
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
new file mode 100644
index 0000000000..a3cb0cf0e3
--- /dev/null
+++ b/hw/intc/xive.c
@@ -0,0 +1,1596 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "target/ppc/cpu.h"
+#include "sysemu/cpus.h"
+#include "sysemu/dma.h"
+#include "hw/qdev-properties.h"
+#include "monitor/monitor.h"
+#include "hw/ppc/xive.h"
+#include "hw/ppc/xive_regs.h"
+
+/*
+ * XIVE Thread Interrupt Management context
+ */
+
+/*
+ * Convert a priority number to an Interrupt Pending Buffer (IPB)
+ * register, which indicates a pending interrupt at the priority
+ * corresponding to the bit number
+ */
+static uint8_t priority_to_ipb(uint8_t priority)
+{
+ return priority > XIVE_PRIORITY_MAX ?
+ 0 : 1 << (XIVE_PRIORITY_MAX - priority);
+}
+
+/*
+ * Convert an Interrupt Pending Buffer (IPB) register to a Pending
+ * Interrupt Priority Register (PIPR), which contains the priority of
+ * the most favored pending notification.
+ */
+static uint8_t ipb_to_pipr(uint8_t ibp)
+{
+ return ibp ? clz32((uint32_t)ibp << 24) : 0xff;
+}
+
+static void ipb_update(uint8_t *regs, uint8_t priority)
+{
+ regs[TM_IPB] |= priority_to_ipb(priority);
+ regs[TM_PIPR] = ipb_to_pipr(regs[TM_IPB]);
+}
+
+static uint8_t exception_mask(uint8_t ring)
+{
+ switch (ring) {
+ case TM_QW1_OS:
+ return TM_QW1_NSR_EO;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static uint64_t xive_tctx_accept(XiveTCTX *tctx, uint8_t ring)
+{
+ uint8_t *regs = &tctx->regs[ring];
+ uint8_t nsr = regs[TM_NSR];
+ uint8_t mask = exception_mask(ring);
+
+ qemu_irq_lower(tctx->output);
+
+ if (regs[TM_NSR] & mask) {
+ uint8_t cppr = regs[TM_PIPR];
+
+ regs[TM_CPPR] = cppr;
+
+ /* Reset the pending buffer bit */
+ regs[TM_IPB] &= ~priority_to_ipb(cppr);
+ regs[TM_PIPR] = ipb_to_pipr(regs[TM_IPB]);
+
+ /* Drop Exception bit */
+ regs[TM_NSR] &= ~mask;
+ }
+
+ return (nsr << 8) | regs[TM_CPPR];
+}
+
+static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
+{
+ uint8_t *regs = &tctx->regs[ring];
+
+ if (regs[TM_PIPR] < regs[TM_CPPR]) {
+ regs[TM_NSR] |= exception_mask(ring);
+ qemu_irq_raise(tctx->output);
+ }
+}
+
+static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
+{
+ if (cppr > XIVE_PRIORITY_MAX) {
+ cppr = 0xff;
+ }
+
+ tctx->regs[ring + TM_CPPR] = cppr;
+
+ /* CPPR has changed, check if we need to raise a pending exception */
+ xive_tctx_notify(tctx, ring);
+}
+
+/*
+ * XIVE Thread Interrupt Management Area (TIMA)
+ */
+
+/*
+ * Define an access map for each page of the TIMA that we will use in
+ * the memory region ops to filter values when doing loads and stores
+ * of raw registers values
+ *
+ * Registers accessibility bits :
+ *
+ * 0x0 - no access
+ * 0x1 - write only
+ * 0x2 - read only
+ * 0x3 - read/write
+ */
+
+static const uint8_t xive_tm_hw_view[] = {
+ /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-2 POOL */ 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-3 PHYS */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0,
+};
+
+static const uint8_t xive_tm_hv_view[] = {
+ /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-1 OS */ 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-2 POOL */ 0, 0, 3, 3, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-3 PHYS */ 3, 3, 3, 3, 0, 3, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0,
+};
+
+static const uint8_t xive_tm_os_view[] = {
+ /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0,
+ /* QW-1 OS */ 2, 3, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* QW-2 POOL */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* QW-3 PHYS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static const uint8_t xive_tm_user_view[] = {
+ /* QW-0 User */ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* QW-1 OS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* QW-2 POOL */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* QW-3 PHYS */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Overall TIMA access map for the thread interrupt management context
+ * registers
+ */
+static const uint8_t *xive_tm_views[] = {
+ [XIVE_TM_HW_PAGE] = xive_tm_hw_view,
+ [XIVE_TM_HV_PAGE] = xive_tm_hv_view,
+ [XIVE_TM_OS_PAGE] = xive_tm_os_view,
+ [XIVE_TM_USER_PAGE] = xive_tm_user_view,
+};
+
+/*
+ * Computes a register access mask for a given offset in the TIMA
+ */
+static uint64_t xive_tm_mask(hwaddr offset, unsigned size, bool write)
+{
+ uint8_t page_offset = (offset >> TM_SHIFT) & 0x3;
+ uint8_t reg_offset = offset & 0x3F;
+ uint8_t reg_mask = write ? 0x1 : 0x2;
+ uint64_t mask = 0x0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (xive_tm_views[page_offset][reg_offset + i] & reg_mask) {
+ mask |= (uint64_t) 0xff << (8 * (size - i - 1));
+ }
+ }
+
+ return mask;
+}
+
+static void xive_tm_raw_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ uint8_t ring_offset = offset & 0x30;
+ uint8_t reg_offset = offset & 0x3F;
+ uint64_t mask = xive_tm_mask(offset, size, true);
+ int i;
+
+ /*
+ * Only 4 or 8 bytes stores are allowed and the User ring is
+ * excluded
+ */
+ if (size < 4 || !mask || ring_offset == TM_QW0_USER) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA @%"
+ HWADDR_PRIx"\n", offset);
+ return;
+ }
+
+ /*
+ * Use the register offset for the raw values and filter out
+ * reserved values
+ */
+ for (i = 0; i < size; i++) {
+ uint8_t byte_mask = (mask >> (8 * (size - i - 1)));
+ if (byte_mask) {
+ tctx->regs[reg_offset + i] = (value >> (8 * (size - i - 1))) &
+ byte_mask;
+ }
+ }
+}
+
+static uint64_t xive_tm_raw_read(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+ uint8_t ring_offset = offset & 0x30;
+ uint8_t reg_offset = offset & 0x3F;
+ uint64_t mask = xive_tm_mask(offset, size, false);
+ uint64_t ret;
+ int i;
+
+ /*
+ * Only 4 or 8 bytes loads are allowed and the User ring is
+ * excluded
+ */
+ if (size < 4 || !mask || ring_offset == TM_QW0_USER) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access at TIMA @%"
+ HWADDR_PRIx"\n", offset);
+ return -1;
+ }
+
+ /* Use the register offset for the raw values */
+ ret = 0;
+ for (i = 0; i < size; i++) {
+ ret |= (uint64_t) tctx->regs[reg_offset + i] << (8 * (size - i - 1));
+ }
+
+ /* filter out reserved values */
+ return ret & mask;
+}
+
+/*
+ * The TM context is mapped twice within each page. Stores and loads
+ * to the first mapping below 2K write and read the specified values
+ * without modification. The second mapping above 2K performs specific
+ * state changes (side effects) in addition to setting/returning the
+ * interrupt management area context of the processor thread.
+ */
+static uint64_t xive_tm_ack_os_reg(XiveTCTX *tctx, hwaddr offset, unsigned size)
+{
+ return xive_tctx_accept(tctx, TM_QW1_OS);
+}
+
+static void xive_tm_set_os_cppr(XiveTCTX *tctx, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ xive_tctx_set_cppr(tctx, TM_QW1_OS, value & 0xff);
+}
+
+/*
+ * Adjust the IPB to allow a CPU to process event queues of other
+ * priorities during one physical interrupt cycle.
+ */
+static void xive_tm_set_os_pending(XiveTCTX *tctx, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ ipb_update(&tctx->regs[TM_QW1_OS], value & 0xff);
+ xive_tctx_notify(tctx, TM_QW1_OS);
+}
+
+/*
+ * Define a mapping of "special" operations depending on the TIMA page
+ * offset and the size of the operation.
+ */
+typedef struct XiveTmOp {
+ uint8_t page_offset;
+ uint32_t op_offset;
+ unsigned size;
+ void (*write_handler)(XiveTCTX *tctx, hwaddr offset, uint64_t value,
+ unsigned size);
+ uint64_t (*read_handler)(XiveTCTX *tctx, hwaddr offset, unsigned size);
+} XiveTmOp;
+
+static const XiveTmOp xive_tm_operations[] = {
+ /*
+ * MMIOs below 2K : raw values and special operations without side
+ * effects
+ */
+ { XIVE_TM_OS_PAGE, TM_QW1_OS + TM_CPPR, 1, xive_tm_set_os_cppr, NULL },
+
+ /* MMIOs above 2K : special operations with side effects */
+ { XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
+ { XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
+};
+
+static const XiveTmOp *xive_tm_find_op(hwaddr offset, unsigned size, bool write)
+{
+ uint8_t page_offset = (offset >> TM_SHIFT) & 0x3;
+ uint32_t op_offset = offset & 0xFFF;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xive_tm_operations); i++) {
+ const XiveTmOp *xto = &xive_tm_operations[i];
+
+ /* Accesses done from a more privileged TIMA page is allowed */
+ if (xto->page_offset >= page_offset &&
+ xto->op_offset == op_offset &&
+ xto->size == size &&
+ ((write && xto->write_handler) || (!write && xto->read_handler))) {
+ return xto;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * TIMA MMIO handlers
+ */
+static void xive_tm_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
+ XiveTCTX *tctx = cpu->tctx;
+ const XiveTmOp *xto;
+
+ /*
+ * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+ */
+
+ /*
+ * First, check for special operations in the 2K region
+ */
+ if (offset & 0x800) {
+ xto = xive_tm_find_op(offset, size, true);
+ if (!xto) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA"
+ "@%"HWADDR_PRIx"\n", offset);
+ } else {
+ xto->write_handler(tctx, offset, value, size);
+ }
+ return;
+ }
+
+ /*
+ * Then, for special operations in the region below 2K.
+ */
+ xto = xive_tm_find_op(offset, size, true);
+ if (xto) {
+ xto->write_handler(tctx, offset, value, size);
+ return;
+ }
+
+ /*
+ * Finish with raw access to the register values
+ */
+ xive_tm_raw_write(tctx, offset, value, size);
+}
+
+static uint64_t xive_tm_read(void *opaque, hwaddr offset, unsigned size)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
+ XiveTCTX *tctx = cpu->tctx;
+ const XiveTmOp *xto;
+
+ /*
+ * TODO: check V bit in Q[0-3]W2, check PTER bit associated with CPU
+ */
+
+ /*
+ * First, check for special operations in the 2K region
+ */
+ if (offset & 0x800) {
+ xto = xive_tm_find_op(offset, size, false);
+ if (!xto) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid read access to TIMA"
+ "@%"HWADDR_PRIx"\n", offset);
+ return -1;
+ }
+ return xto->read_handler(tctx, offset, size);
+ }
+
+ /*
+ * Then, for special operations in the region below 2K.
+ */
+ xto = xive_tm_find_op(offset, size, false);
+ if (xto) {
+ return xto->read_handler(tctx, offset, size);
+ }
+
+ /*
+ * Finish with raw access to the register values
+ */
+ return xive_tm_raw_read(tctx, offset, size);
+}
+
+const MemoryRegionOps xive_tm_ops = {
+ .read = xive_tm_read,
+ .write = xive_tm_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+static inline uint32_t xive_tctx_word2(uint8_t *ring)
+{
+ return *((uint32_t *) &ring[TM_WORD2]);
+}
+
+static char *xive_tctx_ring_print(uint8_t *ring)
+{
+ uint32_t w2 = xive_tctx_word2(ring);
+
+ return g_strdup_printf("%02x %02x %02x %02x %02x "
+ "%02x %02x %02x %08x",
+ ring[TM_NSR], ring[TM_CPPR], ring[TM_IPB], ring[TM_LSMFB],
+ ring[TM_ACK_CNT], ring[TM_INC], ring[TM_AGE], ring[TM_PIPR],
+ be32_to_cpu(w2));
+}
+
+static const char * const xive_tctx_ring_names[] = {
+ "USER", "OS", "POOL", "PHYS",
+};
+
+void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon)
+{
+ int cpu_index = tctx->cs ? tctx->cs->cpu_index : -1;
+ int i;
+
+ monitor_printf(mon, "CPU[%04x]: QW NSR CPPR IPB LSMFB ACK# INC AGE PIPR"
+ " W2\n", cpu_index);
+
+ for (i = 0; i < XIVE_TM_RING_COUNT; i++) {
+ char *s = xive_tctx_ring_print(&tctx->regs[i * XIVE_TM_RING_SIZE]);
+ monitor_printf(mon, "CPU[%04x]: %4s %s\n", cpu_index,
+ xive_tctx_ring_names[i], s);
+ g_free(s);
+ }
+}
+
+static void xive_tctx_reset(void *dev)
+{
+ XiveTCTX *tctx = XIVE_TCTX(dev);
+
+ memset(tctx->regs, 0, sizeof(tctx->regs));
+
+ /* Set some defaults */
+ tctx->regs[TM_QW1_OS + TM_LSMFB] = 0xFF;
+ tctx->regs[TM_QW1_OS + TM_ACK_CNT] = 0xFF;
+ tctx->regs[TM_QW1_OS + TM_AGE] = 0xFF;
+
+ /*
+ * Initialize PIPR to 0xFF to avoid phantom interrupts when the
+ * CPPR is first set.
+ */
+ tctx->regs[TM_QW1_OS + TM_PIPR] =
+ ipb_to_pipr(tctx->regs[TM_QW1_OS + TM_IPB]);
+}
+
+static void xive_tctx_realize(DeviceState *dev, Error **errp)
+{
+ XiveTCTX *tctx = XIVE_TCTX(dev);
+ PowerPCCPU *cpu;
+ CPUPPCState *env;
+ Object *obj;
+ Error *local_err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "cpu", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'cpu' not found: ");
+ return;
+ }
+
+ cpu = POWERPC_CPU(obj);
+ tctx->cs = CPU(obj);
+
+ env = &cpu->env;
+ switch (PPC_INPUT(env)) {
+ case PPC_FLAGS_INPUT_POWER7:
+ tctx->output = env->irq_inputs[POWER7_INPUT_INT];
+ break;
+
+ default:
+ error_setg(errp, "XIVE interrupt controller does not support "
+ "this CPU bus model");
+ return;
+ }
+
+ qemu_register_reset(xive_tctx_reset, dev);
+}
+
+static void xive_tctx_unrealize(DeviceState *dev, Error **errp)
+{
+ qemu_unregister_reset(xive_tctx_reset, dev);
+}
+
+static const VMStateDescription vmstate_xive_tctx = {
+ .name = TYPE_XIVE_TCTX,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BUFFER(regs, XiveTCTX),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void xive_tctx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "XIVE Interrupt Thread Context";
+ dc->realize = xive_tctx_realize;
+ dc->unrealize = xive_tctx_unrealize;
+ dc->vmsd = &vmstate_xive_tctx;
+}
+
+static const TypeInfo xive_tctx_info = {
+ .name = TYPE_XIVE_TCTX,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(XiveTCTX),
+ .class_init = xive_tctx_class_init,
+};
+
+Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = object_new(TYPE_XIVE_TCTX);
+ object_property_add_child(cpu, TYPE_XIVE_TCTX, obj, &error_abort);
+ object_unref(obj);
+ object_property_add_const_link(obj, "cpu", cpu, &error_abort);
+ object_property_set_bool(obj, true, "realized", &local_err);
+ if (local_err) {
+ goto error;
+ }
+
+ return obj;
+
+error:
+ object_unparent(obj);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+/*
+ * XIVE ESB helpers
+ */
+
+static uint8_t xive_esb_set(uint8_t *pq, uint8_t value)
+{
+ uint8_t old_pq = *pq & 0x3;
+
+ *pq &= ~0x3;
+ *pq |= value & 0x3;
+
+ return old_pq;
+}
+
+static bool xive_esb_trigger(uint8_t *pq)
+{
+ uint8_t old_pq = *pq & 0x3;
+
+ switch (old_pq) {
+ case XIVE_ESB_RESET:
+ xive_esb_set(pq, XIVE_ESB_PENDING);
+ return true;
+ case XIVE_ESB_PENDING:
+ case XIVE_ESB_QUEUED:
+ xive_esb_set(pq, XIVE_ESB_QUEUED);
+ return false;
+ case XIVE_ESB_OFF:
+ xive_esb_set(pq, XIVE_ESB_OFF);
+ return false;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static bool xive_esb_eoi(uint8_t *pq)
+{
+ uint8_t old_pq = *pq & 0x3;
+
+ switch (old_pq) {
+ case XIVE_ESB_RESET:
+ case XIVE_ESB_PENDING:
+ xive_esb_set(pq, XIVE_ESB_RESET);
+ return false;
+ case XIVE_ESB_QUEUED:
+ xive_esb_set(pq, XIVE_ESB_PENDING);
+ return true;
+ case XIVE_ESB_OFF:
+ xive_esb_set(pq, XIVE_ESB_OFF);
+ return false;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+/*
+ * XIVE Interrupt Source (or IVSE)
+ */
+
+uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+
+ return xsrc->status[srcno] & 0x3;
+}
+
+uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq)
+{
+ assert(srcno < xsrc->nr_irqs);
+
+ return xive_esb_set(&xsrc->status[srcno], pq);
+}
+
+/*
+ * Returns whether the event notification should be forwarded.
+ */
+static bool xive_source_lsi_trigger(XiveSource *xsrc, uint32_t srcno)
+{
+ uint8_t old_pq = xive_source_esb_get(xsrc, srcno);
+
+ xsrc->status[srcno] |= XIVE_STATUS_ASSERTED;
+
+ switch (old_pq) {
+ case XIVE_ESB_RESET:
+ xive_source_esb_set(xsrc, srcno, XIVE_ESB_PENDING);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Returns whether the event notification should be forwarded.
+ */
+static bool xive_source_esb_trigger(XiveSource *xsrc, uint32_t srcno)
+{
+ bool ret;
+
+ assert(srcno < xsrc->nr_irqs);
+
+ ret = xive_esb_trigger(&xsrc->status[srcno]);
+
+ if (xive_source_irq_is_lsi(xsrc, srcno) &&
+ xive_source_esb_get(xsrc, srcno) == XIVE_ESB_QUEUED) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: queued an event on LSI IRQ %d\n", srcno);
+ }
+
+ return ret;
+}
+
+/*
+ * Returns whether the event notification should be forwarded.
+ */
+static bool xive_source_esb_eoi(XiveSource *xsrc, uint32_t srcno)
+{
+ bool ret;
+
+ assert(srcno < xsrc->nr_irqs);
+
+ ret = xive_esb_eoi(&xsrc->status[srcno]);
+
+ /*
+ * LSI sources do not set the Q bit but they can still be
+ * asserted, in which case we should forward a new event
+ * notification
+ */
+ if (xive_source_irq_is_lsi(xsrc, srcno) &&
+ xsrc->status[srcno] & XIVE_STATUS_ASSERTED) {
+ ret = xive_source_lsi_trigger(xsrc, srcno);
+ }
+
+ return ret;
+}
+
+/*
+ * Forward the source event notification to the Router
+ */
+static void xive_source_notify(XiveSource *xsrc, int srcno)
+{
+ XiveNotifierClass *xnc = XIVE_NOTIFIER_GET_CLASS(xsrc->xive);
+
+ if (xnc->notify) {
+ xnc->notify(xsrc->xive, srcno);
+ }
+}
+
+/*
+ * In a two pages ESB MMIO setting, even page is the trigger page, odd
+ * page is for management
+ */
+static inline bool addr_is_even(hwaddr addr, uint32_t shift)
+{
+ return !((addr >> shift) & 1);
+}
+
+static inline bool xive_source_is_trigger_page(XiveSource *xsrc, hwaddr addr)
+{
+ return xive_source_esb_has_2page(xsrc) &&
+ addr_is_even(addr, xsrc->esb_shift - 1);
+}
+
+/*
+ * ESB MMIO loads
+ * Trigger page Management/EOI page
+ *
+ * ESB MMIO setting 2 pages 1 or 2 pages
+ *
+ * 0x000 .. 0x3FF -1 EOI and return 0|1
+ * 0x400 .. 0x7FF -1 EOI and return 0|1
+ * 0x800 .. 0xBFF -1 return PQ
+ * 0xC00 .. 0xCFF -1 return PQ and atomically PQ=00
+ * 0xD00 .. 0xDFF -1 return PQ and atomically PQ=01
+ * 0xE00 .. 0xDFF -1 return PQ and atomically PQ=10
+ * 0xF00 .. 0xDFF -1 return PQ and atomically PQ=11
+ */
+static uint64_t xive_source_esb_read(void *opaque, hwaddr addr, unsigned size)
+{
+ XiveSource *xsrc = XIVE_SOURCE(opaque);
+ uint32_t offset = addr & 0xFFF;
+ uint32_t srcno = addr >> xsrc->esb_shift;
+ uint64_t ret = -1;
+
+ /* In a two pages ESB MMIO setting, trigger page should not be read */
+ if (xive_source_is_trigger_page(xsrc, addr)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: invalid load on IRQ %d trigger page at "
+ "0x%"HWADDR_PRIx"\n", srcno, addr);
+ return -1;
+ }
+
+ switch (offset) {
+ case XIVE_ESB_LOAD_EOI ... XIVE_ESB_LOAD_EOI + 0x7FF:
+ ret = xive_source_esb_eoi(xsrc, srcno);
+
+ /* Forward the source event notification for routing */
+ if (ret) {
+ xive_source_notify(xsrc, srcno);
+ }
+ break;
+
+ case XIVE_ESB_GET ... XIVE_ESB_GET + 0x3FF:
+ ret = xive_source_esb_get(xsrc, srcno);
+ break;
+
+ case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF:
+ case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF:
+ case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF:
+ case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF:
+ ret = xive_source_esb_set(xsrc, srcno, (offset >> 8) & 0x3);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB load addr %x\n",
+ offset);
+ }
+
+ return ret;
+}
+
+/*
+ * ESB MMIO stores
+ * Trigger page Management/EOI page
+ *
+ * ESB MMIO setting 2 pages 1 or 2 pages
+ *
+ * 0x000 .. 0x3FF Trigger Trigger
+ * 0x400 .. 0x7FF Trigger EOI
+ * 0x800 .. 0xBFF Trigger undefined
+ * 0xC00 .. 0xCFF Trigger PQ=00
+ * 0xD00 .. 0xDFF Trigger PQ=01
+ * 0xE00 .. 0xDFF Trigger PQ=10
+ * 0xF00 .. 0xDFF Trigger PQ=11
+ */
+static void xive_source_esb_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ XiveSource *xsrc = XIVE_SOURCE(opaque);
+ uint32_t offset = addr & 0xFFF;
+ uint32_t srcno = addr >> xsrc->esb_shift;
+ bool notify = false;
+
+ /* In a two pages ESB MMIO setting, trigger page only triggers */
+ if (xive_source_is_trigger_page(xsrc, addr)) {
+ notify = xive_source_esb_trigger(xsrc, srcno);
+ goto out;
+ }
+
+ switch (offset) {
+ case 0 ... 0x3FF:
+ notify = xive_source_esb_trigger(xsrc, srcno);
+ break;
+
+ case XIVE_ESB_STORE_EOI ... XIVE_ESB_STORE_EOI + 0x3FF:
+ if (!(xsrc->esb_flags & XIVE_SRC_STORE_EOI)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: invalid Store EOI for IRQ %d\n", srcno);
+ return;
+ }
+
+ notify = xive_source_esb_eoi(xsrc, srcno);
+ break;
+
+ case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF:
+ case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF:
+ case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF:
+ case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF:
+ xive_source_esb_set(xsrc, srcno, (offset >> 8) & 0x3);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr %x\n",
+ offset);
+ return;
+ }
+
+out:
+ /* Forward the source event notification for routing */
+ if (notify) {
+ xive_source_notify(xsrc, srcno);
+ }
+}
+
+static const MemoryRegionOps xive_source_esb_ops = {
+ .read = xive_source_esb_read,
+ .write = xive_source_esb_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+void xive_source_set_irq(void *opaque, int srcno, int val)
+{
+ XiveSource *xsrc = XIVE_SOURCE(opaque);
+ bool notify = false;
+
+ if (xive_source_irq_is_lsi(xsrc, srcno)) {
+ if (val) {
+ notify = xive_source_lsi_trigger(xsrc, srcno);
+ } else {
+ xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED;
+ }
+ } else {
+ if (val) {
+ notify = xive_source_esb_trigger(xsrc, srcno);
+ }
+ }
+
+ /* Forward the source event notification for routing */
+ if (notify) {
+ xive_source_notify(xsrc, srcno);
+ }
+}
+
+void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, Monitor *mon)
+{
+ int i;
+
+ for (i = 0; i < xsrc->nr_irqs; i++) {
+ uint8_t pq = xive_source_esb_get(xsrc, i);
+
+ if (pq == XIVE_ESB_OFF) {
+ continue;
+ }
+
+ monitor_printf(mon, " %08x %s %c%c%c\n", i + offset,
+ xive_source_irq_is_lsi(xsrc, i) ? "LSI" : "MSI",
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
+ xsrc->status[i] & XIVE_STATUS_ASSERTED ? 'A' : ' ');
+ }
+}
+
+static void xive_source_reset(void *dev)
+{
+ XiveSource *xsrc = XIVE_SOURCE(dev);
+
+ /* Do not clear the LSI bitmap */
+
+ /* PQs are initialized to 0b01 (Q=1) which corresponds to "ints off" */
+ memset(xsrc->status, XIVE_ESB_OFF, xsrc->nr_irqs);
+}
+
+static void xive_source_realize(DeviceState *dev, Error **errp)
+{
+ XiveSource *xsrc = XIVE_SOURCE(dev);
+ Object *obj;
+ Error *local_err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "xive", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'xive' not found: ");
+ return;
+ }
+
+ xsrc->xive = XIVE_NOTIFIER(obj);
+
+ if (!xsrc->nr_irqs) {
+ error_setg(errp, "Number of interrupt needs to be greater than 0");
+ return;
+ }
+
+ if (xsrc->esb_shift != XIVE_ESB_4K &&
+ xsrc->esb_shift != XIVE_ESB_4K_2PAGE &&
+ xsrc->esb_shift != XIVE_ESB_64K &&
+ xsrc->esb_shift != XIVE_ESB_64K_2PAGE) {
+ error_setg(errp, "Invalid ESB shift setting");
+ return;
+ }
+
+ xsrc->status = g_malloc0(xsrc->nr_irqs);
+ xsrc->lsi_map = bitmap_new(xsrc->nr_irqs);
+
+ memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc),
+ &xive_source_esb_ops, xsrc, "xive.esb",
+ (1ull << xsrc->esb_shift) * xsrc->nr_irqs);
+
+ qemu_register_reset(xive_source_reset, dev);
+}
+
+static const VMStateDescription vmstate_xive_source = {
+ .name = TYPE_XIVE_SOURCE,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_EQUAL(nr_irqs, XiveSource, NULL),
+ VMSTATE_VBUFFER_UINT32(status, XiveSource, 1, NULL, nr_irqs),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+/*
+ * The default XIVE interrupt source setting for the ESB MMIOs is two
+ * 64k pages without Store EOI, to be in sync with KVM.
+ */
+static Property xive_source_properties[] = {
+ DEFINE_PROP_UINT64("flags", XiveSource, esb_flags, 0),
+ DEFINE_PROP_UINT32("nr-irqs", XiveSource, nr_irqs, 0),
+ DEFINE_PROP_UINT32("shift", XiveSource, esb_shift, XIVE_ESB_64K_2PAGE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xive_source_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "XIVE Interrupt Source";
+ dc->props = xive_source_properties;
+ dc->realize = xive_source_realize;
+ dc->vmsd = &vmstate_xive_source;
+}
+
+static const TypeInfo xive_source_info = {
+ .name = TYPE_XIVE_SOURCE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(XiveSource),
+ .class_init = xive_source_class_init,
+};
+
+/*
+ * XiveEND helpers
+ */
+
+void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
+ uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qentries = 1 << (qsize + 10);
+ int i;
+
+ /*
+ * print out the [ (qindex - (width - 1)) .. (qindex + 1)] window
+ */
+ monitor_printf(mon, " [ ");
+ qindex = (qindex - (width - 1)) & (qentries - 1);
+ for (i = 0; i < width; i++) {
+ uint64_t qaddr = qaddr_base + (qindex << 2);
+ uint32_t qdata = -1;
+
+ if (dma_memory_read(&address_space_memory, qaddr, &qdata,
+ sizeof(qdata))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to read EQ @0x%"
+ HWADDR_PRIx "\n", qaddr);
+ return;
+ }
+ monitor_printf(mon, "%s%08x ", i == width - 1 ? "^" : "",
+ be32_to_cpu(qdata));
+ qindex = (qindex + 1) & (qentries - 1);
+ }
+}
+
+void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
+ uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
+ uint32_t qentries = 1 << (qsize + 10);
+
+ uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6);
+ uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
+
+ if (!xive_end_is_valid(end)) {
+ return;
+ }
+
+ monitor_printf(mon, " %08x %c%c%c%c%c prio:%d nvt:%04x eq:@%08"PRIx64
+ "% 6d/%5d ^%d", end_idx,
+ xive_end_is_valid(end) ? 'v' : '-',
+ xive_end_is_enqueue(end) ? 'q' : '-',
+ xive_end_is_notify(end) ? 'n' : '-',
+ xive_end_is_backlog(end) ? 'b' : '-',
+ xive_end_is_escalate(end) ? 'e' : '-',
+ priority, nvt, qaddr_base, qindex, qentries, qgen);
+
+ xive_end_queue_pic_print_info(end, 6, mon);
+ monitor_printf(mon, "]\n");
+}
+
+static void xive_end_enqueue(XiveEND *end, uint32_t data)
+{
+ uint64_t qaddr_base = (uint64_t) be32_to_cpu(end->w2 & 0x0fffffff) << 32
+ | be32_to_cpu(end->w3);
+ uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
+ uint32_t qindex = xive_get_field32(END_W1_PAGE_OFF, end->w1);
+ uint32_t qgen = xive_get_field32(END_W1_GENERATION, end->w1);
+
+ uint64_t qaddr = qaddr_base + (qindex << 2);
+ uint32_t qdata = cpu_to_be32((qgen << 31) | (data & 0x7fffffff));
+ uint32_t qentries = 1 << (qsize + 10);
+
+ if (dma_memory_write(&address_space_memory, qaddr, &qdata, sizeof(qdata))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: failed to write END data @0x%"
+ HWADDR_PRIx "\n", qaddr);
+ return;
+ }
+
+ qindex = (qindex + 1) & (qentries - 1);
+ if (qindex == 0) {
+ qgen ^= 1;
+ end->w1 = xive_set_field32(END_W1_GENERATION, end->w1, qgen);
+ }
+ end->w1 = xive_set_field32(END_W1_PAGE_OFF, end->w1, qindex);
+}
+
+/*
+ * XIVE Router (aka. Virtualization Controller or IVRE)
+ */
+
+int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
+ XiveEAS *eas)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->get_eas(xrtr, eas_blk, eas_idx, eas);
+}
+
+int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->get_end(xrtr, end_blk, end_idx, end);
+}
+
+int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->write_end(xrtr, end_blk, end_idx, end, word_number);
+}
+
+int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->get_nvt(xrtr, nvt_blk, nvt_idx, nvt);
+}
+
+int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt, uint8_t word_number)
+{
+ XiveRouterClass *xrc = XIVE_ROUTER_GET_CLASS(xrtr);
+
+ return xrc->write_nvt(xrtr, nvt_blk, nvt_idx, nvt, word_number);
+}
+
+/*
+ * The thread context register words are in big-endian format.
+ */
+static int xive_presenter_tctx_match(XiveTCTX *tctx, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint32_t logic_serv)
+{
+ uint32_t cam = xive_nvt_cam_line(nvt_blk, nvt_idx);
+ uint32_t qw2w2 = xive_tctx_word2(&tctx->regs[TM_QW2_HV_POOL]);
+ uint32_t qw1w2 = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
+ uint32_t qw0w2 = xive_tctx_word2(&tctx->regs[TM_QW0_USER]);
+
+ /*
+ * TODO (PowerNV): ignore mode. The low order bits of the NVT
+ * identifier are ignored in the "CAM" match.
+ */
+
+ if (format == 0) {
+ if (cam_ignore == true) {
+ /*
+ * F=0 & i=1: Logical server notification (bits ignored at
+ * the end of the NVT identifier)
+ */
+ qemu_log_mask(LOG_UNIMP, "XIVE: no support for LS NVT %x/%x\n",
+ nvt_blk, nvt_idx);
+ return -1;
+ }
+
+ /* F=0 & i=0: Specific NVT notification */
+
+ /* TODO (PowerNV) : PHYS ring */
+
+ /* HV POOL ring */
+ if ((be32_to_cpu(qw2w2) & TM_QW2W2_VP) &&
+ cam == xive_get_field32(TM_QW2W2_POOL_CAM, qw2w2)) {
+ return TM_QW2_HV_POOL;
+ }
+
+ /* OS ring */
+ if ((be32_to_cpu(qw1w2) & TM_QW1W2_VO) &&
+ cam == xive_get_field32(TM_QW1W2_OS_CAM, qw1w2)) {
+ return TM_QW1_OS;
+ }
+ } else {
+ /* F=1 : User level Event-Based Branch (EBB) notification */
+
+ /* USER ring */
+ if ((be32_to_cpu(qw1w2) & TM_QW1W2_VO) &&
+ (cam == xive_get_field32(TM_QW1W2_OS_CAM, qw1w2)) &&
+ (be32_to_cpu(qw0w2) & TM_QW0W2_VU) &&
+ (logic_serv == xive_get_field32(TM_QW0W2_LOGIC_SERV, qw0w2))) {
+ return TM_QW0_USER;
+ }
+ }
+ return -1;
+}
+
+typedef struct XiveTCTXMatch {
+ XiveTCTX *tctx;
+ uint8_t ring;
+} XiveTCTXMatch;
+
+static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv, XiveTCTXMatch *match)
+{
+ CPUState *cs;
+
+ /*
+ * TODO (PowerNV): handle chip_id overwrite of block field for
+ * hardwired CAM compares
+ */
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ XiveTCTX *tctx = cpu->tctx;
+ int ring;
+
+ /*
+ * HW checks that the CPU is enabled in the Physical Thread
+ * Enable Register (PTER).
+ */
+
+ /*
+ * Check the thread context CAM lines and record matches. We
+ * will handle CPU exception delivery later
+ */
+ ring = xive_presenter_tctx_match(tctx, format, nvt_blk, nvt_idx,
+ cam_ignore, logic_serv);
+ /*
+ * Save the context and follow on to catch duplicates, that we
+ * don't support yet.
+ */
+ if (ring != -1) {
+ if (match->tctx) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: already found a thread "
+ "context NVT %x/%x\n", nvt_blk, nvt_idx);
+ return false;
+ }
+
+ match->ring = ring;
+ match->tctx = tctx;
+ }
+ }
+
+ if (!match->tctx) {
+ qemu_log_mask(LOG_UNIMP, "XIVE: NVT %x/%x is not dispatched\n",
+ nvt_blk, nvt_idx);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * This is our simple Xive Presenter Engine model. It is merged in the
+ * Router as it does not require an extra object.
+ *
+ * It receives notification requests sent by the IVRE to find one
+ * matching NVT (or more) dispatched on the processor threads. In case
+ * of a single NVT notification, the process is abreviated and the
+ * thread is signaled if a match is found. In case of a logical server
+ * notification (bits ignored at the end of the NVT identifier), the
+ * IVPE and IVRE select a winning thread using different filters. This
+ * involves 2 or 3 exchanges on the PowerBus that the model does not
+ * support.
+ *
+ * The parameters represent what is sent on the PowerBus
+ */
+static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
+ uint8_t nvt_blk, uint32_t nvt_idx,
+ bool cam_ignore, uint8_t priority,
+ uint32_t logic_serv)
+{
+ XiveNVT nvt;
+ XiveTCTXMatch match = { .tctx = NULL, .ring = 0 };
+ bool found;
+
+ /* NVT cache lookup */
+ if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ if (!xive_nvt_is_valid(&nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ found = xive_presenter_match(xrtr, format, nvt_blk, nvt_idx, cam_ignore,
+ priority, logic_serv, &match);
+ if (found) {
+ ipb_update(&match.tctx->regs[match.ring], priority);
+ xive_tctx_notify(match.tctx, match.ring);
+ return;
+ }
+
+ /* Record the IPB in the associated NVT structure */
+ ipb_update((uint8_t *) &nvt.w4, priority);
+ xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+
+ /*
+ * If no matching NVT is dispatched on a HW thread :
+ * - update the NVT structure if backlog is activated
+ * - escalate (ESe PQ bits and EAS in w4-5) if escalation is
+ * activated
+ */
+}
+
+/*
+ * An END trigger can come from an event trigger (IPI or HW) or from
+ * another chip. We don't model the PowerBus but the END trigger
+ * message has the same parameters than in the function below.
+ */
+static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
+ uint32_t end_idx, uint32_t end_data)
+{
+ XiveEND end;
+ uint8_t priority;
+ uint8_t format;
+
+ /* END cache lookup */
+ if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
+ end_idx);
+ return;
+ }
+
+ if (!xive_end_is_valid(&end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: END %x/%x is invalid\n",
+ end_blk, end_idx);
+ return;
+ }
+
+ if (xive_end_is_enqueue(&end)) {
+ xive_end_enqueue(&end, end_data);
+ /* Enqueuing event data modifies the EQ toggle and index */
+ xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
+ }
+
+ /*
+ * The W7 format depends on the F bit in W6. It defines the type
+ * of the notification :
+ *
+ * F=0 : single or multiple NVT notification
+ * F=1 : User level Event-Based Branch (EBB) notification, no
+ * priority
+ */
+ format = xive_get_field32(END_W6_FORMAT_BIT, end.w6);
+ priority = xive_get_field32(END_W7_F0_PRIORITY, end.w7);
+
+ /* The END is masked */
+ if (format == 0 && priority == 0xff) {
+ return;
+ }
+
+ /*
+ * Check the END ESn (Event State Buffer for notification) for
+ * even futher coalescing in the Router
+ */
+ if (!xive_end_is_notify(&end)) {
+ uint8_t pq = xive_get_field32(END_W1_ESn, end.w1);
+ bool notify = xive_esb_trigger(&pq);
+
+ if (pq != xive_get_field32(END_W1_ESn, end.w1)) {
+ end.w1 = xive_set_field32(END_W1_ESn, end.w1, pq);
+ xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
+ }
+
+ /* ESn[Q]=1 : end of notification */
+ if (!notify) {
+ return;
+ }
+ }
+
+ /*
+ * Follows IVPE notification
+ */
+ xive_presenter_notify(xrtr, format,
+ xive_get_field32(END_W6_NVT_BLOCK, end.w6),
+ xive_get_field32(END_W6_NVT_INDEX, end.w6),
+ xive_get_field32(END_W7_F0_IGNORE, end.w7),
+ priority,
+ xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
+
+ /* TODO: Auto EOI. */
+}
+
+static void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
+{
+ XiveRouter *xrtr = XIVE_ROUTER(xn);
+ uint8_t eas_blk = XIVE_SRCNO_BLOCK(lisn);
+ uint32_t eas_idx = XIVE_SRCNO_INDEX(lisn);
+ XiveEAS eas;
+
+ /* EAS cache lookup */
+ if (xive_router_get_eas(xrtr, eas_blk, eas_idx, &eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: Unknown LISN %x\n", lisn);
+ return;
+ }
+
+ /*
+ * The IVRE checks the State Bit Cache at this point. We skip the
+ * SBC lookup because the state bits of the sources are modeled
+ * internally in QEMU.
+ */
+
+ if (!xive_eas_is_valid(&eas)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid LISN %x\n", lisn);
+ return;
+ }
+
+ if (xive_eas_is_masked(&eas)) {
+ /* Notification completed */
+ return;
+ }
+
+ /*
+ * The event trigger becomes an END trigger
+ */
+ xive_router_end_notify(xrtr,
+ xive_get_field64(EAS_END_BLOCK, eas.w),
+ xive_get_field64(EAS_END_INDEX, eas.w),
+ xive_get_field64(EAS_END_DATA, eas.w));
+}
+
+static void xive_router_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass);
+
+ dc->desc = "XIVE Router Engine";
+ xnc->notify = xive_router_notify;
+}
+
+static const TypeInfo xive_router_info = {
+ .name = TYPE_XIVE_ROUTER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .abstract = true,
+ .class_size = sizeof(XiveRouterClass),
+ .class_init = xive_router_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_XIVE_NOTIFIER },
+ { }
+ }
+};
+
+void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon)
+{
+ if (!xive_eas_is_valid(eas)) {
+ return;
+ }
+
+ monitor_printf(mon, " %08x %s end:%02x/%04x data:%08x\n",
+ lisn, xive_eas_is_masked(eas) ? "M" : " ",
+ (uint8_t) xive_get_field64(EAS_END_BLOCK, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_INDEX, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_DATA, eas->w));
+}
+
+/*
+ * END ESB MMIO loads
+ */
+static uint64_t xive_end_source_read(void *opaque, hwaddr addr, unsigned size)
+{
+ XiveENDSource *xsrc = XIVE_END_SOURCE(opaque);
+ uint32_t offset = addr & 0xFFF;
+ uint8_t end_blk;
+ uint32_t end_idx;
+ XiveEND end;
+ uint32_t end_esmask;
+ uint8_t pq;
+ uint64_t ret = -1;
+
+ end_blk = xsrc->block_id;
+ end_idx = addr >> (xsrc->esb_shift + 1);
+
+ if (xive_router_get_end(xsrc->xrtr, end_blk, end_idx, &end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No END %x/%x\n", end_blk,
+ end_idx);
+ return -1;
+ }
+
+ if (!xive_end_is_valid(&end)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: END %x/%x is invalid\n",
+ end_blk, end_idx);
+ return -1;
+ }
+
+ end_esmask = addr_is_even(addr, xsrc->esb_shift) ? END_W1_ESn : END_W1_ESe;
+ pq = xive_get_field32(end_esmask, end.w1);
+
+ switch (offset) {
+ case XIVE_ESB_LOAD_EOI ... XIVE_ESB_LOAD_EOI + 0x7FF:
+ ret = xive_esb_eoi(&pq);
+
+ /* Forward the source event notification for routing ?? */
+ break;
+
+ case XIVE_ESB_GET ... XIVE_ESB_GET + 0x3FF:
+ ret = pq;
+ break;
+
+ case XIVE_ESB_SET_PQ_00 ... XIVE_ESB_SET_PQ_00 + 0x0FF:
+ case XIVE_ESB_SET_PQ_01 ... XIVE_ESB_SET_PQ_01 + 0x0FF:
+ case XIVE_ESB_SET_PQ_10 ... XIVE_ESB_SET_PQ_10 + 0x0FF:
+ case XIVE_ESB_SET_PQ_11 ... XIVE_ESB_SET_PQ_11 + 0x0FF:
+ ret = xive_esb_set(&pq, (offset >> 8) & 0x3);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid END ESB load addr %d\n",
+ offset);
+ return -1;
+ }
+
+ if (pq != xive_get_field32(end_esmask, end.w1)) {
+ end.w1 = xive_set_field32(end_esmask, end.w1, pq);
+ xive_router_write_end(xsrc->xrtr, end_blk, end_idx, &end, 1);
+ }
+
+ return ret;
+}
+
+/*
+ * END ESB MMIO stores are invalid
+ */
+static void xive_end_source_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr 0x%"
+ HWADDR_PRIx"\n", addr);
+}
+
+static const MemoryRegionOps xive_end_source_ops = {
+ .read = xive_end_source_read,
+ .write = xive_end_source_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 8,
+ .max_access_size = 8,
+ },
+};
+
+static void xive_end_source_realize(DeviceState *dev, Error **errp)
+{
+ XiveENDSource *xsrc = XIVE_END_SOURCE(dev);
+ Object *obj;
+ Error *local_err = NULL;
+
+ obj = object_property_get_link(OBJECT(dev), "xive", &local_err);
+ if (!obj) {
+ error_propagate(errp, local_err);
+ error_prepend(errp, "required link 'xive' not found: ");
+ return;
+ }
+
+ xsrc->xrtr = XIVE_ROUTER(obj);
+
+ if (!xsrc->nr_ends) {
+ error_setg(errp, "Number of interrupt needs to be greater than 0");
+ return;
+ }
+
+ if (xsrc->esb_shift != XIVE_ESB_4K &&
+ xsrc->esb_shift != XIVE_ESB_64K) {
+ error_setg(errp, "Invalid ESB shift setting");
+ return;
+ }
+
+ /*
+ * Each END is assigned an even/odd pair of MMIO pages, the even page
+ * manages the ESn field while the odd page manages the ESe field.
+ */
+ memory_region_init_io(&xsrc->esb_mmio, OBJECT(xsrc),
+ &xive_end_source_ops, xsrc, "xive.end",
+ (1ull << (xsrc->esb_shift + 1)) * xsrc->nr_ends);
+}
+
+static Property xive_end_source_properties[] = {
+ DEFINE_PROP_UINT8("block-id", XiveENDSource, block_id, 0),
+ DEFINE_PROP_UINT32("nr-ends", XiveENDSource, nr_ends, 0),
+ DEFINE_PROP_UINT32("shift", XiveENDSource, esb_shift, XIVE_ESB_64K),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xive_end_source_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "XIVE END Source";
+ dc->props = xive_end_source_properties;
+ dc->realize = xive_end_source_realize;
+}
+
+static const TypeInfo xive_end_source_info = {
+ .name = TYPE_XIVE_END_SOURCE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(XiveENDSource),
+ .class_init = xive_end_source_class_init,
+};
+
+/*
+ * XIVE Fabric
+ */
+static const TypeInfo xive_fabric_info = {
+ .name = TYPE_XIVE_NOTIFIER,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(XiveNotifierClass),
+};
+
+static void xive_register_types(void)
+{
+ type_register_static(&xive_source_info);
+ type_register_static(&xive_fabric_info);
+ type_register_static(&xive_router_info);
+ type_register_static(&xive_end_source_info);
+ type_register_static(&xive_tctx_info);
+}
+
+type_init(xive_register_types)
diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c
index 7de1ccd497..5f2c408036 100644
--- a/hw/mem/memory-device.c
+++ b/hw/mem/memory-device.c
@@ -85,7 +85,8 @@ static void memory_device_check_addable(MachineState *ms, uint64_t size,
/* will we exceed the total amount of memory specified */
memory_device_used_region_size(OBJECT(ms), &used_region_size);
- if (used_region_size + size > ms->maxram_size - ms->ram_size) {
+ if (used_region_size + size < used_region_size ||
+ used_region_size + size > ms->maxram_size - ms->ram_size) {
error_setg(errp, "not enough space, currently 0x%" PRIx64
" in use of total space for memory devices 0x" RAM_ADDR_FMT,
used_region_size, ms->maxram_size - ms->ram_size);
@@ -99,9 +100,8 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
uint64_t align, uint64_t size,
Error **errp)
{
- uint64_t address_space_start, address_space_end;
GSList *list = NULL, *item;
- uint64_t new_addr = 0;
+ Range as, new = range_empty;
if (!ms->device_memory) {
error_setg(errp, "memory devices (e.g. for memory hotplug) are not "
@@ -114,13 +114,11 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
"enabled, please specify the maxmem option");
return 0;
}
- address_space_start = ms->device_memory->base;
- address_space_end = address_space_start +
- memory_region_size(&ms->device_memory->mr);
- g_assert(address_space_end >= address_space_start);
+ range_init_nofail(&as, ms->device_memory->base,
+ memory_region_size(&ms->device_memory->mr));
- /* address_space_start indicates the maximum alignment we expect */
- if (QEMU_ALIGN_UP(address_space_start, align) != address_space_start) {
+ /* start of address space indicates the maximum alignment we expect */
+ if (!QEMU_IS_ALIGNED(range_lob(&as), align)) {
error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported",
align);
return 0;
@@ -131,33 +129,31 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
return 0;
}
- if (hint && QEMU_ALIGN_UP(*hint, align) != *hint) {
+ if (hint && !QEMU_IS_ALIGNED(*hint, align)) {
error_setg(errp, "address must be aligned to 0x%" PRIx64 " bytes",
align);
return 0;
}
- if (QEMU_ALIGN_UP(size, align) != size) {
+ if (!QEMU_IS_ALIGNED(size, align)) {
error_setg(errp, "backend memory size must be multiple of 0x%"
PRIx64, align);
return 0;
}
if (hint) {
- new_addr = *hint;
- if (new_addr < address_space_start) {
+ if (range_init(&new, *hint, size) || !range_contains_range(&as, &new)) {
error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64
- "] before 0x%" PRIx64, new_addr, size,
- address_space_start);
- return 0;
- } else if ((new_addr + size) > address_space_end) {
- error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64
- "] beyond 0x%" PRIx64, new_addr, size,
- address_space_end);
+ "], usable range for memory devices [0x%" PRIx64 ":0x%"
+ PRIx64 "]", *hint, size, range_lob(&as),
+ range_size(&as));
return 0;
}
} else {
- new_addr = address_space_start;
+ if (range_init(&new, range_lob(&as), size)) {
+ error_setg(errp, "can't add memory device, device too big");
+ return 0;
+ }
}
/* find address range that will fit new memory device */
@@ -165,30 +161,36 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
for (item = list; item; item = g_slist_next(item)) {
const MemoryDeviceState *md = item->data;
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(OBJECT(md));
- uint64_t md_size, md_addr;
+ uint64_t next_addr;
+ Range tmp;
- md_addr = mdc->get_addr(md);
- md_size = memory_device_get_region_size(md, &error_abort);
+ range_init_nofail(&tmp, mdc->get_addr(md),
+ memory_device_get_region_size(md, &error_abort));
- if (ranges_overlap(md_addr, md_size, new_addr, size)) {
+ if (range_overlaps_range(&tmp, &new)) {
if (hint) {
const DeviceState *d = DEVICE(md);
error_setg(errp, "address range conflicts with memory device"
" id='%s'", d->id ? d->id : "(unnamed)");
goto out;
}
- new_addr = QEMU_ALIGN_UP(md_addr + md_size, align);
+
+ next_addr = QEMU_ALIGN_UP(range_upb(&tmp) + 1, align);
+ if (!next_addr || range_init(&new, next_addr, range_size(&new))) {
+ range_make_empty(&new);
+ break;
+ }
}
}
- if (new_addr + size > address_space_end) {
+ if (!range_contains_range(&as, &new)) {
error_setg(errp, "could not find position in guest address space for "
"memory device - memory fragmented due to alignments");
goto out;
}
out:
g_slist_free(list);
- return new_addr;
+ return range_lob(&new);
}
MemoryDeviceInfoList *qmp_memory_device_list(void)
diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c
index 35bfeda7aa..489ab839b7 100644
--- a/hw/microblaze/boot.c
+++ b/hw/microblaze/boot.c
@@ -156,7 +156,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
/* If it wasn't an ELF image, try an u-boot image. */
if (kernel_size < 0) {
- hwaddr uentry, loadaddr;
+ hwaddr uentry, loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
NULL, NULL);
diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c
index 5cf7b84c79..b9f0b0d06e 100644
--- a/hw/microblaze/petalogix_s3adsp1800_mmu.c
+++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c
@@ -35,6 +35,7 @@
#include "sysemu/sysemu.h"
#include "hw/devices.h"
#include "hw/boards.h"
+#include "hw/misc/unimp.h"
#include "exec/address-spaces.h"
#include "hw/char/xilinx_uartlite.h"
@@ -47,6 +48,7 @@
#define MEMORY_BASEADDR 0x90000000
#define FLASH_BASEADDR 0xa0000000
+#define GPIO_BASEADDR 0x81400000
#define INTC_BASEADDR 0x81800000
#define TIMER_BASEADDR 0x83c00000
#define UARTLITE_BASEADDR 0x84000000
@@ -122,6 +124,8 @@ petalogix_s3adsp1800_init(MachineState *machine)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]);
+ create_unimplemented_device("gpio", GPIO_BASEADDR, 0x10000);
+
microblaze_load_kernel(cpu, ddr_base, ram_size,
machine->initrd_filename,
BINARY_DEVICE_TREE_FILE,
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 4285d1964e..fc97f59af4 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -69,6 +69,7 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
Error *err = NULL;
target_ulong gcr_base;
bool itu_present = false;
+ bool saar_present = false;
for (i = 0; i < s->num_vp; i++) {
cpu = MIPS_CPU(cpu_create(s->cpu_type));
@@ -82,12 +83,14 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
itu_present = true;
/* Attach ITC Tag to the VP */
env->itc_tag = mips_itu_get_tag_region(&s->itu);
+ env->itu = &s->itu;
}
qemu_register_reset(main_cpu_reset, cpu);
}
cpu = MIPS_CPU(first_cpu);
env = &cpu->env;
+ saar_present = (bool)env->saarp;
/* Inter-Thread Communication Unit */
if (itu_present) {
@@ -96,6 +99,11 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
object_property_set_int(OBJECT(&s->itu), 16, "num-fifo", &err);
object_property_set_int(OBJECT(&s->itu), 16, "num-semaphores", &err);
+ object_property_set_bool(OBJECT(&s->itu), saar_present, "saar-present",
+ &err);
+ if (saar_present) {
+ qdev_prop_set_ptr(DEVICE(&s->itu), "saar", (void *)&env->CP0_SAAR);
+ }
object_property_set_bool(OBJECT(&s->itu), true, "realized", &err);
if (err != NULL) {
error_propagate(errp, err);
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
index 1cd8aac658..f707e59c7a 100644
--- a/hw/mips/gt64xxx_pci.c
+++ b/hw/mips/gt64xxx_pci.c
@@ -395,7 +395,7 @@ static void gt64120_writel (void *opaque, hwaddr addr,
s->regs[GT_CPU] = val;
break;
case GT_MULTI:
- /* Read-only register as only one GT64xxx is present on the CPU bus */
+ /* Read-only register as only one GT64xxx is present on the CPU bus */
break;
/* CPU Address Decode */
@@ -457,13 +457,13 @@ static void gt64120_writel (void *opaque, hwaddr addr,
case GT_CPUERR_DATALO:
case GT_CPUERR_DATAHI:
case GT_CPUERR_PARITY:
- /* Read-only registers, do nothing */
+ /* Read-only registers, do nothing */
break;
/* CPU Sync Barrier */
case GT_PCI0SYNC:
case GT_PCI1SYNC:
- /* Read-only registers, do nothing */
+ /* Read-only registers, do nothing */
break;
/* SDRAM and Device Address Decode */
diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c
index 3e852e98cf..1922407394 100644
--- a/hw/mips/mips_r4k.c
+++ b/hw/mips/mips_r4k.c
@@ -239,7 +239,7 @@ void mips_r4k_init(MachineState *machine)
sector_len, mips_rom / sector_len,
4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
- }
+ }
} else if (!qtest_enabled()) {
/* not fatal */
warn_report("could not load MIPS bios '%s'", bios_name);
@@ -285,7 +285,7 @@ void mips_r4k_init(MachineState *machine)
for(i = 0; i < MAX_IDE_BUS; i++)
isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[MAX_IDE_DEVS * i],
- hd[MAX_IDE_DEVS * i + 1]);
+ hd[MAX_IDE_DEVS * i + 1]);
isa_create_simple(isa_bus, TYPE_I8042);
}
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 680350b3c3..04f3bfa516 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -74,3 +74,4 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_AUX) += auxbus.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
obj-$(CONFIG_MSF2) += msf2-sysreg.o
+obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
diff --git a/hw/misc/edu.c b/hw/misc/edu.c
index cdcf550dd7..ceaf688bfb 100644
--- a/hw/misc/edu.c
+++ b/hw/misc/edu.c
@@ -377,6 +377,7 @@ static void pci_edu_uninit(PCIDevice *pdev)
qemu_mutex_destroy(&edu->thr_mutex);
timer_del(&edu->dma_timer);
+ msi_uninit(pdev);
}
static void edu_obj_uint64(Object *obj, Visitor *v, const char *name,
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index ecfd10a29a..c7b6bbc974 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -112,13 +112,6 @@ typedef struct IVShmemState {
/* migration stuff */
OnOffAuto master;
Error *migration_blocker;
-
- /* legacy cruft */
- char *role;
- char *shmobj;
- char *sizearg;
- size_t legacy_size;
- uint32_t not_legacy_32bit;
} IVShmemState;
/* registers for the Inter-VM shared memory device */
@@ -529,17 +522,6 @@ static void process_msg_shmem(IVShmemState *s, int fd, Error **errp)
size = buf.st_size;
- /* Legacy cruft */
- if (s->legacy_size != SIZE_MAX) {
- if (size < s->legacy_size) {
- error_setg(errp, "server sent only %zd bytes of shared memory",
- (size_t)buf.st_size);
- close(fd);
- return;
- }
- size = s->legacy_size;
- }
-
/* mmap the region and map into the BAR2 */
memory_region_init_ram_from_fd(&s->server_bar2, OBJECT(s),
"ivshmem.bar2", size, true, fd, &local_err);
@@ -882,8 +864,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
IVShmemState *s = IVSHMEM_COMMON(dev);
Error *err = NULL;
uint8_t *pci_conf;
- uint8_t attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH;
Error *local_err = NULL;
/* IRQFD requires MSI */
@@ -903,10 +883,6 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio);
- if (s->not_legacy_32bit) {
- attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- }
-
if (s->hostmem != NULL) {
IVSHMEM_DPRINTF("using hostmem\n");
@@ -964,7 +940,11 @@ static void ivshmem_common_realize(PCIDevice *dev, Error **errp)
}
vmstate_register_ram(s->ivshmem_bar2, DEVICE(s));
- pci_register_bar(PCI_DEVICE(s), 2, attr, s->ivshmem_bar2);
+ pci_register_bar(PCI_DEVICE(s), 2,
+ PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH |
+ PCI_BASE_ADDRESS_MEM_TYPE_64,
+ s->ivshmem_bar2);
}
static void ivshmem_exit(PCIDevice *dev)
@@ -1084,13 +1064,6 @@ static Property ivshmem_plain_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static void ivshmem_plain_init(Object *obj)
-{
- IVShmemState *s = IVSHMEM_PLAIN(obj);
-
- s->not_legacy_32bit = 1;
-}
-
static void ivshmem_plain_realize(PCIDevice *dev, Error **errp)
{
IVShmemState *s = IVSHMEM_COMMON(dev);
@@ -1122,7 +1095,6 @@ static const TypeInfo ivshmem_plain_info = {
.name = TYPE_IVSHMEM_PLAIN,
.parent = TYPE_IVSHMEM_COMMON,
.instance_size = sizeof(IVShmemState),
- .instance_init = ivshmem_plain_init,
.class_init = ivshmem_plain_class_init,
};
@@ -1155,8 +1127,6 @@ static void ivshmem_doorbell_init(Object *obj)
IVShmemState *s = IVSHMEM_DOORBELL(obj);
s->features |= (1 << IVSHMEM_MSI);
- s->legacy_size = SIZE_MAX; /* whatever the server sends */
- s->not_legacy_32bit = 1;
}
static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp)
@@ -1189,181 +1159,11 @@ static const TypeInfo ivshmem_doorbell_info = {
.class_init = ivshmem_doorbell_class_init,
};
-static int ivshmem_load_old(QEMUFile *f, void *opaque, int version_id)
-{
- IVShmemState *s = opaque;
- PCIDevice *pdev = PCI_DEVICE(s);
- int ret;
-
- IVSHMEM_DPRINTF("ivshmem_load_old\n");
-
- if (version_id != 0) {
- return -EINVAL;
- }
-
- ret = ivshmem_pre_load(s);
- if (ret) {
- return ret;
- }
-
- ret = pci_device_load(pdev, f);
- if (ret) {
- return ret;
- }
-
- if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
- msix_load(pdev, f);
- ivshmem_msix_vector_use(s);
- } else {
- s->intrstatus = qemu_get_be32(f);
- s->intrmask = qemu_get_be32(f);
- }
-
- return 0;
-}
-
-static bool test_msix(void *opaque, int version_id)
-{
- IVShmemState *s = opaque;
-
- return ivshmem_has_feature(s, IVSHMEM_MSI);
-}
-
-static bool test_no_msix(void *opaque, int version_id)
-{
- return !test_msix(opaque, version_id);
-}
-
-static const VMStateDescription ivshmem_vmsd = {
- .name = "ivshmem",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_load = ivshmem_pre_load,
- .post_load = ivshmem_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(parent_obj, IVShmemState),
-
- VMSTATE_MSIX_TEST(parent_obj, IVShmemState, test_msix),
- VMSTATE_UINT32_TEST(intrstatus, IVShmemState, test_no_msix),
- VMSTATE_UINT32_TEST(intrmask, IVShmemState, test_no_msix),
-
- VMSTATE_END_OF_LIST()
- },
- .load_state_old = ivshmem_load_old,
- .minimum_version_id_old = 0
-};
-
-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_UINT32("use64", IVShmemState, not_legacy_32bit, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void desugar_shm(IVShmemState *s)
-{
- Object *obj;
- char *path;
-
- obj = object_new("memory-backend-file");
- path = g_strdup_printf("/dev/shm/%s", s->shmobj);
- object_property_set_str(obj, path, "mem-path", &error_abort);
- g_free(path);
- object_property_set_int(obj, s->legacy_size, "size", &error_abort);
- object_property_set_bool(obj, true, "share", &error_abort);
- object_property_add_child(OBJECT(s), "internal-shm-backend", obj,
- &error_abort);
- object_unref(obj);
- user_creatable_complete(obj, &error_abort);
- s->hostmem = MEMORY_BACKEND(obj);
-}
-
-static void ivshmem_realize(PCIDevice *dev, Error **errp)
-{
- IVShmemState *s = IVSHMEM_COMMON(dev);
-
- if (!qtest_enabled()) {
- warn_report("ivshmem is deprecated, please use ivshmem-plain"
- " or ivshmem-doorbell instead");
- }
-
- if (qemu_chr_fe_backend_connected(&s->server_chr) + !!s->shmobj != 1) {
- error_setg(errp, "You must specify either 'shm' or 'chardev'");
- return;
- }
-
- if (s->sizearg == NULL) {
- s->legacy_size = 4 * MiB; /* 4 MB default */
- } else {
- int ret;
- uint64_t size;
-
- ret = qemu_strtosz_MiB(s->sizearg, NULL, &size);
- if (ret < 0 || (size_t)size != size || !is_power_of_2(size)) {
- error_setg(errp, "Invalid size %s", s->sizearg);
- return;
- }
- s->legacy_size = size;
- }
-
- /* check that role is reasonable */
- if (s->role) {
- if (strncmp(s->role, "peer", 5) == 0) {
- s->master = ON_OFF_AUTO_OFF;
- } else if (strncmp(s->role, "master", 7) == 0) {
- s->master = ON_OFF_AUTO_ON;
- } else {
- error_setg(errp, "'role' must be 'peer' or 'master'");
- return;
- }
- } else {
- s->master = ON_OFF_AUTO_AUTO;
- }
-
- if (s->shmobj) {
- desugar_shm(s);
- }
-
- /*
- * Note: we don't use INTx with IVSHMEM_MSI at all, so this is a
- * bald-faced lie then. But it's a backwards compatible lie.
- */
- pci_config_set_interrupt_pin(dev->config, 1);
-
- ivshmem_common_realize(dev, errp);
-}
-
-static void ivshmem_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = ivshmem_realize;
- k->revision = 0;
- dc->desc = "Inter-VM shared memory (legacy)";
- dc->props = ivshmem_properties;
- dc->vmsd = &ivshmem_vmsd;
-}
-
-static const TypeInfo ivshmem_info = {
- .name = TYPE_IVSHMEM,
- .parent = TYPE_IVSHMEM_COMMON,
- .instance_size = sizeof(IVShmemState),
- .class_init = ivshmem_class_init,
-};
-
static void ivshmem_register_types(void)
{
type_register_static(&ivshmem_common_info);
type_register_static(&ivshmem_plain_info);
type_register_static(&ivshmem_doorbell_info);
- type_register_static(&ivshmem_info);
}
type_init(ivshmem_register_types)
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index 87ae246d37..e5917d8f2e 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -38,7 +38,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/isa/isa.h"
#include "hw/ppc/mac_dbdma.h"
#include "qemu/main-loop.h"
#include "qemu/log.h"
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index 6dbdc03677..ac6d35a81d 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -43,9 +43,9 @@ typedef struct {
#define CB_START (1 << 7)
#define CHANNEL_NUM(v, b0, b1, b2) \
- ((((v) >> (2 + (b0))) & 4) | \
- (((v) >> (3 + (b1))) & 2) | \
- (((v) >> (4 + (b2))) & 1))
+ ((((v) >> (2 + (b0))) & 4) | \
+ (((v) >> (3 + (b1))) & 2) | \
+ (((v) >> (4 + (b2))) & 1))
static uint32_t max111x_read(MAX111xState *s)
{
diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c
index e6140eec6b..44dc0698ec 100644
--- a/hw/misc/milkymist-hpdmc.c
+++ b/hw/misc/milkymist-hpdmc.c
@@ -129,15 +129,13 @@ static void milkymist_hpdmc_reset(DeviceState *d)
| IODELAY_PLL2_LOCKED;
}
-static int milkymist_hpdmc_init(SysBusDevice *dev)
+static void milkymist_hpdmc_realize(DeviceState *dev, Error **errp)
{
MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev);
memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s,
"milkymist-hpdmc", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs_region);
}
static const VMStateDescription vmstate_milkymist_hpdmc = {
@@ -153,9 +151,8 @@ static const VMStateDescription vmstate_milkymist_hpdmc = {
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->realize = milkymist_hpdmc_realize;
dc->reset = milkymist_hpdmc_reset;
dc->vmsd = &vmstate_milkymist_hpdmc;
}
diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c
index 86f5e383b0..4a03c7ee63 100644
--- a/hw/misc/milkymist-pfpu.c
+++ b/hw/misc/milkymist-pfpu.c
@@ -497,17 +497,16 @@ static void milkymist_pfpu_reset(DeviceState *d)
}
}
-static int milkymist_pfpu_init(SysBusDevice *dev)
+static void milkymist_pfpu_realize(DeviceState *dev, Error **errp)
{
MilkymistPFPUState *s = MILKYMIST_PFPU(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->regs_region, OBJECT(dev), &pfpu_mmio_ops, s,
"milkymist-pfpu", MICROCODE_END * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- return 0;
+ sysbus_init_mmio(sbd, &s->regs_region);
}
static const VMStateDescription vmstate_milkymist_pfpu = {
@@ -527,9 +526,8 @@ static const VMStateDescription vmstate_milkymist_pfpu = {
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->realize = milkymist_pfpu_realize;
dc->reset = milkymist_pfpu_reset;
dc->vmsd = &vmstate_milkymist_pfpu;
}
diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c
index 43bbec46cf..1257d8fce6 100644
--- a/hw/misc/mips_itu.c
+++ b/hw/misc/mips_itu.c
@@ -55,9 +55,17 @@ typedef enum ITCView {
ITCVIEW_EF_SYNC = 2,
ITCVIEW_EF_TRY = 3,
ITCVIEW_PV_SYNC = 4,
- ITCVIEW_PV_TRY = 5
+ ITCVIEW_PV_TRY = 5,
+ ITCVIEW_PV_ICR0 = 15,
} ITCView;
+#define ITC_ICR0_CELL_NUM 16
+#define ITC_ICR0_BLK_GRAIN 8
+#define ITC_ICR0_BLK_GRAIN_MASK 0x7
+#define ITC_ICR0_ERR_AXI 2
+#define ITC_ICR0_ERR_PARITY 1
+#define ITC_ICR0_ERR_EXEC 0
+
MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu)
{
return &itu->tag_io;
@@ -76,7 +84,7 @@ static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size)
return tag->ITCAddressMap[index];
}
-static void itc_reconfigure(MIPSITUState *tag)
+void itc_reconfigure(MIPSITUState *tag)
{
uint64_t *am = &tag->ITCAddressMap[0];
MemoryRegion *mr = &tag->storage_io;
@@ -84,6 +92,12 @@ static void itc_reconfigure(MIPSITUState *tag)
uint64_t size = (1 * KiB) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
+ if (tag->saar_present) {
+ address = ((*(uint64_t *) tag->saar) & 0xFFFFFFFFE000ULL) << 4;
+ size = 1 << ((*(uint64_t *) tag->saar >> 1) & 0x1f);
+ is_enabled = *(uint64_t *) tag->saar & 1;
+ }
+
memory_region_transaction_begin();
if (!(size & (size - 1))) {
memory_region_set_size(mr, size);
@@ -142,7 +156,12 @@ static inline ITCView get_itc_view(hwaddr addr)
static inline int get_cell_stride_shift(const MIPSITUState *s)
{
/* Minimum interval (for EntryGain = 0) is 128 B */
- return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK);
+ if (s->saar_present) {
+ return 7 + ((s->icr0 >> ITC_ICR0_BLK_GRAIN) &
+ ITC_ICR0_BLK_GRAIN_MASK);
+ } else {
+ return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK);
+ }
}
static inline ITCStorageCell *get_cell(MIPSITUState *s,
@@ -356,6 +375,12 @@ static void view_pv_try_write(ITCStorageCell *c)
view_pv_common_write(c);
}
+static void raise_exception(int excp)
+{
+ current_cpu->exception_index = excp;
+ cpu_loop_exit(current_cpu);
+}
+
static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
{
MIPSITUState *s = (MIPSITUState *)opaque;
@@ -363,6 +388,14 @@ static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
ITCView view = get_itc_view(addr);
uint64_t ret = -1;
+ switch (size) {
+ case 1:
+ case 2:
+ s->icr0 |= 1 << ITC_ICR0_ERR_AXI;
+ raise_exception(EXCP_DBE);
+ return 0;
+ }
+
switch (view) {
case ITCVIEW_BYPASS:
ret = view_bypass_read(cell);
@@ -382,6 +415,9 @@ static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
case ITCVIEW_PV_TRY:
ret = view_pv_try_read(cell);
break;
+ case ITCVIEW_PV_ICR0:
+ ret = s->icr0;
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"itc_storage_read: Bad ITC View %d\n", (int)view);
@@ -398,6 +434,14 @@ static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
ITCStorageCell *cell = get_cell(s, addr);
ITCView view = get_itc_view(addr);
+ switch (size) {
+ case 1:
+ case 2:
+ s->icr0 |= 1 << ITC_ICR0_ERR_AXI;
+ raise_exception(EXCP_DBE);
+ return;
+ }
+
switch (view) {
case ITCVIEW_BYPASS:
view_bypass_write(cell, data);
@@ -417,6 +461,15 @@ static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
case ITCVIEW_PV_TRY:
view_pv_try_write(cell);
break;
+ case ITCVIEW_PV_ICR0:
+ if (data & 0x7) {
+ /* clear ERROR bits */
+ s->icr0 &= ~(data & 0x7);
+ }
+ /* set BLK_GRAIN */
+ s->icr0 &= ~0x700;
+ s->icr0 |= data & 0x700;
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"itc_storage_write: Bad ITC View %d\n", (int)view);
@@ -479,10 +532,15 @@ static void mips_itu_reset(DeviceState *dev)
{
MIPSITUState *s = MIPS_ITU(dev);
- s->ITCAddressMap[0] = 0;
- s->ITCAddressMap[1] =
- ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) |
- (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS);
+ if (s->saar_present) {
+ *(uint64_t *) s->saar = 0x11 << 1;
+ s->icr0 = get_num_cells(s) << ITC_ICR0_CELL_NUM;
+ } else {
+ s->ITCAddressMap[0] = 0;
+ s->ITCAddressMap[1] =
+ ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) |
+ (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS);
+ }
itc_reconfigure(s);
itc_reset_cells(s);
@@ -493,6 +551,7 @@ static Property mips_itu_properties[] = {
ITC_FIFO_NUM_MAX),
DEFINE_PROP_INT32("num-semaphores", MIPSITUState, num_semaphores,
ITC_SEMAPH_NUM_MAX),
+ DEFINE_PROP_BOOL("saar-present", MIPSITUState, saar_present, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c
new file mode 100644
index 0000000000..d188f044f4
--- /dev/null
+++ b/hw/misc/nrf51_rng.c
@@ -0,0 +1,262 @@
+/*
+ * nRF51 Random Number Generator
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/arm/nrf51.h"
+#include "hw/misc/nrf51_rng.h"
+#include "crypto/random.h"
+
+static void update_irq(NRF51RNGState *s)
+{
+ bool irq = s->interrupt_enabled && s->event_valrdy;
+ qemu_set_irq(s->irq, irq);
+}
+
+static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+ uint64_t r = 0;
+
+ switch (offset) {
+ case NRF51_RNG_EVENT_VALRDY:
+ r = s->event_valrdy;
+ break;
+ case NRF51_RNG_REG_SHORTS:
+ r = s->shortcut_stop_on_valrdy;
+ break;
+ case NRF51_RNG_REG_INTEN:
+ case NRF51_RNG_REG_INTENSET:
+ case NRF51_RNG_REG_INTENCLR:
+ r = s->interrupt_enabled;
+ break;
+ case NRF51_RNG_REG_CONFIG:
+ r = s->filter_enabled;
+ break;
+ case NRF51_RNG_REG_VALUE:
+ r = s->value;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ return r;
+}
+
+static int64_t calc_next_timeout(NRF51RNGState *s)
+{
+ int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
+ if (s->filter_enabled) {
+ timeout += s->period_filtered_us;
+ } else {
+ timeout += s->period_unfiltered_us;
+ }
+
+ return timeout;
+}
+
+
+static void rng_update_timer(NRF51RNGState *s)
+{
+ if (s->active) {
+ timer_mod(&s->timer, calc_next_timeout(s));
+ } else {
+ timer_del(&s->timer);
+ }
+}
+
+
+static void rng_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ switch (offset) {
+ case NRF51_RNG_TASK_START:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->active = 1;
+ rng_update_timer(s);
+ }
+ break;
+ case NRF51_RNG_TASK_STOP:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->active = 0;
+ rng_update_timer(s);
+ }
+ break;
+ case NRF51_RNG_EVENT_VALRDY:
+ if (value == NRF51_EVENT_CLEAR) {
+ s->event_valrdy = 0;
+ }
+ break;
+ case NRF51_RNG_REG_SHORTS:
+ s->shortcut_stop_on_valrdy =
+ (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
+ break;
+ case NRF51_RNG_REG_INTEN:
+ s->interrupt_enabled =
+ (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
+ break;
+ case NRF51_RNG_REG_INTENSET:
+ if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ s->interrupt_enabled = 1;
+ }
+ break;
+ case NRF51_RNG_REG_INTENCLR:
+ if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ s->interrupt_enabled = 0;
+ }
+ break;
+ case NRF51_RNG_REG_CONFIG:
+ s->filter_enabled =
+ (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_irq(s);
+}
+
+static const MemoryRegionOps rng_ops = {
+ .read = rng_read,
+ .write = rng_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4
+};
+
+static void nrf51_rng_timer_expire(void *opaque)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ qcrypto_random_bytes(&s->value, 1, &error_abort);
+
+ s->event_valrdy = 1;
+ qemu_set_irq(s->eep_valrdy, 1);
+
+ if (s->shortcut_stop_on_valrdy) {
+ s->active = 0;
+ }
+
+ rng_update_timer(s);
+ update_irq(s);
+}
+
+static void nrf51_rng_tep_start(void *opaque, int n, int level)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ if (level) {
+ s->active = 1;
+ rng_update_timer(s);
+ }
+}
+
+static void nrf51_rng_tep_stop(void *opaque, int n, int level)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ if (level) {
+ s->active = 0;
+ rng_update_timer(s);
+ }
+}
+
+
+static void nrf51_rng_init(Object *obj)
+{
+ NRF51RNGState *s = NRF51_RNG(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->mmio, obj, &rng_ops, s,
+ TYPE_NRF51_RNG, NRF51_RNG_SIZE);
+ sysbus_init_mmio(sbd, &s->mmio);
+
+ timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ /* Tasks */
+ qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
+ qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
+
+ /* Events */
+ qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
+}
+
+static void nrf51_rng_reset(DeviceState *dev)
+{
+ NRF51RNGState *s = NRF51_RNG(dev);
+
+ s->value = 0;
+ s->active = 0;
+ s->event_valrdy = 0;
+ s->shortcut_stop_on_valrdy = 0;
+ s->interrupt_enabled = 0;
+ s->filter_enabled = 0;
+
+ rng_update_timer(s);
+}
+
+
+static Property nrf51_rng_properties[] = {
+ DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
+ period_unfiltered_us, 167),
+ DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
+ period_filtered_us, 660),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_rng = {
+ .name = "nrf51_soc.rng",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(active, NRF51RNGState),
+ VMSTATE_UINT32(event_valrdy, NRF51RNGState),
+ VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
+ VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
+ VMSTATE_UINT32(filter_enabled, NRF51RNGState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_rng_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = nrf51_rng_properties;
+ dc->vmsd = &vmstate_rng;
+ dc->reset = nrf51_rng_reset;
+}
+
+static const TypeInfo nrf51_rng_info = {
+ .name = TYPE_NRF51_RNG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51RNGState),
+ .instance_init = nrf51_rng_init,
+ .class_init = nrf51_rng_class_init
+};
+
+static void nrf51_rng_register_types(void)
+{
+ type_register_static(&nrf51_rng_info);
+}
+
+type_init(nrf51_rng_register_types)
diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c
index 96fc057b4e..c217728c78 100644
--- a/hw/misc/omap_l4.c
+++ b/hw/misc/omap_l4.c
@@ -112,8 +112,8 @@ static const MemoryRegionOps omap_l4ta_ops = {
struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
const struct omap_l4_region_s *regions,
- const struct omap_l4_agent_info_s *agents,
- int cs)
+ const struct omap_l4_agent_info_s *agents,
+ int cs)
{
int i;
struct omap_target_agent_s *ta = NULL;
diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c
index 577cebaac7..afe191fbe1 100644
--- a/hw/misc/puv3_pm.c
+++ b/hw/misc/puv3_pm.c
@@ -119,7 +119,7 @@ static const MemoryRegionOps puv3_pm_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int puv3_pm_init(SysBusDevice *dev)
+static void puv3_pm_realize(DeviceState *dev, Error **errp)
{
PUV3PMState *s = PUV3_PM(dev);
@@ -127,16 +127,14 @@ static int puv3_pm_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm",
PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
static void puv3_pm_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = puv3_pm_init;
+ dc->realize = puv3_pm_realize;
}
static const TypeInfo puv3_pm_info = {
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index 0918f3a6ea..f6d7163273 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -79,7 +79,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
return;
}
if (temp >= 128000 || temp < -128000) {
- error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range",
+ error_setg(errp, "value %" PRId64 ".%03" PRIu64 " C is out of range",
temp / 1000, temp % 1000);
return;
}
diff --git a/hw/misc/tmp421.c b/hw/misc/tmp421.c
index c234044305..eeb11000f0 100644
--- a/hw/misc/tmp421.c
+++ b/hw/misc/tmp421.c
@@ -153,7 +153,7 @@ static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name,
}
if (temp >= maxs[ext_range] || temp < mins[ext_range]) {
- error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range",
+ error_setg(errp, "value %" PRId64 ".%03" PRIu64 " C is out of range",
temp / 1000, temp % 1000);
return;
}
diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index e0c58ba37e..9a84be75ed 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -150,7 +150,7 @@ static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
r = s->ctrl;
break;
case A_BLK_MAX:
- r = s->blk_max;
+ r = s->blk_max - 1;
break;
case A_BLK_CFG:
/* We are never in "init in progress state", so this just indicates
@@ -448,7 +448,7 @@ static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
{
/* We treat unspecified attributes like secure. Transactions with
* unspecified attributes come from places like
- * cpu_physical_memory_write_rom() for initial image load, and we want
+ * rom_reset() for initial image load, and we want
* those to pass through the from-reset "everything is secure" config.
* All the real during-emulation transactions from the CPU will
* specify attributes.
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index 4b0ce09c5e..c6b6f7262d 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -31,7 +31,6 @@
#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/hw.h"
-#include "hw/isa/isa.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 909c1182ee..790430346b 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -90,6 +90,18 @@
#define FTGMAC100_PHYDATA_MIIRDATA(x) (((x) >> 16) & 0xffff)
/*
+ * PHY control register - New MDC/MDIO interface
+ */
+#define FTGMAC100_PHYCR_NEW_DATA(x) (((x) >> 16) & 0xffff)
+#define FTGMAC100_PHYCR_NEW_FIRE (1 << 15)
+#define FTGMAC100_PHYCR_NEW_ST_22 (1 << 12)
+#define FTGMAC100_PHYCR_NEW_OP(x) (((x) >> 10) & 3)
+#define FTGMAC100_PHYCR_NEW_OP_WRITE 0x1
+#define FTGMAC100_PHYCR_NEW_OP_READ 0x2
+#define FTGMAC100_PHYCR_NEW_DEV(x) (((x) >> 5) & 0x1f)
+#define FTGMAC100_PHYCR_NEW_REG(x) ((x) & 0x1f)
+
+/*
* Feature Register
*/
#define FTGMAC100_REVR_NEW_MDIO_INTERFACE (1 << 31)
@@ -269,9 +281,9 @@ static void phy_reset(FTGMAC100State *s)
s->phy_int = 0;
}
-static uint32_t do_phy_read(FTGMAC100State *s, int reg)
+static uint16_t do_phy_read(FTGMAC100State *s, uint8_t reg)
{
- uint32_t val;
+ uint16_t val;
switch (reg) {
case MII_BMCR: /* Basic Control */
@@ -336,7 +348,7 @@ static uint32_t do_phy_read(FTGMAC100State *s, int reg)
MII_BMCR_FD | MII_BMCR_CTST)
#define MII_ANAR_MASK 0x2d7f
-static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val)
+static void do_phy_write(FTGMAC100State *s, uint8_t reg, uint16_t val)
{
switch (reg) {
case MII_BMCR: /* Basic Control */
@@ -373,6 +385,55 @@ static void do_phy_write(FTGMAC100State *s, int reg, uint32_t val)
}
}
+static void do_phy_new_ctl(FTGMAC100State *s)
+{
+ uint8_t reg;
+ uint16_t data;
+
+ if (!(s->phycr & FTGMAC100_PHYCR_NEW_ST_22)) {
+ qemu_log_mask(LOG_UNIMP, "%s: unsupported ST code\n", __func__);
+ return;
+ }
+
+ /* Nothing to do */
+ if (!(s->phycr & FTGMAC100_PHYCR_NEW_FIRE)) {
+ return;
+ }
+
+ reg = FTGMAC100_PHYCR_NEW_REG(s->phycr);
+ data = FTGMAC100_PHYCR_NEW_DATA(s->phycr);
+
+ switch (FTGMAC100_PHYCR_NEW_OP(s->phycr)) {
+ case FTGMAC100_PHYCR_NEW_OP_WRITE:
+ do_phy_write(s, reg, data);
+ break;
+ case FTGMAC100_PHYCR_NEW_OP_READ:
+ s->phydata = do_phy_read(s, reg) & 0xffff;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid OP code %08x\n",
+ __func__, s->phycr);
+ }
+
+ s->phycr &= ~FTGMAC100_PHYCR_NEW_FIRE;
+}
+
+static void do_phy_ctl(FTGMAC100State *s)
+{
+ uint8_t reg = FTGMAC100_PHYCR_REG(s->phycr);
+
+ if (s->phycr & FTGMAC100_PHYCR_MIIWR) {
+ do_phy_write(s, reg, s->phydata & 0xffff);
+ s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
+ } else if (s->phycr & FTGMAC100_PHYCR_MIIRD) {
+ s->phydata = do_phy_read(s, reg) << 16;
+ s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no OP code %08x\n",
+ __func__, s->phycr);
+ }
+}
+
static int ftgmac100_read_bd(FTGMAC100Desc *bd, dma_addr_t addr)
{
if (dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd))) {
@@ -628,7 +689,6 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
FTGMAC100State *s = FTGMAC100(opaque);
- int reg;
switch (addr & 0xff) {
case FTGMAC100_ISR: /* Interrupt status */
@@ -711,14 +771,11 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
break;
case FTGMAC100_PHYCR: /* PHY Device control */
- reg = FTGMAC100_PHYCR_REG(value);
s->phycr = value;
- if (value & FTGMAC100_PHYCR_MIIWR) {
- do_phy_write(s, reg, s->phydata & 0xffff);
- s->phycr &= ~FTGMAC100_PHYCR_MIIWR;
+ if (s->revr & FTGMAC100_REVR_NEW_MDIO_INTERFACE) {
+ do_phy_new_ctl(s);
} else {
- s->phydata = do_phy_read(s, reg) << 16;
- s->phycr &= ~FTGMAC100_PHYCR_MIIRD;
+ do_phy_ctl(s);
}
break;
case FTGMAC100_PHYDATA:
@@ -728,8 +785,7 @@ static void ftgmac100_write(void *opaque, hwaddr addr,
s->dblac = value;
break;
case FTGMAC100_REVR: /* Feature Register */
- /* TODO: Only Old MDIO interface is supported */
- s->revr = value & ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
+ s->revr = value;
break;
case FTGMAC100_FEAR1: /* Feature Register 1 */
s->fear1 = value;
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
index 03b3104278..5ec13105df 100644
--- a/hw/net/mipsnet.c
+++ b/hw/net/mipsnet.c
@@ -112,27 +112,27 @@ static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
addr &= 0x3f;
switch (addr) {
case MIPSNET_DEV_ID:
- ret = be32_to_cpu(0x4d495053); /* MIPS */
+ ret = be32_to_cpu(0x4d495053); /* MIPS */
break;
case MIPSNET_DEV_ID + 4:
- ret = be32_to_cpu(0x4e455430); /* NET0 */
+ ret = be32_to_cpu(0x4e455430); /* NET0 */
break;
case MIPSNET_BUSY:
- ret = s->busy;
+ ret = s->busy;
break;
case MIPSNET_RX_DATA_COUNT:
- ret = s->rx_count;
+ ret = s->rx_count;
break;
case MIPSNET_TX_DATA_COUNT:
- ret = s->tx_count;
+ ret = s->tx_count;
break;
case MIPSNET_INT_CTL:
- ret = s->intctl;
+ ret = s->intctl;
s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
break;
case MIPSNET_INTERRUPT_INFO:
/* XXX: This seems to be a per-VPE interrupt number. */
- ret = 0;
+ ret = 0;
break;
case MIPSNET_RX_DATA_BUFFER:
if (s->rx_count) {
@@ -161,7 +161,7 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr,
trace_mipsnet_write(addr, val);
switch (addr) {
case MIPSNET_TX_DATA_COUNT:
- s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
+ s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
s->tx_written = 0;
break;
case MIPSNET_INT_CTL:
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 869518ee06..037afc8052 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -145,7 +145,7 @@ static void ne2000_update_irq(NE2000State *s)
isr = (s->isr & s->imr) & 0x7f;
#if defined(DEBUG_NE2000)
printf("NE2000: Set IRQ to %d (%02x %02x)\n",
- isr ? 1 : 0, s->isr, s->imr);
+ isr ? 1 : 0, s->isr, s->imr);
#endif
qemu_set_irq(s->irq, (isr != 0));
}
@@ -396,12 +396,12 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
case EN0_ISR:
ret = s->isr;
break;
- case EN0_RSARLO:
- ret = s->rsar & 0x00ff;
- break;
- case EN0_RSARHI:
- ret = s->rsar >> 8;
- break;
+ case EN0_RSARLO:
+ ret = s->rsar & 0x00ff;
+ break;
+ case EN0_RSARHI:
+ ret = s->rsar >> 8;
+ break;
case EN1_PHYS ... EN1_PHYS + 5:
ret = s->phys[offset - EN1_PHYS];
break;
@@ -420,21 +420,21 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
case EN2_STOPPG:
ret = s->stop >> 8;
break;
- case EN0_RTL8029ID0:
- ret = 0x50;
- break;
- case EN0_RTL8029ID1:
- ret = 0x43;
- break;
- case EN3_CONFIG0:
- ret = 0; /* 10baseT media */
- break;
- case EN3_CONFIG2:
- ret = 0x40; /* 10baseT active */
- break;
- case EN3_CONFIG3:
- ret = 0x40; /* Full duplex */
- break;
+ case EN0_RTL8029ID0:
+ ret = 0x50;
+ break;
+ case EN0_RTL8029ID1:
+ ret = 0x43;
+ break;
+ case EN3_CONFIG0:
+ ret = 0; /* 10baseT media */
+ break;
+ case EN3_CONFIG2:
+ ret = 0x40; /* 10baseT active */
+ break;
+ case EN3_CONFIG3:
+ ret = 0x40; /* Full duplex */
+ break;
default:
ret = 0x00;
break;
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index c02cbefece..5266f9b7dd 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -1279,7 +1279,7 @@ static World *rocker_world_type_by_name(Rocker *r, const char *name)
for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
if (strcmp(name, world_name(r->worlds[i])) == 0) {
return r->worlds[i];
- }
+ }
}
return NULL;
}
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 385b1a03e9..3f319ef723 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -41,6 +41,47 @@
#define VIRTIO_NET_RX_QUEUE_MIN_SIZE VIRTIO_NET_RX_QUEUE_DEFAULT_SIZE
#define VIRTIO_NET_TX_QUEUE_MIN_SIZE VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE
+#define VIRTIO_NET_IP4_ADDR_SIZE 8 /* ipv4 saddr + daddr */
+
+#define VIRTIO_NET_TCP_FLAG 0x3F
+#define VIRTIO_NET_TCP_HDR_LENGTH 0xF000
+
+/* IPv4 max payload, 16 bits in the header */
+#define VIRTIO_NET_MAX_IP4_PAYLOAD (65535 - sizeof(struct ip_header))
+#define VIRTIO_NET_MAX_TCP_PAYLOAD 65535
+
+/* header length value in ip header without option */
+#define VIRTIO_NET_IP4_HEADER_LENGTH 5
+
+#define VIRTIO_NET_IP6_ADDR_SIZE 32 /* ipv6 saddr + daddr */
+#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
+
+/* Purge coalesced packets timer interval, This value affects the performance
+ a lot, and should be tuned carefully, '300000'(300us) is the recommended
+ value to pass the WHQL test, '50000' can gain 2x netperf throughput with
+ tso/gso/gro 'off'. */
+#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000
+
+/* temporary until standard header include it */
+#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
+
+#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */
+#define VIRTIO_NET_F_RSC_EXT 61
+
+static inline __virtio16 *virtio_net_rsc_ext_num_packets(
+ struct virtio_net_hdr *hdr)
+{
+ return &hdr->csum_start;
+}
+
+static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
+ struct virtio_net_hdr *hdr)
+{
+ return &hdr->csum_offset;
+}
+
+#endif
+
/*
* Calculate the number of bytes up to and including the given 'field' of
* 'container'.
@@ -628,6 +669,7 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
if (!get_vhost_net(nc->peer)) {
return features;
}
+
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
vdev->backend_features = features;
@@ -701,6 +743,11 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
virtio_has_feature(features,
VIRTIO_F_VERSION_1));
+ n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
+ virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4);
+ n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
+ virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6);
+
if (n->has_vnet_hdr) {
n->curr_guest_offloads =
virtio_net_guest_offloads_by_features(features);
@@ -781,6 +828,12 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR;
}
+ n->rsc4_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) &&
+ virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO4);
+ n->rsc6_enabled = virtio_has_feature(offloads, VIRTIO_NET_F_RSC_EXT) &&
+ virtio_has_feature(offloads, VIRTIO_NET_F_GUEST_TSO6);
+ virtio_clear_feature(&offloads, VIRTIO_NET_F_RSC_EXT);
+
supported_offloads = virtio_net_supported_guest_offloads(n);
if (offloads & ~supported_offloads) {
return VIRTIO_NET_ERR;
@@ -1292,7 +1345,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
return size;
}
-static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
+static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
size_t size)
{
ssize_t r;
@@ -1303,6 +1356,612 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
return r;
}
+static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
+ const uint8_t *buf,
+ VirtioNetRscUnit *unit)
+{
+ uint16_t ip_hdrlen;
+ struct ip_header *ip;
+
+ ip = (struct ip_header *)(buf + chain->n->guest_hdr_len
+ + sizeof(struct eth_header));
+ unit->ip = (void *)ip;
+ ip_hdrlen = (ip->ip_ver_len & 0xF) << 2;
+ unit->ip_plen = &ip->ip_len;
+ unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip) + ip_hdrlen);
+ unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
+ unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
+}
+
+static void virtio_net_rsc_extract_unit6(VirtioNetRscChain *chain,
+ const uint8_t *buf,
+ VirtioNetRscUnit *unit)
+{
+ struct ip6_header *ip6;
+
+ ip6 = (struct ip6_header *)(buf + chain->n->guest_hdr_len
+ + sizeof(struct eth_header));
+ unit->ip = ip6;
+ unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+ unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
+ + sizeof(struct ip6_header));
+ unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
+
+ /* There is a difference between payload lenght in ipv4 and v6,
+ ip header is excluded in ipv6 */
+ unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
+}
+
+static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain,
+ VirtioNetRscSeg *seg)
+{
+ int ret;
+ struct virtio_net_hdr *h;
+
+ h = (struct virtio_net_hdr *)seg->buf;
+ h->flags = 0;
+ h->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+
+ if (seg->is_coalesced) {
+ *virtio_net_rsc_ext_num_packets(h) = seg->packets;
+ *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack;
+ h->flags = VIRTIO_NET_HDR_F_RSC_INFO;
+ if (chain->proto == ETH_P_IP) {
+ h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ } else {
+ h->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ }
+ }
+
+ ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
+ QTAILQ_REMOVE(&chain->buffers, seg, next);
+ g_free(seg->buf);
+ g_free(seg);
+
+ return ret;
+}
+
+static void virtio_net_rsc_purge(void *opq)
+{
+ VirtioNetRscSeg *seg, *rn;
+ VirtioNetRscChain *chain = (VirtioNetRscChain *)opq;
+
+ QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn) {
+ if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
+ chain->stat.purge_failed++;
+ continue;
+ }
+ }
+
+ chain->stat.timer++;
+ if (!QTAILQ_EMPTY(&chain->buffers)) {
+ timer_mod(chain->drain_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
+ }
+}
+
+static void virtio_net_rsc_cleanup(VirtIONet *n)
+{
+ VirtioNetRscChain *chain, *rn_chain;
+ VirtioNetRscSeg *seg, *rn_seg;
+
+ QTAILQ_FOREACH_SAFE(chain, &n->rsc_chains, next, rn_chain) {
+ QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, rn_seg) {
+ QTAILQ_REMOVE(&chain->buffers, seg, next);
+ g_free(seg->buf);
+ g_free(seg);
+ }
+
+ timer_del(chain->drain_timer);
+ timer_free(chain->drain_timer);
+ QTAILQ_REMOVE(&n->rsc_chains, chain, next);
+ g_free(chain);
+ }
+}
+
+static void virtio_net_rsc_cache_buf(VirtioNetRscChain *chain,
+ NetClientState *nc,
+ const uint8_t *buf, size_t size)
+{
+ uint16_t hdr_len;
+ VirtioNetRscSeg *seg;
+
+ hdr_len = chain->n->guest_hdr_len;
+ seg = g_malloc(sizeof(VirtioNetRscSeg));
+ seg->buf = g_malloc(hdr_len + sizeof(struct eth_header)
+ + sizeof(struct ip6_header) + VIRTIO_NET_MAX_TCP_PAYLOAD);
+ memcpy(seg->buf, buf, size);
+ seg->size = size;
+ seg->packets = 1;
+ seg->dup_ack = 0;
+ seg->is_coalesced = 0;
+ seg->nc = nc;
+
+ QTAILQ_INSERT_TAIL(&chain->buffers, seg, next);
+ chain->stat.cache++;
+
+ switch (chain->proto) {
+ case ETH_P_IP:
+ virtio_net_rsc_extract_unit4(chain, seg->buf, &seg->unit);
+ break;
+ case ETH_P_IPV6:
+ virtio_net_rsc_extract_unit6(chain, seg->buf, &seg->unit);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static int32_t virtio_net_rsc_handle_ack(VirtioNetRscChain *chain,
+ VirtioNetRscSeg *seg,
+ const uint8_t *buf,
+ struct tcp_header *n_tcp,
+ struct tcp_header *o_tcp)
+{
+ uint32_t nack, oack;
+ uint16_t nwin, owin;
+
+ nack = htonl(n_tcp->th_ack);
+ nwin = htons(n_tcp->th_win);
+ oack = htonl(o_tcp->th_ack);
+ owin = htons(o_tcp->th_win);
+
+ if ((nack - oack) >= VIRTIO_NET_MAX_TCP_PAYLOAD) {
+ chain->stat.ack_out_of_win++;
+ return RSC_FINAL;
+ } else if (nack == oack) {
+ /* duplicated ack or window probe */
+ if (nwin == owin) {
+ /* duplicated ack, add dup ack count due to whql test up to 1 */
+ chain->stat.dup_ack++;
+ return RSC_FINAL;
+ } else {
+ /* Coalesce window update */
+ o_tcp->th_win = n_tcp->th_win;
+ chain->stat.win_update++;
+ return RSC_COALESCE;
+ }
+ } else {
+ /* pure ack, go to 'C', finalize*/
+ chain->stat.pure_ack++;
+ return RSC_FINAL;
+ }
+}
+
+static int32_t virtio_net_rsc_coalesce_data(VirtioNetRscChain *chain,
+ VirtioNetRscSeg *seg,
+ const uint8_t *buf,
+ VirtioNetRscUnit *n_unit)
+{
+ void *data;
+ uint16_t o_ip_len;
+ uint32_t nseq, oseq;
+ VirtioNetRscUnit *o_unit;
+
+ o_unit = &seg->unit;
+ o_ip_len = htons(*o_unit->ip_plen);
+ nseq = htonl(n_unit->tcp->th_seq);
+ oseq = htonl(o_unit->tcp->th_seq);
+
+ /* out of order or retransmitted. */
+ if ((nseq - oseq) > VIRTIO_NET_MAX_TCP_PAYLOAD) {
+ chain->stat.data_out_of_win++;
+ return RSC_FINAL;
+ }
+
+ data = ((uint8_t *)n_unit->tcp) + n_unit->tcp_hdrlen;
+ if (nseq == oseq) {
+ if ((o_unit->payload == 0) && n_unit->payload) {
+ /* From no payload to payload, normal case, not a dup ack or etc */
+ chain->stat.data_after_pure_ack++;
+ goto coalesce;
+ } else {
+ return virtio_net_rsc_handle_ack(chain, seg, buf,
+ n_unit->tcp, o_unit->tcp);
+ }
+ } else if ((nseq - oseq) != o_unit->payload) {
+ /* Not a consistent packet, out of order */
+ chain->stat.data_out_of_order++;
+ return RSC_FINAL;
+ } else {
+coalesce:
+ if ((o_ip_len + n_unit->payload) > chain->max_payload) {
+ chain->stat.over_size++;
+ return RSC_FINAL;
+ }
+
+ /* Here comes the right data, the payload length in v4/v6 is different,
+ so use the field value to update and record the new data len */
+ o_unit->payload += n_unit->payload; /* update new data len */
+
+ /* update field in ip header */
+ *o_unit->ip_plen = htons(o_ip_len + n_unit->payload);
+
+ /* Bring 'PUSH' big, the whql test guide says 'PUSH' can be coalesced
+ for windows guest, while this may change the behavior for linux
+ guest (only if it uses RSC feature). */
+ o_unit->tcp->th_offset_flags = n_unit->tcp->th_offset_flags;
+
+ o_unit->tcp->th_ack = n_unit->tcp->th_ack;
+ o_unit->tcp->th_win = n_unit->tcp->th_win;
+
+ memmove(seg->buf + seg->size, data, n_unit->payload);
+ seg->size += n_unit->payload;
+ seg->packets++;
+ chain->stat.coalesced++;
+ return RSC_COALESCE;
+ }
+}
+
+static int32_t virtio_net_rsc_coalesce4(VirtioNetRscChain *chain,
+ VirtioNetRscSeg *seg,
+ const uint8_t *buf, size_t size,
+ VirtioNetRscUnit *unit)
+{
+ struct ip_header *ip1, *ip2;
+
+ ip1 = (struct ip_header *)(unit->ip);
+ ip2 = (struct ip_header *)(seg->unit.ip);
+ if ((ip1->ip_src ^ ip2->ip_src) || (ip1->ip_dst ^ ip2->ip_dst)
+ || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
+ || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
+ chain->stat.no_match++;
+ return RSC_NO_MATCH;
+ }
+
+ return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
+}
+
+static int32_t virtio_net_rsc_coalesce6(VirtioNetRscChain *chain,
+ VirtioNetRscSeg *seg,
+ const uint8_t *buf, size_t size,
+ VirtioNetRscUnit *unit)
+{
+ struct ip6_header *ip1, *ip2;
+
+ ip1 = (struct ip6_header *)(unit->ip);
+ ip2 = (struct ip6_header *)(seg->unit.ip);
+ if (memcmp(&ip1->ip6_src, &ip2->ip6_src, sizeof(struct in6_address))
+ || memcmp(&ip1->ip6_dst, &ip2->ip6_dst, sizeof(struct in6_address))
+ || (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
+ || (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
+ chain->stat.no_match++;
+ return RSC_NO_MATCH;
+ }
+
+ return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
+}
+
+/* Packets with 'SYN' should bypass, other flag should be sent after drain
+ * to prevent out of order */
+static int virtio_net_rsc_tcp_ctrl_check(VirtioNetRscChain *chain,
+ struct tcp_header *tcp)
+{
+ uint16_t tcp_hdr;
+ uint16_t tcp_flag;
+
+ tcp_flag = htons(tcp->th_offset_flags);
+ tcp_hdr = (tcp_flag & VIRTIO_NET_TCP_HDR_LENGTH) >> 10;
+ tcp_flag &= VIRTIO_NET_TCP_FLAG;
+ tcp_flag = htons(tcp->th_offset_flags) & 0x3F;
+ if (tcp_flag & TH_SYN) {
+ chain->stat.tcp_syn++;
+ return RSC_BYPASS;
+ }
+
+ if (tcp_flag & (TH_FIN | TH_URG | TH_RST | TH_ECE | TH_CWR)) {
+ chain->stat.tcp_ctrl_drain++;
+ return RSC_FINAL;
+ }
+
+ if (tcp_hdr > sizeof(struct tcp_header)) {
+ chain->stat.tcp_all_opt++;
+ return RSC_FINAL;
+ }
+
+ return RSC_CANDIDATE;
+}
+
+static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain,
+ NetClientState *nc,
+ const uint8_t *buf, size_t size,
+ VirtioNetRscUnit *unit)
+{
+ int ret;
+ VirtioNetRscSeg *seg, *nseg;
+
+ if (QTAILQ_EMPTY(&chain->buffers)) {
+ chain->stat.empty_cache++;
+ virtio_net_rsc_cache_buf(chain, nc, buf, size);
+ timer_mod(chain->drain_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
+ return size;
+ }
+
+ QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) {
+ if (chain->proto == ETH_P_IP) {
+ ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
+ } else {
+ ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit);
+ }
+
+ if (ret == RSC_FINAL) {
+ if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
+ /* Send failed */
+ chain->stat.final_failed++;
+ return 0;
+ }
+
+ /* Send current packet */
+ return virtio_net_do_receive(nc, buf, size);
+ } else if (ret == RSC_NO_MATCH) {
+ continue;
+ } else {
+ /* Coalesced, mark coalesced flag to tell calc cksum for ipv4 */
+ seg->is_coalesced = 1;
+ return size;
+ }
+ }
+
+ chain->stat.no_match_cache++;
+ virtio_net_rsc_cache_buf(chain, nc, buf, size);
+ return size;
+}
+
+/* Drain a connection data, this is to avoid out of order segments */
+static size_t virtio_net_rsc_drain_flow(VirtioNetRscChain *chain,
+ NetClientState *nc,
+ const uint8_t *buf, size_t size,
+ uint16_t ip_start, uint16_t ip_size,
+ uint16_t tcp_port)
+{
+ VirtioNetRscSeg *seg, *nseg;
+ uint32_t ppair1, ppair2;
+
+ ppair1 = *(uint32_t *)(buf + tcp_port);
+ QTAILQ_FOREACH_SAFE(seg, &chain->buffers, next, nseg) {
+ ppair2 = *(uint32_t *)(seg->buf + tcp_port);
+ if (memcmp(buf + ip_start, seg->buf + ip_start, ip_size)
+ || (ppair1 != ppair2)) {
+ continue;
+ }
+ if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
+ chain->stat.drain_failed++;
+ }
+
+ break;
+ }
+
+ return virtio_net_do_receive(nc, buf, size);
+}
+
+static int32_t virtio_net_rsc_sanity_check4(VirtioNetRscChain *chain,
+ struct ip_header *ip,
+ const uint8_t *buf, size_t size)
+{
+ uint16_t ip_len;
+
+ /* Not an ipv4 packet */
+ if (((ip->ip_ver_len & 0xF0) >> 4) != IP_HEADER_VERSION_4) {
+ chain->stat.ip_option++;
+ return RSC_BYPASS;
+ }
+
+ /* Don't handle packets with ip option */
+ if ((ip->ip_ver_len & 0xF) != VIRTIO_NET_IP4_HEADER_LENGTH) {
+ chain->stat.ip_option++;
+ return RSC_BYPASS;
+ }
+
+ if (ip->ip_p != IPPROTO_TCP) {
+ chain->stat.bypass_not_tcp++;
+ return RSC_BYPASS;
+ }
+
+ /* Don't handle packets with ip fragment */
+ if (!(htons(ip->ip_off) & IP_DF)) {
+ chain->stat.ip_frag++;
+ return RSC_BYPASS;
+ }
+
+ /* Don't handle packets with ecn flag */
+ if (IPTOS_ECN(ip->ip_tos)) {
+ chain->stat.ip_ecn++;
+ return RSC_BYPASS;
+ }
+
+ ip_len = htons(ip->ip_len);
+ if (ip_len < (sizeof(struct ip_header) + sizeof(struct tcp_header))
+ || ip_len > (size - chain->n->guest_hdr_len -
+ sizeof(struct eth_header))) {
+ chain->stat.ip_hacked++;
+ return RSC_BYPASS;
+ }
+
+ return RSC_CANDIDATE;
+}
+
+static size_t virtio_net_rsc_receive4(VirtioNetRscChain *chain,
+ NetClientState *nc,
+ const uint8_t *buf, size_t size)
+{
+ int32_t ret;
+ uint16_t hdr_len;
+ VirtioNetRscUnit unit;
+
+ hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
+
+ if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header)
+ + sizeof(struct tcp_header))) {
+ chain->stat.bypass_not_tcp++;
+ return virtio_net_do_receive(nc, buf, size);
+ }
+
+ virtio_net_rsc_extract_unit4(chain, buf, &unit);
+ if (virtio_net_rsc_sanity_check4(chain, unit.ip, buf, size)
+ != RSC_CANDIDATE) {
+ return virtio_net_do_receive(nc, buf, size);
+ }
+
+ ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp);
+ if (ret == RSC_BYPASS) {
+ return virtio_net_do_receive(nc, buf, size);
+ } else if (ret == RSC_FINAL) {
+ return virtio_net_rsc_drain_flow(chain, nc, buf, size,
+ ((hdr_len + sizeof(struct eth_header)) + 12),
+ VIRTIO_NET_IP4_ADDR_SIZE,
+ hdr_len + sizeof(struct eth_header) + sizeof(struct ip_header));
+ }
+
+ return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit);
+}
+
+static int32_t virtio_net_rsc_sanity_check6(VirtioNetRscChain *chain,
+ struct ip6_header *ip6,
+ const uint8_t *buf, size_t size)
+{
+ uint16_t ip_len;
+
+ if (((ip6->ip6_ctlun.ip6_un1.ip6_un1_flow & 0xF0) >> 4)
+ != IP_HEADER_VERSION_6) {
+ return RSC_BYPASS;
+ }
+
+ /* Both option and protocol is checked in this */
+ if (ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) {
+ chain->stat.bypass_not_tcp++;
+ return RSC_BYPASS;
+ }
+
+ ip_len = htons(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+ if (ip_len < sizeof(struct tcp_header) ||
+ ip_len > (size - chain->n->guest_hdr_len - sizeof(struct eth_header)
+ - sizeof(struct ip6_header))) {
+ chain->stat.ip_hacked++;
+ return RSC_BYPASS;
+ }
+
+ /* Don't handle packets with ecn flag */
+ if (IP6_ECN(ip6->ip6_ctlun.ip6_un3.ip6_un3_ecn)) {
+ chain->stat.ip_ecn++;
+ return RSC_BYPASS;
+ }
+
+ return RSC_CANDIDATE;
+}
+
+static size_t virtio_net_rsc_receive6(void *opq, NetClientState *nc,
+ const uint8_t *buf, size_t size)
+{
+ int32_t ret;
+ uint16_t hdr_len;
+ VirtioNetRscChain *chain;
+ VirtioNetRscUnit unit;
+
+ chain = (VirtioNetRscChain *)opq;
+ hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
+
+ if (size < (hdr_len + sizeof(struct eth_header) + sizeof(struct ip6_header)
+ + sizeof(tcp_header))) {
+ return virtio_net_do_receive(nc, buf, size);
+ }
+
+ virtio_net_rsc_extract_unit6(chain, buf, &unit);
+ if (RSC_CANDIDATE != virtio_net_rsc_sanity_check6(chain,
+ unit.ip, buf, size)) {
+ return virtio_net_do_receive(nc, buf, size);
+ }
+
+ ret = virtio_net_rsc_tcp_ctrl_check(chain, unit.tcp);
+ if (ret == RSC_BYPASS) {
+ return virtio_net_do_receive(nc, buf, size);
+ } else if (ret == RSC_FINAL) {
+ return virtio_net_rsc_drain_flow(chain, nc, buf, size,
+ ((hdr_len + sizeof(struct eth_header)) + 8),
+ VIRTIO_NET_IP6_ADDR_SIZE,
+ hdr_len + sizeof(struct eth_header)
+ + sizeof(struct ip6_header));
+ }
+
+ return virtio_net_rsc_do_coalesce(chain, nc, buf, size, &unit);
+}
+
+static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n,
+ NetClientState *nc,
+ uint16_t proto)
+{
+ VirtioNetRscChain *chain;
+
+ if ((proto != (uint16_t)ETH_P_IP) && (proto != (uint16_t)ETH_P_IPV6)) {
+ return NULL;
+ }
+
+ QTAILQ_FOREACH(chain, &n->rsc_chains, next) {
+ if (chain->proto == proto) {
+ return chain;
+ }
+ }
+
+ chain = g_malloc(sizeof(*chain));
+ chain->n = n;
+ chain->proto = proto;
+ if (proto == (uint16_t)ETH_P_IP) {
+ chain->max_payload = VIRTIO_NET_MAX_IP4_PAYLOAD;
+ chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ } else {
+ chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
+ chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ }
+ chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST,
+ virtio_net_rsc_purge, chain);
+ memset(&chain->stat, 0, sizeof(chain->stat));
+
+ QTAILQ_INIT(&chain->buffers);
+ QTAILQ_INSERT_TAIL(&n->rsc_chains, chain, next);
+
+ return chain;
+}
+
+static ssize_t virtio_net_rsc_receive(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+ uint16_t proto;
+ VirtioNetRscChain *chain;
+ struct eth_header *eth;
+ VirtIONet *n;
+
+ n = qemu_get_nic_opaque(nc);
+ if (size < (n->host_hdr_len + sizeof(struct eth_header))) {
+ return virtio_net_do_receive(nc, buf, size);
+ }
+
+ eth = (struct eth_header *)(buf + n->guest_hdr_len);
+ proto = htons(eth->h_proto);
+
+ chain = virtio_net_rsc_lookup_chain(n, nc, proto);
+ if (chain) {
+ chain->stat.received++;
+ if (proto == (uint16_t)ETH_P_IP && n->rsc4_enabled) {
+ return virtio_net_rsc_receive4(chain, nc, buf, size);
+ } else if (proto == (uint16_t)ETH_P_IPV6 && n->rsc6_enabled) {
+ return virtio_net_rsc_receive6(chain, nc, buf, size);
+ }
+ }
+ return virtio_net_do_receive(nc, buf, size);
+}
+
+static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
+ size_t size)
+{
+ VirtIONet *n = qemu_get_nic_opaque(nc);
+ if ((n->rsc4_enabled || n->rsc6_enabled)) {
+ return virtio_net_rsc_receive(nc, buf, size);
+ } else {
+ return virtio_net_do_receive(nc, buf, size);
+ }
+}
+
static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
@@ -1375,10 +2034,10 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
n->guest_hdr_len, -1);
if (out_num == VIRTQUEUE_MAX_SIZE) {
goto drop;
- }
+ }
out_num += 1;
out_sg = sg2;
- }
+ }
}
/*
* If host wants to see the guest header as is, we can
@@ -2075,6 +2734,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
nc = qemu_get_queue(n->nic);
nc->rxfilter_notify_enabled = 1;
+ QTAILQ_INIT(&n->rsc_chains);
n->qdev = dev;
}
@@ -2104,6 +2764,7 @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp)
timer_free(n->announce_timer);
g_free(n->vqs);
qemu_del_nic(n->nic);
+ virtio_net_rsc_cleanup(n);
virtio_cleanup(vdev);
}
@@ -2184,6 +2845,10 @@ static Property virtio_net_properties[] = {
DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features,
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
+ DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
+ VIRTIO_NET_F_RSC_EXT, false),
+ DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
+ VIRTIO_NET_RSC_DEFAULT_INTERVAL),
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
TX_TIMER_INTERVAL),
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 3648630386..4665dc95ad 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -18,7 +18,6 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/pci/pci.h"
-#include "net/net.h"
#include "net/tap.h"
#include "net/checksum.h"
#include "sysemu/sysemu.h"
@@ -29,6 +28,7 @@
#include "migration/register.h"
#include "vmxnet3.h"
+#include "vmxnet3_defs.h"
#include "vmxnet_debug.h"
#include "vmware_utils.h"
#include "net_tx_pkt.h"
@@ -131,25 +131,13 @@ typedef struct VMXNET3Class {
DeviceRealize parent_dc_realize;
} VMXNET3Class;
-#define TYPE_VMXNET3 "vmxnet3"
-#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
-
#define VMXNET3_DEVICE_CLASS(klass) \
OBJECT_CLASS_CHECK(VMXNET3Class, (klass), TYPE_VMXNET3)
#define VMXNET3_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(VMXNET3Class, (obj), TYPE_VMXNET3)
-/* Cyclic ring abstraction */
-typedef struct {
- hwaddr pa;
- uint32_t size;
- uint32_t cell_size;
- uint32_t next;
- uint8_t gen;
-} Vmxnet3Ring;
-
static inline void vmxnet3_ring_init(PCIDevice *d,
- Vmxnet3Ring *ring,
+ Vmxnet3Ring *ring,
hwaddr pa,
uint32_t size,
uint32_t cell_size,
@@ -193,13 +181,13 @@ static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring)
}
static inline void vmxnet3_ring_read_curr_cell(PCIDevice *d, Vmxnet3Ring *ring,
- void *buff)
+ void *buff)
{
vmw_shmem_read(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
}
static inline void vmxnet3_ring_write_curr_cell(PCIDevice *d, Vmxnet3Ring *ring,
- void *buff)
+ void *buff)
{
vmw_shmem_write(d, vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
}
@@ -245,108 +233,6 @@ vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr)
descr->rsvd, descr->dtype, descr->ext1, descr->btype);
}
-/* Device state and helper functions */
-#define VMXNET3_RX_RINGS_PER_QUEUE (2)
-
-typedef struct {
- Vmxnet3Ring tx_ring;
- Vmxnet3Ring comp_ring;
-
- uint8_t intr_idx;
- hwaddr tx_stats_pa;
- struct UPT1_TxStats txq_stats;
-} Vmxnet3TxqDescr;
-
-typedef struct {
- Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
- Vmxnet3Ring comp_ring;
- uint8_t intr_idx;
- hwaddr rx_stats_pa;
- struct UPT1_RxStats rxq_stats;
-} Vmxnet3RxqDescr;
-
-typedef struct {
- bool is_masked;
- bool is_pending;
- bool is_asserted;
-} Vmxnet3IntState;
-
-typedef struct {
- PCIDevice parent_obj;
- NICState *nic;
- NICConf conf;
- MemoryRegion bar0;
- MemoryRegion bar1;
- MemoryRegion msix_bar;
-
- Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
- Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
-
- /* Whether MSI-X support was installed successfully */
- bool msix_used;
- hwaddr drv_shmem;
- hwaddr temp_shared_guest_driver_memory;
-
- uint8_t txq_num;
-
- /* This boolean tells whether RX packet being indicated has to */
- /* be split into head and body chunks from different RX rings */
- bool rx_packets_compound;
-
- bool rx_vlan_stripping;
- bool lro_supported;
-
- uint8_t rxq_num;
-
- /* Network MTU */
- uint32_t mtu;
-
- /* Maximum number of fragments for indicated TX packets */
- uint32_t max_tx_frags;
-
- /* Maximum number of fragments for indicated RX packets */
- uint16_t max_rx_frags;
-
- /* Index for events interrupt */
- uint8_t event_int_idx;
-
- /* Whether automatic interrupts masking enabled */
- bool auto_int_masking;
-
- bool peer_has_vhdr;
-
- /* TX packets to QEMU interface */
- struct NetTxPkt *tx_pkt;
- uint32_t offload_mode;
- uint32_t cso_or_gso_size;
- uint16_t tci;
- bool needs_vlan;
-
- struct NetRxPkt *rx_pkt;
-
- bool tx_sop;
- bool skip_current_tx_pkt;
-
- uint32_t device_active;
- uint32_t last_command;
-
- uint32_t link_status_and_speed;
-
- Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
-
- uint32_t temp_mac; /* To store the low part first */
-
- MACAddr perm_mac;
- uint32_t vlan_table[VMXNET3_VFT_SIZE];
- uint32_t rx_mode;
- MACAddr *mcast_list;
- uint32_t mcast_list_len;
- uint32_t mcast_list_buff_size; /* needed for live migration. */
-
- /* Compatibility flags for migration */
- uint32_t compat_flags;
-} VMXNET3State;
-
/* Interrupt management */
/*
diff --git a/hw/net/vmxnet3_defs.h b/hw/net/vmxnet3_defs.h
new file mode 100644
index 0000000000..6c19d29b12
--- /dev/null
+++ b/hw/net/vmxnet3_defs.h
@@ -0,0 +1,133 @@
+/*
+ * QEMU VMWARE VMXNET3 paravirtual NIC
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "net/net.h"
+#include "hw/net/vmxnet3.h"
+
+#define TYPE_VMXNET3 "vmxnet3"
+#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
+
+/* Device state and helper functions */
+#define VMXNET3_RX_RINGS_PER_QUEUE (2)
+
+/* Cyclic ring abstraction */
+typedef struct {
+ hwaddr pa;
+ uint32_t size;
+ uint32_t cell_size;
+ uint32_t next;
+ uint8_t gen;
+} Vmxnet3Ring;
+
+typedef struct {
+ Vmxnet3Ring tx_ring;
+ Vmxnet3Ring comp_ring;
+
+ uint8_t intr_idx;
+ hwaddr tx_stats_pa;
+ struct UPT1_TxStats txq_stats;
+} Vmxnet3TxqDescr;
+
+typedef struct {
+ Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
+ Vmxnet3Ring comp_ring;
+ uint8_t intr_idx;
+ hwaddr rx_stats_pa;
+ struct UPT1_RxStats rxq_stats;
+} Vmxnet3RxqDescr;
+
+typedef struct {
+ bool is_masked;
+ bool is_pending;
+ bool is_asserted;
+} Vmxnet3IntState;
+
+typedef struct {
+ PCIDevice parent_obj;
+ NICState *nic;
+ NICConf conf;
+ MemoryRegion bar0;
+ MemoryRegion bar1;
+ MemoryRegion msix_bar;
+
+ Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
+ Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
+
+ /* Whether MSI-X support was installed successfully */
+ bool msix_used;
+ hwaddr drv_shmem;
+ hwaddr temp_shared_guest_driver_memory;
+
+ uint8_t txq_num;
+
+ /* This boolean tells whether RX packet being indicated has to */
+ /* be split into head and body chunks from different RX rings */
+ bool rx_packets_compound;
+
+ bool rx_vlan_stripping;
+ bool lro_supported;
+
+ uint8_t rxq_num;
+
+ /* Network MTU */
+ uint32_t mtu;
+
+ /* Maximum number of fragments for indicated TX packets */
+ uint32_t max_tx_frags;
+
+ /* Maximum number of fragments for indicated RX packets */
+ uint16_t max_rx_frags;
+
+ /* Index for events interrupt */
+ uint8_t event_int_idx;
+
+ /* Whether automatic interrupts masking enabled */
+ bool auto_int_masking;
+
+ bool peer_has_vhdr;
+
+ /* TX packets to QEMU interface */
+ struct NetTxPkt *tx_pkt;
+ uint32_t offload_mode;
+ uint32_t cso_or_gso_size;
+ uint16_t tci;
+ bool needs_vlan;
+
+ struct NetRxPkt *rx_pkt;
+
+ bool tx_sop;
+ bool skip_current_tx_pkt;
+
+ uint32_t device_active;
+ uint32_t last_command;
+
+ uint32_t link_status_and_speed;
+
+ Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
+
+ uint32_t temp_mac; /* To store the low part first */
+
+ MACAddr perm_mac;
+ uint32_t vlan_table[VMXNET3_VFT_SIZE];
+ uint32_t rx_mode;
+ MACAddr *mcast_list;
+ uint32_t mcast_list_len;
+ uint32_t mcast_list_buff_size; /* needed for live migration. */
+
+ /* Compatibility flags for migration */
+ uint32_t compat_flags;
+} VMXNET3State;
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 46a8dbfc90..37cda8e4be 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -28,14 +28,14 @@
#include "net/net.h"
#include "net/checksum.h"
#include "net/util.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include <xen/io/netif.h>
/* ------------------------------------------------------------- */
struct XenNetDev {
- struct XenDevice xendev; /* must be first */
+ struct XenLegacyDevice xendev; /* must be first */
char *mac;
int tx_work;
int tx_ring_ref;
@@ -276,7 +276,7 @@ static NetClientInfo net_xen_info = {
.receive = net_rx_packet,
};
-static int net_init(struct XenDevice *xendev)
+static int net_init(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
@@ -308,7 +308,7 @@ static int net_init(struct XenDevice *xendev)
return 0;
}
-static int net_connect(struct XenDevice *xendev)
+static int net_connect(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
int rx_copy;
@@ -363,7 +363,7 @@ static int net_connect(struct XenDevice *xendev)
return 0;
}
-static void net_disconnect(struct XenDevice *xendev)
+static void net_disconnect(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
@@ -379,14 +379,14 @@ static void net_disconnect(struct XenDevice *xendev)
}
}
-static void net_event(struct XenDevice *xendev)
+static void net_event(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
net_tx_packets(netdev);
qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
}
-static int net_free(struct XenDevice *xendev)
+static int net_free(struct XenLegacyDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c
index 4bb5b601d3..ed5cb28e94 100644
--- a/hw/nios2/boot.c
+++ b/hw/nios2/boot.c
@@ -161,7 +161,7 @@ void nios2_load_kernel(Nios2CPU *cpu, hwaddr ddr_base,
/* If it wasn't an ELF image, try an u-boot image. */
if (kernel_size < 0) {
- hwaddr uentry, loadaddr;
+ hwaddr uentry, loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
kernel_size = load_uimage(kernel_filename, &uentry, &loadaddr, 0,
NULL, NULL);
diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c
index ad7345f288..b6ef463db0 100644
--- a/hw/nvram/ds1225y.c
+++ b/hw/nvram/ds1225y.c
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "trace.h"
+#include "qemu/error-report.h"
typedef struct {
MemoryRegion iomem;
@@ -113,7 +114,7 @@ typedef struct {
NvRamState nvram;
} SysBusNvRamState;
-static int nvram_sysbus_initfn(SysBusDevice *dev)
+static void nvram_sysbus_realize(DeviceState *dev, Error **errp)
{
SysBusNvRamState *sys = DS1225Y(dev);
NvRamState *s = &sys->nvram;
@@ -123,20 +124,18 @@ static int nvram_sysbus_initfn(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &nvram_ops, s,
"nvram", s->chip_size);
- sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
/* Read current file */
file = s->filename ? fopen(s->filename, "rb") : NULL;
if (file) {
/* Read nvram contents */
if (fread(s->contents, s->chip_size, 1, file) != 1) {
- printf("nvram_sysbus_initfn: short read\n");
+ error_report("nvram_sysbus_realize: short read");
}
fclose(file);
}
nvram_post_load(s, 0);
-
- return 0;
}
static Property nvram_sysbus_properties[] = {
@@ -148,9 +147,8 @@ static Property nvram_sysbus_properties[] = {
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->realize = nvram_sysbus_realize;
dc->vmsd = &vmstate_nvram;
dc->props = nvram_sysbus_properties;
}
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 3cb726ff68..53e8e010a8 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -27,7 +27,6 @@
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
#include "hw/boards.h"
-#include "hw/isa/isa.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h"
#include "trace.h"
@@ -68,15 +67,14 @@ static char *read_splashfile(char *filename, gsize *file_sizep,
int *file_typep)
{
GError *err = NULL;
- gboolean res;
gchar *content;
int file_type;
unsigned int filehead;
int bmp_bpp;
- res = g_file_get_contents(filename, &content, file_sizep, &err);
- if (res == FALSE) {
- error_report("failed to read splash file '%s'", filename);
+ if (!g_file_get_contents(filename, &content, file_sizep, &err)) {
+ error_report("failed to read splash file '%s': %s",
+ filename, err->message);
g_error_free(err);
return NULL;
}
@@ -118,47 +116,39 @@ error:
static void fw_cfg_bootsplash(FWCfgState *s)
{
- int boot_splash_time = -1;
const char *boot_splash_filename = NULL;
- char *p;
+ const char *boot_splash_time = NULL;
+ uint8_t qemu_extra_params_fw[2];
char *filename, *file_data;
gsize file_size;
int file_type;
- const char *temp;
/* get user configuration */
QemuOptsList *plist = qemu_find_opts("boot-opts");
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- if (opts != NULL) {
- temp = qemu_opt_get(opts, "splash");
- if (temp != NULL) {
- boot_splash_filename = temp;
- }
- temp = qemu_opt_get(opts, "splash-time");
- if (temp != NULL) {
- p = (char *)temp;
- boot_splash_time = strtol(p, &p, 10);
- }
- }
+ boot_splash_filename = qemu_opt_get(opts, "splash");
+ boot_splash_time = qemu_opt_get(opts, "splash-time");
/* insert splash time if user configurated */
- if (boot_splash_time >= 0) {
+ if (boot_splash_time) {
+ int64_t bst_val = qemu_opt_get_number(opts, "splash-time", -1);
/* validate the input */
- if (boot_splash_time > 0xffff) {
- error_report("splash time is big than 65535, force it to 65535.");
- boot_splash_time = 0xffff;
+ if (bst_val < 0 || bst_val > 0xffff) {
+ error_report("splash-time is invalid,"
+ "it should be a value between 0 and 65535");
+ exit(1);
}
/* use little endian format */
- qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
- qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
+ qemu_extra_params_fw[0] = (uint8_t)(bst_val & 0xff);
+ qemu_extra_params_fw[1] = (uint8_t)((bst_val >> 8) & 0xff);
fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
}
/* insert splash file if user configurated */
- if (boot_splash_filename != NULL) {
+ if (boot_splash_filename) {
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
if (filename == NULL) {
- error_report("failed to find file '%s'.", boot_splash_filename);
+ error_report("failed to find file '%s'", boot_splash_filename);
return;
}
@@ -186,26 +176,25 @@ static void fw_cfg_bootsplash(FWCfgState *s)
static void fw_cfg_reboot(FWCfgState *s)
{
- int reboot_timeout = -1;
- char *p;
- const char *temp;
+ const char *reboot_timeout = NULL;
+ int64_t rt_val = -1;
/* get user configuration */
QemuOptsList *plist = qemu_find_opts("boot-opts");
QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- if (opts != NULL) {
- temp = qemu_opt_get(opts, "reboot-timeout");
- if (temp != NULL) {
- p = (char *)temp;
- reboot_timeout = strtol(p, &p, 10);
+ reboot_timeout = qemu_opt_get(opts, "reboot-timeout");
+
+ if (reboot_timeout) {
+ rt_val = qemu_opt_get_number(opts, "reboot-timeout", -1);
+ /* validate the input */
+ if (rt_val < 0 || rt_val > 0xffff) {
+ error_report("reboot timeout is invalid,"
+ "it should be a value between 0 and 65535");
+ exit(1);
}
}
- /* validate the input */
- if (reboot_timeout > 0xffff) {
- error_report("reboot timeout is larger than 65535, force it to 65535.");
- reboot_timeout = 0xffff;
- }
- fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
+
+ fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&rt_val, 4), 4);
}
static void fw_cfg_write(FWCfgState *s, uint8_t value)
diff --git a/hw/pci-bridge/dec.c b/hw/pci-bridge/dec.c
index 84492d5e5f..8484bfd434 100644
--- a/hw/pci-bridge/dec.c
+++ b/hw/pci-bridge/dec.c
@@ -98,9 +98,10 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
return pci_bridge_get_sec_bus(br);
}
-static int pci_dec_21154_device_init(SysBusDevice *dev)
+static void pci_dec_21154_device_realize(DeviceState *dev, Error **errp)
{
PCIHostState *phb;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
phb = PCI_HOST_BRIDGE(dev);
@@ -108,9 +109,8 @@ static int pci_dec_21154_device_init(SysBusDevice *dev)
dev, "pci-conf-idx", 0x1000);
memory_region_init_io(&phb->data_mem, OBJECT(dev), &pci_host_data_le_ops,
dev, "pci-data-idx", 0x1000);
- sysbus_init_mmio(dev, &phb->conf_mem);
- sysbus_init_mmio(dev, &phb->data_mem);
- return 0;
+ sysbus_init_mmio(sbd, &phb->conf_mem);
+ sysbus_init_mmio(sbd, &phb->data_mem);
}
static void dec_21154_pci_host_realize(PCIDevice *d, Error **errp)
@@ -150,9 +150,9 @@ static const TypeInfo dec_21154_pci_host_info = {
static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = pci_dec_21154_device_init;
+ dc->realize = pci_dec_21154_device_realize;
}
static const TypeInfo pci_dec_21154_device_info = {
diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c
index 299de429ec..9766edb445 100644
--- a/hw/pci-bridge/gen_pcie_root_port.c
+++ b/hw/pci-bridge/gen_pcie_root_port.c
@@ -124,6 +124,10 @@ static Property gen_rp_props[] = {
res_reserve.mem_pref_32, -1),
DEFINE_PROP_SIZE("pref64-reserve", GenPCIERootPort,
res_reserve.mem_pref_64, -1),
+ DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
+ speed, PCIE_LINK_SPEED_16),
+ DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
+ width, PCIE_LINK_WIDTH_32),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 97a8e8b6a4..ff6b8323da 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -206,31 +206,39 @@ static const VMStateDescription pci_bridge_dev_vmstate = {
}
};
-static void pci_bridge_dev_hotplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
+void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCI_BRIDGE_DEV);
+ "this %s", object_get_typename(OBJECT(hotplug_dev)));
return;
}
- shpc_device_hotplug_cb(hotplug_dev, dev, errp);
+ shpc_device_plug_cb(hotplug_dev, dev, errp);
}
-static void pci_bridge_dev_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev,
- Error **errp)
+void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
+
+ g_assert(shpc_present(pci_hotplug_dev));
+ shpc_device_unplug_cb(hotplug_dev, dev, errp);
+}
+
+void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
{
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
if (!shpc_present(pci_hotplug_dev)) {
error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCI_BRIDGE_DEV);
+ "this %s", object_get_typename(OBJECT(hotplug_dev)));
return;
}
- shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
+ shpc_device_unplug_request_cb(hotplug_dev, dev, errp);
}
static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
@@ -251,8 +259,9 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
dc->props = pci_bridge_dev_properties;
dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- hc->plug = pci_bridge_dev_hotplug_cb;
- hc->unplug_request = pci_bridge_dev_hot_unplug_request_cb;
+ hc->plug = pci_bridge_dev_plug_cb;
+ hc->unplug = pci_bridge_dev_unplug_cb;
+ hc->unplug_request = pci_bridge_dev_unplug_request_cb;
}
static const TypeInfo pci_bridge_dev_info = {
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index 04cf5a6a92..d491b40d04 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -137,33 +137,6 @@ static const VMStateDescription pcie_pci_bridge_dev_vmstate = {
}
};
-static void pcie_pci_bridge_hotplug_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
-{
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
-
- if (!shpc_present(pci_hotplug_dev)) {
- error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
- return;
- }
- shpc_device_hotplug_cb(hotplug_dev, dev, errp);
-}
-
-static void pcie_pci_bridge_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev,
- Error **errp)
-{
- PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
-
- if (!shpc_present(pci_hotplug_dev)) {
- error_setg(errp, "standard hotplug controller has been disabled for "
- "this %s", TYPE_PCIE_PCI_BRIDGE_DEV);
- return;
- }
- shpc_device_hot_unplug_request_cb(hotplug_dev, dev, errp);
-}
-
static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -180,8 +153,9 @@ static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
dc->props = pcie_pci_bridge_dev_properties;
dc->reset = &pcie_pci_bridge_reset;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- hc->plug = pcie_pci_bridge_hotplug_cb;
- hc->unplug_request = pcie_pci_bridge_hot_unplug_request_cb;
+ hc->plug = pci_bridge_dev_plug_cb;
+ hc->unplug = pci_bridge_dev_unplug_cb;
+ hc->unplug_request = pci_bridge_dev_unplug_request_cb;
}
static const TypeInfo pcie_pci_bridge_info = {
diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c
index 45f9e8cd4a..34ad76743c 100644
--- a/hw/pci-bridge/pcie_root_port.c
+++ b/hw/pci-bridge/pcie_root_port.c
@@ -140,6 +140,19 @@ static Property rp_props[] = {
DEFINE_PROP_END_OF_LIST()
};
+static void rp_instance_post_init(Object *obj)
+{
+ PCIESlot *s = PCIE_SLOT(obj);
+
+ if (!s->speed) {
+ s->speed = QEMU_PCI_EXP_LNK_2_5GT;
+ }
+
+ if (!s->width) {
+ s->width = QEMU_PCI_EXP_LNK_X1;
+ }
+}
+
static void rp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -157,6 +170,7 @@ static void rp_class_init(ObjectClass *klass, void *data)
static const TypeInfo rp_info = {
.name = TYPE_PCIE_ROOT_PORT,
.parent = TYPE_PCIE_SLOT,
+ .instance_post_init = rp_instance_post_init,
.class_init = rp_class_init,
.abstract = true,
.class_size = sizeof(PCIERootPortClass),
diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
index e361ecb7ee..aa5ecfd0c2 100644
--- a/hw/pci-host/pam.c
+++ b/hw/pci-host/pam.c
@@ -52,11 +52,13 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory,
memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory,
start, size);
+ memory_region_transaction_begin();
for (i = 0; i < 4; ++i) {
memory_region_set_enabled(&mem->alias[i], false);
memory_region_add_subregion_overlap(system_memory, start,
&mem->alias[i], 1);
}
+ memory_region_transaction_commit();
mem->current = 0;
}
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 702dac4ec7..4e336416a7 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -345,7 +345,7 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
char *name;
uint32_t bar_size = 4096;
uint32_t bar_pba_offset = bar_size / 2;
- uint32_t bar_pba_size = (nentries / 8 + 1) * 8;
+ uint32_t bar_pba_size = QEMU_ALIGN_UP(nentries, 64) / 8;
/*
* Migration compatibility dictates that this remains a 4k
@@ -501,7 +501,7 @@ void msix_reset(PCIDevice *dev)
}
msix_clear_all_vectors(dev);
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
- ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
+ ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
memset(dev->msix_pba, 0, QEMU_ALIGN_UP(dev->msix_entries_nr, 64) / 8);
msix_mask_all(dev, dev->msix_entries_nr);
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 56b13b3320..c9fc2fbe19 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -211,13 +211,13 @@ int pci_bar(PCIDevice *d, int reg)
static inline int pci_irq_state(PCIDevice *d, int irq_num)
{
- return (d->irq_state >> irq_num) & 0x1;
+ return (d->irq_state >> irq_num) & 0x1;
}
static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
{
- d->irq_state &= ~(0x1 << irq_num);
- d->irq_state |= level << irq_num;
+ d->irq_state &= ~(0x1 << irq_num);
+ d->irq_state |= level << irq_num;
}
static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
@@ -333,6 +333,13 @@ static void pci_host_bus_register(DeviceState *host)
QLIST_INSERT_HEAD(&pci_host_bridges, host_bridge, next);
}
+static void pci_host_bus_unregister(DeviceState *host)
+{
+ PCIHostState *host_bridge = PCI_HOST_BRIDGE(host);
+
+ QLIST_REMOVE(host_bridge, next);
+}
+
PCIBus *pci_device_root_bus(const PCIDevice *d)
{
PCIBus *bus = pci_get_bus(d);
@@ -379,6 +386,11 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent,
pci_host_bus_register(parent);
}
+static void pci_bus_uninit(PCIBus *bus)
+{
+ pci_host_bus_unregister(BUS(bus)->parent);
+}
+
bool pci_bus_is_express(PCIBus *bus)
{
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
@@ -413,6 +425,12 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name,
return bus;
}
+void pci_root_bus_cleanup(PCIBus *bus)
+{
+ pci_bus_uninit(bus);
+ object_unparent(OBJECT(bus));
+}
+
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq)
{
@@ -423,6 +441,15 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
bus->irq_count = g_malloc0(nirq * sizeof(bus->irq_count[0]));
}
+void pci_bus_irqs_cleanup(PCIBus *bus)
+{
+ bus->set_irq = NULL;
+ bus->map_irq = NULL;
+ bus->irq_opaque = NULL;
+ bus->nirq = 0;
+ g_free(bus->irq_count);
+}
+
PCIBus *pci_register_root_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque,
@@ -439,6 +466,12 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name,
return bus;
}
+void pci_unregister_root_bus(PCIBus *bus)
+{
+ pci_bus_irqs_cleanup(bus);
+ pci_root_bus_cleanup(bus);
+}
+
int pci_bus_num(PCIBus *s)
{
return PCI_BUS_GET_CLASS(s)->bus_num(s);
@@ -571,8 +604,8 @@ const VMStateDescription vmstate_pci_device = {
0, vmstate_info_pci_config,
PCIE_CONFIG_SPACE_SIZE),
VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
- vmstate_info_pci_irq_state,
- PCI_NUM_PINS * sizeof(int32_t)),
+ vmstate_info_pci_irq_state,
+ PCI_NUM_PINS * sizeof(int32_t)),
VMSTATE_END_OF_LIST()
}
};
@@ -624,21 +657,21 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
p = addr;
val = strtoul(p, &e, 16);
if (e == p)
- return -1;
+ return -1;
if (*e == ':') {
- bus = val;
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
- if (*e == ':') {
- dom = bus;
- bus = val;
- p = e + 1;
- val = strtoul(p, &e, 16);
- if (e == p)
- return -1;
- }
+ bus = val;
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ if (*e == ':') {
+ dom = bus;
+ bus = val;
+ p = e + 1;
+ val = strtoul(p, &e, 16);
+ if (e == p)
+ return -1;
+ }
}
slot = val;
@@ -657,10 +690,10 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp,
/* if funcp == NULL func is 0 */
if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
- return -1;
+ return -1;
if (*e)
- return -1;
+ return -1;
*domp = dom;
*busp = bus;
@@ -1217,7 +1250,7 @@ pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
}
static pcibus_t pci_bar_address(PCIDevice *d,
- int reg, uint8_t type, pcibus_t size)
+ int reg, uint8_t type, pcibus_t size)
{
pcibus_t new_addr, last_addr;
int bar = pci_bar(d, reg);
@@ -1353,6 +1386,10 @@ uint32_t pci_default_read_config(PCIDevice *d,
{
uint32_t val = 0;
+ if (pci_is_express_downstream_port(d) &&
+ ranges_overlap(address, len, d->exp.exp_cap + PCI_EXP_LNKSTA, 2)) {
+ pcie_sync_bridge_lnk(d);
+ }
memcpy(&val, d->config + address, len);
return le32_to_cpu(val);
}
@@ -2261,7 +2298,11 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom,
pdev->has_rom = true;
memory_region_init_rom(&pdev->rom, OBJECT(pdev), name, size, &error_fatal);
ptr = memory_region_get_ram_ptr(&pdev->rom);
- load_image(path, ptr);
+ if (load_image_size(path, ptr, size) < 0) {
+ error_setg(errp, "failed to load romfile \"%s\"", pdev->romfile);
+ g_free(path);
+ return;
+ }
g_free(path);
if (is_default_rom) {
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index ee9dff2d3a..c6d9ded320 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -241,9 +241,9 @@ void pci_bridge_update_mappings(PCIBridge *br)
* while another accesses an unaffected region. */
memory_region_transaction_begin();
pci_bridge_region_del(br, br->windows);
+ pci_bridge_region_cleanup(br, w);
br->windows = pci_bridge_region_init(br);
memory_region_transaction_commit();
- pci_bridge_region_cleanup(br, w);
}
/* default write_config function for PCI-to-PCI bridge */
@@ -369,7 +369,7 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
* let users address the bus using the device name.
*/
if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
- br->bus_name = dev->qdev.id;
+ br->bus_name = dev->qdev.id;
}
qbus_create_inplace(sec_bus, sizeof(br->sec_bus), typename, DEVICE(dev),
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index 5eaa935cb5..5f5345dbac 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "hw/pci/pci.h"
+#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pci_bus.h"
#include "trace.h"
@@ -50,9 +51,29 @@ static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
return pci_find_device(bus, bus_num, devfn);
}
+static void pci_adjust_config_limit(PCIBus *bus, uint32_t *limit)
+{
+ if (*limit > PCI_CONFIG_SPACE_SIZE) {
+ if (!pci_bus_is_express(bus)) {
+ *limit = PCI_CONFIG_SPACE_SIZE;
+ return;
+ }
+
+ if (!pci_bus_is_root(bus)) {
+ PCIDevice *bridge = pci_bridge_get_device(bus);
+ pci_adjust_config_limit(pci_get_bus(bridge), limit);
+ }
+ }
+}
+
void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
uint32_t limit, uint32_t val, uint32_t len)
{
+ pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
+ if (limit <= addr) {
+ return;
+ }
+
assert(len <= 4);
/* non-zero functions are only exposed when function 0 is present,
* allowing direct removal of unexposed functions.
@@ -71,6 +92,11 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
{
uint32_t ret;
+ pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
+ if (limit <= addr) {
+ return ~0x0;
+ }
+
assert(len <= 4);
/* non-zero functions are only exposed when function 0 is present,
* allowing direct removal of unexposed functions.
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 6c91bd44a0..230478faab 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -27,6 +27,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pcie_regs.h"
+#include "hw/pci/pcie_port.h"
#include "qemu/range.h"
//#define DEBUG_PCIE
@@ -68,11 +69,12 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_long(exp_cap + PCI_EXP_LNKCAP,
(port << PCI_EXP_LNKCAP_PN_SHIFT) |
PCI_EXP_LNKCAP_ASPMS_0S |
- PCI_EXP_LNK_MLW_1 |
- PCI_EXP_LNK_LS_25);
+ QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
+ QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT));
pci_set_word(exp_cap + PCI_EXP_LNKSTA,
- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
+ QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1) |
+ QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT));
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
@@ -86,6 +88,76 @@ pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
}
+static void pcie_cap_fill_slot_lnk(PCIDevice *dev)
+{
+ PCIESlot *s = (PCIESlot *)object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT);
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
+
+ /* Skip anything that isn't a PCIESlot */
+ if (!s) {
+ return;
+ }
+
+ /* Clear and fill LNKCAP from what was configured above */
+ pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ QEMU_PCI_EXP_LNKCAP_MLW(s->width) |
+ QEMU_PCI_EXP_LNKCAP_MLS(s->speed));
+
+ /*
+ * Link bandwidth notification is required for all root ports and
+ * downstream ports supporting links wider than x1 or multiple link
+ * speeds.
+ */
+ if (s->width > QEMU_PCI_EXP_LNK_X1 ||
+ s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_LBNC);
+ }
+
+ if (s->speed > QEMU_PCI_EXP_LNK_2_5GT) {
+ /*
+ * Hot-plug capable downstream ports and downstream ports supporting
+ * link speeds greater than 5GT/s must hardwire PCI_EXP_LNKCAP_DLLLARC
+ * to 1b. PCI_EXP_LNKCAP_DLLLARC implies PCI_EXP_LNKSTA_DLLLA, which
+ * we also hardwire to 1b here. 2.5GT/s hot-plug slots should also
+ * technically implement this, but it's not done here for compatibility.
+ */
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP,
+ PCI_EXP_LNKCAP_DLLLARC);
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_DLLLA);
+
+ /*
+ * Target Link Speed defaults to the highest link speed supported by
+ * the component. 2.5GT/s devices are permitted to hardwire to zero.
+ */
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS);
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKCTL2,
+ QEMU_PCI_EXP_LNKCAP_MLS(s->speed) &
+ PCI_EXP_LNKCTL2_TLS);
+ }
+
+ /*
+ * 2.5 & 5.0GT/s can be fully described by LNKCAP, but 8.0GT/s is
+ * actually a reference to the highest bit supported in this register.
+ * We assume the device supports all link speeds.
+ */
+ if (s->speed > QEMU_PCI_EXP_LNK_5GT) {
+ pci_long_test_and_clear_mask(exp_cap + PCI_EXP_LNKCAP2, ~0U);
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
+ PCI_EXP_LNKCAP2_SLS_2_5GB |
+ PCI_EXP_LNKCAP2_SLS_5_0GB |
+ PCI_EXP_LNKCAP2_SLS_8_0GB);
+ if (s->speed > QEMU_PCI_EXP_LNK_8GT) {
+ pci_long_test_and_set_mask(exp_cap + PCI_EXP_LNKCAP2,
+ PCI_EXP_LNKCAP2_SLS_16_0GB);
+ }
+ }
+}
+
int pcie_cap_init(PCIDevice *dev, uint8_t offset,
uint8_t type, uint8_t port,
Error **errp)
@@ -107,6 +179,9 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset,
/* Filling values common with v1 */
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
+ /* Fill link speed and width options */
+ pcie_cap_fill_slot_lnk(dev);
+
/* Filling v2 specific values */
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
PCI_EXP_DEVCAP2_EFF | PCI_EXP_DEVCAP2_EETLPP);
@@ -315,12 +390,11 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
hotplug_event_notify(dev);
}
-static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
- DeviceState *dev,
- uint8_t **exp_cap, Error **errp)
+static void pcie_cap_slot_plug_common(PCIDevice *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
- *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
- uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
+ uint8_t *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
+ uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: 0x%x\n", sltsta);
if (sltsta & PCI_EXP_SLTSTA_EIS) {
@@ -331,13 +405,18 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
}
}
-void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp)
+void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
- uint8_t *exp_cap;
- PCIDevice *pci_dev = PCI_DEVICE(dev);
+ pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, errp);
+}
- pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
+void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ PCIDevice *hotplug_pdev = PCI_DEVICE(hotplug_dev);
+ uint8_t *exp_cap = hotplug_pdev->config + hotplug_pdev->exp.exp_cap;
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
/* 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
@@ -345,6 +424,10 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
if (!dev->hotplugged) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
+ if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_DLLLA);
+ }
return;
}
@@ -355,24 +438,40 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
if (pci_get_function_0(pci_dev)) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
+ if (pci_dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_DLLLA);
+ }
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev),
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
}
}
-static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
+void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
object_unparent(OBJECT(dev));
}
-void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
+static void pcie_unplug_device(PCIBus *bus, PCIDevice *dev, void *opaque)
{
- uint8_t *exp_cap;
+ HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(dev));
+
+ hotplug_handler_unplug(hotplug_ctrl, DEVICE(dev), &error_abort);
+}
+
+void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ Error *local_err = NULL;
PCIDevice *pci_dev = PCI_DEVICE(dev);
PCIBus *bus = pci_get_bus(pci_dev);
- pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
+ pcie_cap_slot_plug_common(PCI_DEVICE(hotplug_dev), dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
/* In case user cancel the operation of multi-function hot-add,
* remove the function that is unexposed to guest individually,
@@ -531,6 +630,10 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
+ if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_DLLLA);
+ }
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDC);
}
@@ -728,6 +831,45 @@ void pcie_add_capability(PCIDevice *dev,
memset(dev->cmask + offset, 0xFF, size);
}
+/*
+ * Sync the PCIe Link Status negotiated speed and width of a bridge with the
+ * downstream device. If downstream device is not present, re-write with the
+ * Link Capability fields. Limit width and speed to bridge capabilities for
+ * compatibility. Use config_read to access the downstream device since it
+ * could be an assigned device with volatile link information.
+ */
+void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
+{
+ PCIBridge *br = PCI_BRIDGE(bridge_dev);
+ PCIBus *bus = pci_bridge_get_sec_bus(br);
+ PCIDevice *target = bus->devices[0];
+ uint8_t *exp_cap = bridge_dev->config + bridge_dev->exp.exp_cap;
+ uint16_t lnksta, lnkcap = pci_get_word(exp_cap + PCI_EXP_LNKCAP);
+
+ if (!target || !target->exp.exp_cap) {
+ lnksta = lnkcap;
+ } else {
+ lnksta = target->config_read(target,
+ target->exp.exp_cap + PCI_EXP_LNKSTA,
+ sizeof(lnksta));
+
+ if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
+ lnksta &= ~PCI_EXP_LNKSTA_NLW;
+ lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
+ }
+
+ if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
+ lnksta &= ~PCI_EXP_LNKSTA_CLS;
+ lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
+ }
+ }
+
+ pci_word_test_and_clear_mask(exp_cap + PCI_EXP_LNKSTA,
+ PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
+ pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA, lnksta &
+ (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW));
+}
+
/**************************************************************************
* pci express extended capability helper functions
*/
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 6432b9ac1f..a30291ef54 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -154,8 +154,10 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
dc->props = pcie_slot_props;
- hc->plug = pcie_cap_slot_hotplug_cb;
- hc->unplug_request = pcie_cap_slot_hot_unplug_request_cb;
+ hc->pre_plug = pcie_cap_slot_pre_plug_cb;
+ hc->plug = pcie_cap_slot_plug_cb;
+ hc->unplug = pcie_cap_slot_unplug_cb;
+ hc->unplug_request = pcie_cap_slot_unplug_request_cb;
}
static const TypeInfo pcie_slot_type_info = {
diff --git a/hw/pci/shpc.c b/hw/pci/shpc.c
index 96a43d2f70..45053b39b9 100644
--- a/hw/pci/shpc.c
+++ b/hw/pci/shpc.c
@@ -238,6 +238,7 @@ static void shpc_invalid_command(SHPCDevice *shpc)
static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
{
+ HotplugHandler *hotplug_ctrl;
int devfn;
int pci_slot = SHPC_IDX_TO_PCI(slot);
for (devfn = PCI_DEVFN(pci_slot, 0);
@@ -245,7 +246,9 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
if (affected_dev) {
- object_unparent(OBJECT(affected_dev));
+ hotplug_ctrl = qdev_get_hotplug_handler(DEVICE(affected_dev));
+ hotplug_handler_unplug(hotplug_ctrl, DEVICE(affected_dev),
+ &error_abort);
}
}
}
@@ -482,8 +485,8 @@ static const MemoryRegionOps shpc_mmio_ops = {
.max_access_size = 4,
},
};
-static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
- SHPCDevice *shpc, Error **errp)
+static void shpc_device_plug_common(PCIDevice *affected_dev, int *slot,
+ SHPCDevice *shpc, Error **errp)
{
int pci_slot = PCI_SLOT(affected_dev->devfn);
*slot = SHPC_PCI_TO_IDX(pci_slot);
@@ -497,7 +500,7 @@ static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
}
}
-void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
Error *local_err = NULL;
@@ -505,7 +508,7 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
SHPCDevice *shpc = pci_hotplug_dev->shpc;
int slot;
- shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
+ shpc_device_plug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -540,8 +543,14 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
shpc_interrupt_update(pci_hotplug_dev);
}
-void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
+void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ object_unparent(OBJECT(dev));
+}
+
+void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
{
Error *local_err = NULL;
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
@@ -550,7 +559,7 @@ void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
uint8_t led;
int slot;
- shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
+ shpc_device_plug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index e6747fce28..0581e9e3d4 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -685,7 +685,7 @@ static void ppce500_cpu_reset(void *opaque)
}
static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
- qemu_irq **irqs)
+ IrqLines *irqs)
{
DeviceState *dev;
SysBusDevice *s;
@@ -705,7 +705,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
- sysbus_connect_irq(s, k++, irqs[i][j]);
+ sysbus_connect_irq(s, k++, irqs[i].irq[j]);
}
}
@@ -713,7 +713,7 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
}
static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
- qemu_irq **irqs, Error **errp)
+ IrqLines *irqs, Error **errp)
{
Error *err = NULL;
DeviceState *dev;
@@ -742,7 +742,7 @@ static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
MemoryRegion *ccsr,
- qemu_irq **irqs)
+ IrqLines *irqs)
{
MachineState *machine = MACHINE(pms);
const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
@@ -806,15 +806,14 @@ void ppce500_init(MachineState *machine)
/* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
* 4 respectively */
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
- qemu_irq **irqs;
+ IrqLines *irqs;
DeviceState *dev, *mpicdev;
CPUPPCState *firstenv = NULL;
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
PPCE500CCSRState *ccsr;
- irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
- irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+ irqs = g_new0(IrqLines, smp_cpus);
for (i = 0; i < smp_cpus; i++) {
PowerPCCPU *cpu;
CPUState *cs;
@@ -834,10 +833,9 @@ void ppce500_init(MachineState *machine)
firstenv = env;
}
- irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
input = (qemu_irq *)env->irq_inputs;
- irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
- irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
+ irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
+ irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
@@ -997,6 +995,7 @@ void ppce500_init(MachineState *machine)
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
* ePAPR compliant kernel
*/
+ loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
NULL, NULL);
if (payload_size < 0) {
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 14273a123e..bb19eaba36 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -115,7 +115,7 @@ static void ppc_core99_init(MachineState *machine)
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
char *filename;
- qemu_irq **openpic_irqs;
+ IrqLines *openpic_irqs;
int linux_boot, i, j, k;
MemoryRegion *ram = g_new(MemoryRegion, 1), *bios = g_new(MemoryRegion, 1);
hwaddr kernel_base, initrd_base, cmdline_base = 0;
@@ -127,8 +127,7 @@ static void ppc_core99_init(MachineState *machine)
MACIOIDEState *macio_ide;
BusState *adb_bus;
MacIONVRAMState *nvr;
- int bios_size, ndrv_size;
- uint8_t *ndrv_file;
+ int bios_size;
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
@@ -249,41 +248,37 @@ static void ppc_core99_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), 0xf8000000,
sysbus_mmio_get_region(s, 0));
- openpic_irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
- openpic_irqs[0] =
- g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+ openpic_irqs = g_new0(IrqLines, smp_cpus);
for (i = 0; i < smp_cpus; i++) {
/* Mac99 IRQ connection between OpenPIC outputs pins
* and PowerPC input pins
*/
switch (PPC_INPUT(env)) {
case PPC_FLAGS_INPUT_6xx:
- openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
- openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
/* Not connected ? */
- openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
- openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
break;
#if defined(TARGET_PPC64)
case PPC_FLAGS_INPUT_970:
- openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
- openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
- openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
/* Not connected ? */
- openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
/* Check this */
- openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+ openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
break;
#endif /* defined(TARGET_PPC64) */
@@ -300,7 +295,7 @@ static void ppc_core99_init(MachineState *machine)
k = 0;
for (i = 0; i < smp_cpus; i++) {
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
- sysbus_connect_irq(s, k++, openpic_irqs[i][j]);
+ sysbus_connect_irq(s, k++, openpic_irqs[i].irq[j]);
}
}
g_free(openpic_irqs);
@@ -510,11 +505,10 @@ static void ppc_core99_init(MachineState *machine)
/* MacOS NDRV VGA driver */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME);
if (filename) {
- ndrv_size = get_image_size(filename);
- if (ndrv_size != -1) {
- ndrv_file = g_malloc(ndrv_size);
- ndrv_size = load_image(filename, ndrv_file);
+ gchar *ndrv_file;
+ gsize ndrv_size;
+ if (g_file_get_contents(filename, &ndrv_file, &ndrv_size, NULL)) {
fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size);
}
g_free(filename);
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 9891c325a9..817f70e52c 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -99,8 +99,7 @@ static void ppc_heathrow_init(MachineState *machine)
SysBusDevice *s;
DeviceState *dev, *pic_dev;
BusState *adb_bus;
- int bios_size, ndrv_size;
- uint8_t *ndrv_file;
+ int bios_size;
uint16_t ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
@@ -361,11 +360,10 @@ static void ppc_heathrow_init(MachineState *machine)
/* MacOS NDRV VGA driver */
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, NDRV_VGA_FILENAME);
if (filename) {
- ndrv_size = get_image_size(filename);
- if (ndrv_size != -1) {
- ndrv_file = g_malloc(ndrv_size);
- ndrv_size = load_image(filename, ndrv_file);
+ gchar *ndrv_file;
+ gsize ndrv_size;
+ if (g_file_get_contents(filename, &ndrv_file, &ndrv_size, NULL)) {
fw_cfg_add_file(fw_cfg, "ndrv/qemu_vga.ndrv", ndrv_file, ndrv_size);
}
g_free(filename);
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 346f5e7aed..d84acef55b 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -668,11 +668,20 @@ static uint32_t pnv_chip_core_pir_p8(PnvChip *chip, uint32_t core_id)
return (chip->chip_id << 7) | (core_id << 3);
}
-static Object *pnv_chip_power8_intc_create(PnvChip *chip, Object *child,
- Error **errp)
+static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
+ Error **errp)
{
- return icp_create(child, TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
- errp);
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = icp_create(OBJECT(cpu), TYPE_PNV_ICP, XICS_FABRIC(qdev_get_machine()),
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cpu->icp = ICP(obj);
}
/*
@@ -690,10 +699,10 @@ static uint32_t pnv_chip_core_pir_p9(PnvChip *chip, uint32_t core_id)
return (chip->chip_id << 8) | (core_id << 2);
}
-static Object *pnv_chip_power9_intc_create(PnvChip *chip, Object *child,
- Error **errp)
+static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
+ Error **errp)
{
- return NULL;
+ return;
}
/* Allowed core identifiers on a POWER8 Processor Chip :
@@ -1090,7 +1099,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
{
PowerPCCPU *cpu = ppc_get_vcpu_by_pir(pir);
- return cpu ? ICP(cpu->intc) : NULL;
+ return cpu ? cpu->icp : NULL;
}
static void pnv_pic_print_info(InterruptStatsProvider *obj,
@@ -1103,7 +1112,7 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- icp_pic_print_info(ICP(cpu->intc), mon);
+ icp_pic_print_info(cpu->icp, mon);
}
for (i = 0; i < pnv->num_chips; i++) {
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index ad1bcc7990..b98f277f1e 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -114,7 +114,7 @@ static void pnv_realize_vcpu(PowerPCCPU *cpu, PnvChip *chip, Error **errp)
return;
}
- cpu->intc = pcc->intc_create(chip, OBJECT(cpu), &local_err);
+ pcc->intc_create(chip, cpu, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -190,7 +190,7 @@ err:
static void pnv_unrealize_vcpu(PowerPCCPU *cpu)
{
qemu_unregister_reset(pnv_cpu_reset, cpu);
- object_unparent(cpu->intc);
+ object_unparent(OBJECT(cpu->icp));
cpu_remove_sync(CPU(cpu));
object_unparent(OBJECT(cpu));
}
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 5b969127c3..8ced095063 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -207,7 +207,6 @@ static const uint64_t stat_bits[] = {
void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
{
- ICSState *ics = &psi->ics;
uint32_t xivr_reg;
uint32_t stat_reg;
uint32_t src;
@@ -227,14 +226,14 @@ void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state)
/* TODO: optimization, check mask here. That means
* re-evaluating when unmasking
*/
- qemu_irq_raise(ics->qirqs[src]);
+ qemu_irq_raise(psi->qirqs[src]);
} else {
psi->regs[stat_reg] &= ~stat_bits[irq];
/* FSP and PSI are muxed so don't lower if either is still set */
if (stat_reg != PSIHB_XSCOM_CR ||
!(psi->regs[stat_reg] & (PSIHB_CR_PSI_IRQ | PSIHB_CR_FSP_IRQ))) {
- qemu_irq_lower(ics->qirqs[src]);
+ qemu_irq_lower(psi->qirqs[src]);
} else {
state = true;
}
@@ -491,6 +490,8 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp)
ics_set_irq_type(ics, i, true);
}
+ psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs);
+
/* XSCOM region for PSI registers */
pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops,
psi, "xscom-psi", PNV_XSCOM_PSIHB_SIZE);
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index 3be3fe4432..f47b15f10e 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -149,7 +149,7 @@ static void ref405ep_init(MachineState *machine)
MemoryRegion *bios;
MemoryRegion *sram = g_new(MemoryRegion, 1);
ram_addr_t bdloc;
- MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
+ MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
hwaddr ram_bases[2], ram_sizes[2];
target_ulong sram_size;
long bios_size;
@@ -219,9 +219,11 @@ static void ref405ep_init(MachineState *machine)
bios_name = BIOS_FILENAME;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
- bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+ bios_size = load_image_size(filename,
+ memory_region_get_ram_ptr(bios),
+ BIOS_SIZE);
g_free(filename);
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ if (bios_size < 0) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
@@ -446,7 +448,7 @@ static void taihu_405ep_init(MachineState *machine)
qemu_irq *pic;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *bios;
- MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
+ MemoryRegion *ram_memories = g_new(MemoryRegion, 2);
MemoryRegion *ram = g_malloc0(sizeof(*ram));
hwaddr ram_bases[2], ram_sizes[2];
long bios_size;
@@ -515,9 +517,11 @@ static void taihu_405ep_init(MachineState *machine)
&error_fatal);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
- bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
+ bios_size = load_image_size(filename,
+ memory_region_get_ram_ptr(bios),
+ BIOS_SIZE);
g_free(filename);
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ if (bios_size < 0) {
error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 5c58415cf1..8d3a797cb8 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -1519,7 +1519,7 @@ CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
/* OBP arbitrer */
ppc4xx_opba_init(0xef600600);
/* Universal interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
irqs[PPCUIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
irqs[PPCUIC_OUTPUT_CINT] =
@@ -1877,7 +1877,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
/* Initialize timers */
ppc_booke_timers_init(cpu, sysclk, 0);
/* Universal interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs = g_new0(qemu_irq, PPCUIC_OUTPUT_NB);
irqs[PPCUIC_OUTPUT_INT] =
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
irqs[PPCUIC_OUTPUT_CINT] =
@@ -1885,7 +1885,7 @@ CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
*picp = pic;
/* SDRAM controller */
- /* XXX 405EP has no ECC interrupt */
+ /* XXX 405EP has no ECC interrupt */
ppc4xx_sdram_init(env, pic[17], 2, ram_memories,
ram_bases, ram_sizes, do_init);
/* External bus controller */
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index f5720f979e..fc06191588 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -169,8 +169,7 @@ static void bamboo_init(MachineState *machine)
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1);
- MemoryRegion *ram_memories
- = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
+ MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
qemu_irq *pic;
@@ -180,7 +179,7 @@ static void bamboo_init(MachineState *machine)
CPUPPCState *env;
uint64_t elf_entry;
uint64_t elf_lowaddr;
- hwaddr loadaddr = 0;
+ hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
target_long initrd_size = 0;
DeviceState *dev;
int success;
@@ -200,7 +199,7 @@ static void bamboo_init(MachineState *machine)
ppc_dcr_init(env, NULL, NULL);
/* interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs = g_new0(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);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 8c6f3c9577..9b6e4c60fa 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -32,8 +32,7 @@
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
-#define DEBUG_UIC
-
+/*#define DEBUG_UIC*/
#ifdef DEBUG_UIC
# define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 2afb7f437e..7bda86a7d0 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -538,7 +538,7 @@ static void ppc_prep_init(MachineState *machine)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
if (nd_table[i].model == NULL) {
- nd_table[i].model = g_strdup("ne2k_isa");
+ nd_table[i].model = g_strdup("ne2k_isa");
}
if (strcmp(nd_table[i].model, "ne2k_isa") == 0) {
isa_ne2000_init(isa_bus, ne2000_io[i], ne2000_irq[i],
@@ -552,7 +552,7 @@ static void ppc_prep_init(MachineState *machine)
for(i = 0; i < MAX_IDE_BUS; i++) {
isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[2 * i],
- hd[2 * i + 1]);
+ hd[2 * i + 1]);
}
cpu = POWERPC_CPU(first_cpu);
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 5aac58f36e..84ea592749 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -402,7 +402,7 @@ static void sam460ex_init(MachineState *machine)
CPUPPCState *env;
PPC4xxI2CState *i2c[2];
hwaddr entry = UBOOT_ENTRY;
- hwaddr loadaddr = 0;
+ hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
target_long initrd_size = 0;
DeviceState *dev;
SysBusDevice *sbdev;
@@ -430,7 +430,7 @@ static void sam460ex_init(MachineState *machine)
ppc4xx_plb_init(env);
/* interrupt controllers */
- irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
+ irqs = g_new0(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];
uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 7afd1a175b..0942f35bf8 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -70,7 +70,6 @@
#include "hw/nmi.h"
#include "hw/intc/intc.h"
-#include "hw/compat.h"
#include "qemu/cutils.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/mem/memory-device.h"
@@ -150,7 +149,7 @@ static void pre_2_10_vmstate_unregister_dummy_icp(int i)
(void *)(uintptr_t) i);
}
-static int xics_max_server_number(sPAPRMachineState *spapr)
+int spapr_max_server_number(sPAPRMachineState *spapr)
{
assert(spapr->vsmt);
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
@@ -889,8 +888,6 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
/* ibm,associativity-lookup-arrays */
buf_len = (nr_nodes * 4 + 2) * sizeof(uint32_t);
cur_index = int_buf = g_malloc0(buf_len);
-
- cur_index = int_buf;
int_buf[0] = cpu_to_be32(nr_nodes);
int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
cur_index += 2;
@@ -1033,7 +1030,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
cpu_to_be32(0),
cpu_to_be32(0),
cpu_to_be32(0),
- cpu_to_be32(nb_numa_nodes ? nb_numa_nodes - 1 : 0),
+ cpu_to_be32(nb_numa_nodes ? nb_numa_nodes : 1),
};
_FDT(rtas = fdt_add_subnode(fdt, 0, "rtas"));
@@ -1051,6 +1048,7 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
add_str(hypertas, "hcall-sprg0");
add_str(hypertas, "hcall-copy");
add_str(hypertas, "hcall-debug");
+ add_str(hypertas, "hcall-vphn");
add_str(qemu_hypertas, "hcall-memop1");
if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
@@ -1097,15 +1095,18 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt)
spapr_dt_rtas_tokens(fdt, rtas);
}
-/* Prepare ibm,arch-vec-5-platform-support, which indicates the MMU features
- * that the guest may request and thus the valid values for bytes 24..26 of
- * option vector 5: */
-static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
+/*
+ * Prepare ibm,arch-vec-5-platform-support, which indicates the MMU
+ * and the XIVE features that the guest may request and thus the valid
+ * values for bytes 23..26 of option vector 5:
+ */
+static void spapr_dt_ov5_platform_support(sPAPRMachineState *spapr, void *fdt,
+ int chosen)
{
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
char val[2 * 4] = {
- 23, 0x00, /* Xive mode, filled in below. */
+ 23, spapr->irq->ov5, /* Xive mode. */
24, 0x00, /* Hash/Radix, filled in below. */
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
26, 0x40, /* Radix options: GTSE == yes. */
@@ -1113,7 +1114,11 @@ static void spapr_dt_ov5_platform_support(void *fdt, int chosen)
if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
first_ppc_cpu->compat_pvr)) {
- /* If we're in a pre POWER9 compat mode then the guest should do hash */
+ /*
+ * If we're in a pre POWER9 compat mode then the guest should
+ * do hash and use the legacy interrupt mode
+ */
+ val[1] = 0x00; /* XICS */
val[3] = 0x00; /* Hash */
} else if (kvm_enabled()) {
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
@@ -1191,7 +1196,7 @@ static void spapr_dt_chosen(sPAPRMachineState *spapr, void *fdt)
_FDT(fdt_setprop_string(fdt, chosen, "stdout-path", stdout_path));
}
- spapr_dt_ov5_platform_support(fdt, chosen);
+ spapr_dt_ov5_platform_support(spapr, fdt, chosen);
g_free(stdout_path);
g_free(bootlist);
@@ -1270,7 +1275,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
_FDT(fdt_setprop_cell(fdt, 0, "#size-cells", 2));
/* /interrupt controller */
- spapr_dt_xics(xics_max_server_number(spapr), fdt, PHANDLE_XICP);
+ spapr->irq->dt_populate(spapr, spapr_max_server_number(spapr), fdt,
+ PHANDLE_XICP);
ret = spapr_populate_memory(spapr, fdt);
if (ret < 0) {
@@ -1290,7 +1296,8 @@ static void *spapr_build_fdt(sPAPRMachineState *spapr,
}
QLIST_FOREACH(phb, &spapr->phbs, list) {
- ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt, smc->irq->nr_msis);
+ ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt,
+ spapr->irq->nr_msis);
if (ret < 0) {
error_report("couldn't setup PCI devices in fdt");
exit(1);
@@ -1620,6 +1627,12 @@ static void spapr_machine_reset(void)
qemu_devices_reset();
+ /*
+ * This is fixing some of the default configuration of the XIVE
+ * devices. To be called after the reset of the machine devices.
+ */
+ spapr_irq_reset(spapr, &error_fatal);
+
/* DRC reset may cause a device to be unplugged. This will cause troubles
* if this device is used by another device (eg, a running vhost backend
* will crash QEMU if the DIMM holding the vring goes away). To avoid such
@@ -1656,7 +1669,10 @@ static void spapr_machine_reset(void)
/* Load the fdt */
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
- g_free(fdt);
+ g_free(spapr->fdt_blob);
+ spapr->fdt_size = fdt_totalsize(fdt);
+ spapr->fdt_initial_size = spapr->fdt_size;
+ spapr->fdt_blob = fdt;
/* Set up the entry state */
spapr_cpu_set_entry_state(first_ppc_cpu, SPAPR_ENTRY_POINT, fdt_addr);
@@ -1731,20 +1747,17 @@ static int spapr_post_load(void *opaque, int version_id)
return err;
}
- if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) {
- CPUState *cs;
- CPU_FOREACH(cs) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- icp_resend(ICP(cpu->intc));
- }
- }
-
- /* In earlier versions, there was no separate qdev for the PAPR
+ /*
+ * In earlier versions, there was no separate qdev for the PAPR
* RTC, so the RTC offset was stored directly in sPAPREnvironment.
* So when migrating from those versions, poke the incoming offset
- * value into the RTC device */
+ * value into the RTC device
+ */
if (version_id < 3) {
err = spapr_rtc_import_offset(&spapr->rtc, spapr->rtc_offset);
+ if (err) {
+ return err;
+ }
}
if (kvm_enabled() && spapr->patb_entry) {
@@ -1759,6 +1772,11 @@ static int spapr_post_load(void *opaque, int version_id)
}
}
+ err = spapr_irq_post_load(spapr, version_id);
+ if (err) {
+ return err;
+ }
+
return err;
}
@@ -1910,6 +1928,39 @@ static const VMStateDescription vmstate_spapr_irq_map = {
},
};
+static bool spapr_dtb_needed(void *opaque)
+{
+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(opaque);
+
+ return smc->update_dt_enabled;
+}
+
+static int spapr_dtb_pre_load(void *opaque)
+{
+ sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
+
+ g_free(spapr->fdt_blob);
+ spapr->fdt_blob = NULL;
+ spapr->fdt_size = 0;
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_spapr_dtb = {
+ .name = "spapr_dtb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_dtb_needed,
+ .pre_load = spapr_dtb_pre_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(fdt_initial_size, sPAPRMachineState),
+ VMSTATE_UINT32(fdt_size, sPAPRMachineState),
+ VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, sPAPRMachineState, 0, NULL,
+ fdt_size),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 3,
@@ -1939,6 +1990,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_ibs,
&vmstate_spapr_irq_map,
&vmstate_spapr_cap_nested_kvm_hv,
+ &vmstate_spapr_dtb,
NULL
}
};
@@ -2466,15 +2518,10 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
boot_cores_nr = possible_cpus->len;
}
- /* VSMT must be set in order to be able to compute VCPU ids, ie to
- * call xics_max_server_number() or spapr_vcpu_id().
- */
- spapr_set_vsmt_mode(spapr, &error_fatal);
-
if (smc->pre_2_10_has_unused_icps) {
int i;
- for (i = 0; i < xics_max_server_number(spapr); i++) {
+ for (i = 0; i < spapr_max_server_number(spapr); i++) {
/* Dummy entries get deregistered when real ICPState objects
* are registered during CPU core hotplug.
*/
@@ -2510,6 +2557,17 @@ static void spapr_init_cpus(sPAPRMachineState *spapr)
}
}
+static PCIHostState *spapr_create_default_phb(void)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
+ qdev_prop_set_uint32(dev, "index", 0);
+ qdev_init_nofail(dev);
+
+ return PCI_HOST_BRIDGE(dev);
+}
+
/* pSeries LPAR / sPAPR hardware init */
static void spapr_machine_init(MachineState *machine)
{
@@ -2593,8 +2651,14 @@ static void spapr_machine_init(MachineState *machine)
/* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
+ /*
+ * VSMT must be set in order to be able to compute VCPU ids, ie to
+ * call spapr_max_server_number() or spapr_vcpu_id().
+ */
+ spapr_set_vsmt_mode(spapr, &error_fatal);
+
/* Set up Interrupt Controller before we create the VCPUs */
- smc->irq->init(spapr, &error_fatal);
+ spapr_irq_init(spapr, &error_fatal);
/* Set up containers for ibm,client-architecture-support negotiated options
*/
@@ -2621,6 +2685,17 @@ static void spapr_machine_init(MachineState *machine)
/* advertise support for ibm,dyamic-memory-v2 */
spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
+ /* advertise XIVE on POWER9 machines */
+ if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) {
+ if (ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00,
+ 0, spapr->max_compat_pvr)) {
+ spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
+ } else if (spapr->irq->ov5 & SPAPR_OV5_XIVE_EXPLOIT) {
+ error_report("XIVE-only machines require a POWER9 CPU");
+ exit(1);
+ }
+ }
+
/* init CPUs */
spapr_init_cpus(spapr);
@@ -2725,7 +2800,7 @@ static void spapr_machine_init(MachineState *machine)
/* Set up PCI */
spapr_pci_rtas_init();
- phb = spapr_create_phb(spapr, 0);
+ phb = spapr_create_default_phb();
for (i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
@@ -3031,9 +3106,42 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
}
+static char *spapr_get_ic_mode(Object *obj, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ if (spapr->irq == &spapr_irq_xics_legacy) {
+ return g_strdup("legacy");
+ } else if (spapr->irq == &spapr_irq_xics) {
+ return g_strdup("xics");
+ } else if (spapr->irq == &spapr_irq_xive) {
+ return g_strdup("xive");
+ } else if (spapr->irq == &spapr_irq_dual) {
+ return g_strdup("dual");
+ }
+ g_assert_not_reached();
+}
+
+static void spapr_set_ic_mode(Object *obj, const char *value, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ /* The legacy IRQ backend can not be set */
+ if (strcmp(value, "xics") == 0) {
+ spapr->irq = &spapr_irq_xics;
+ } else if (strcmp(value, "xive") == 0) {
+ spapr->irq = &spapr_irq_xive;
+ } else if (strcmp(value, "dual") == 0) {
+ spapr->irq = &spapr_irq_dual;
+ } else {
+ error_setg(errp, "Bad value for \"ic-mode\" property");
+ }
+}
+
static void spapr_instance_init(Object *obj)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
spapr->htab_fd = -1;
spapr->use_hotplug_event_source = true;
@@ -3067,6 +3175,14 @@ static void spapr_instance_init(Object *obj)
" the host's SMT mode", &error_abort);
object_property_add_bool(obj, "vfio-no-msix-emulation",
spapr_get_msix_emulation, NULL, NULL);
+
+ /* The machine class defines the default interrupt controller mode */
+ spapr->irq = smc->irq;
+ object_property_add_str(obj, "ic-mode", spapr_get_ic_mode,
+ spapr_set_ic_mode, NULL);
+ object_property_set_description(obj, "ic-mode",
+ "Specifies the interrupt controller mode (xics, xive, dual)",
+ NULL);
}
static void spapr_machine_finalizefn(Object *obj)
@@ -3733,8 +3849,6 @@ static void spapr_phb_placement(sPAPRMachineState *spapr, uint32_t index,
* 1TiB 64-bit MMIO windows for each PHB.
*/
const uint64_t base_buid = 0x800000020000000ULL;
-#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \
- SPAPR_PCI_MEM64_WIN_SIZE - 1)
int i;
/* Sanity check natural alignments */
@@ -3782,16 +3896,15 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
{
PowerPCCPU *cpu = spapr_find_cpu(vcpu_id);
- return cpu ? ICP(cpu->intc) : NULL;
+ return cpu ? cpu->icp : NULL;
}
static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- smc->irq->print_info(spapr, mon);
+ spapr->irq->print_info(spapr, mon);
}
int spapr_get_vcpu_id(PowerPCCPU *cpu)
@@ -3873,7 +3986,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
hc->unplug = spapr_machine_device_unplug;
smc->dr_lmb_enabled = true;
- mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
+ smc->update_dt_enabled = true;
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.0");
mc->has_hotpluggable_cpus = true;
smc->resize_hpt_default = SPAPR_RESIZE_HPT_ENABLED;
fwc->get_dev_path = spapr_get_fw_dev_path;
@@ -3939,16 +4053,10 @@ static const TypeInfo spapr_machine_info = {
mc->is_default = 1; \
} \
} \
- static void spapr_machine_##suffix##_instance_init(Object *obj) \
- { \
- MachineState *machine = MACHINE(obj); \
- spapr_machine_##suffix##_instance_options(machine); \
- } \
static const TypeInfo spapr_machine_##suffix##_info = { \
.name = MACHINE_TYPE_NAME("pseries-" verstr), \
.parent = TYPE_SPAPR_MACHINE, \
.class_init = spapr_machine_##suffix##_class_init, \
- .instance_init = spapr_machine_##suffix##_instance_init, \
}; \
static void spapr_machine_register_##suffix(void) \
{ \
@@ -3956,37 +4064,41 @@ static const TypeInfo spapr_machine_info = {
} \
type_init(spapr_machine_register_##suffix)
- /*
- * pseries-3.1
+/*
+ * pseries-4.0
*/
-static void spapr_machine_3_1_instance_options(MachineState *machine)
+static void spapr_machine_4_0_class_options(MachineClass *mc)
{
+ /* Defaults for the latest behaviour inherited from the base class */
}
+DEFINE_SPAPR_MACHINE(4_0, "4.0", true);
+
+/*
+ * pseries-3.1
+ */
static void spapr_machine_3_1_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+
+ spapr_machine_4_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0");
+ smc->update_dt_enabled = false;
}
-DEFINE_SPAPR_MACHINE(3_1, "3.1", true);
+DEFINE_SPAPR_MACHINE(3_1, "3.1", false);
/*
* pseries-3.0
*/
-#define SPAPR_COMPAT_3_0 \
- HW_COMPAT_3_0
-
-static void spapr_machine_3_0_instance_options(MachineState *machine)
-{
- spapr_machine_3_1_instance_options(machine);
-}
static void spapr_machine_3_0_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_3_1_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_3_0);
+ compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
smc->legacy_irq_allocation = true;
smc->irq = &spapr_irq_xics_legacy;
@@ -3997,30 +4109,17 @@ DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
/*
* pseries-2.12
*/
-#define SPAPR_COMPAT_2_12 \
- HW_COMPAT_2_12 \
- { \
- .driver = TYPE_POWERPC_CPU, \
- .property = "pre-3.0-migration", \
- .value = "on", \
- }, \
- { \
- .driver = TYPE_SPAPR_CPU_CORE, \
- .property = "pre-3.0-migration", \
- .value = "on", \
- },
-
-static void spapr_machine_2_12_instance_options(MachineState *machine)
-{
- spapr_machine_3_0_instance_options(machine);
-}
-
static void spapr_machine_2_12_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_POWERPC_CPU, "pre-3.0-migration", "on" },
+ { TYPE_SPAPR_CPU_CORE, "pre-3.0-migration", "on" },
+ };
spapr_machine_3_0_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_12);
+ compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
/* We depend on kvm_enabled() to choose a default value for the
* hpt-max-page-size capability. Of course we can't do it here
@@ -4032,11 +4131,6 @@ static void spapr_machine_2_12_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE(2_12, "2.12", false);
-static void spapr_machine_2_12_sxxm_instance_options(MachineState *machine)
-{
- spapr_machine_2_12_instance_options(machine);
-}
-
static void spapr_machine_2_12_sxxm_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
@@ -4052,13 +4146,6 @@ DEFINE_SPAPR_MACHINE(2_12_sxxm, "2.12-sxxm", false);
/*
* pseries-2.11
*/
-#define SPAPR_COMPAT_2_11 \
- HW_COMPAT_2_11
-
-static void spapr_machine_2_11_instance_options(MachineState *machine)
-{
- spapr_machine_2_12_instance_options(machine);
-}
static void spapr_machine_2_11_class_options(MachineClass *mc)
{
@@ -4066,7 +4153,7 @@ static void spapr_machine_2_11_class_options(MachineClass *mc)
spapr_machine_2_12_class_options(mc);
smc->default_caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_ON;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11);
+ compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
}
DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
@@ -4074,18 +4161,11 @@ DEFINE_SPAPR_MACHINE(2_11, "2.11", false);
/*
* pseries-2.10
*/
-#define SPAPR_COMPAT_2_10 \
- HW_COMPAT_2_10
-
-static void spapr_machine_2_10_instance_options(MachineState *machine)
-{
- spapr_machine_2_11_instance_options(machine);
-}
static void spapr_machine_2_10_class_options(MachineClass *mc)
{
spapr_machine_2_11_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_10);
+ compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
}
DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
@@ -4093,25 +4173,17 @@ DEFINE_SPAPR_MACHINE(2_10, "2.10", false);
/*
* pseries-2.9
*/
-#define SPAPR_COMPAT_2_9 \
- HW_COMPAT_2_9 \
- { \
- .driver = TYPE_POWERPC_CPU, \
- .property = "pre-2.10-migration", \
- .value = "on", \
- }, \
-
-static void spapr_machine_2_9_instance_options(MachineState *machine)
-{
- spapr_machine_2_10_instance_options(machine);
-}
static void spapr_machine_2_9_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_POWERPC_CPU, "pre-2.10-migration", "on" },
+ };
spapr_machine_2_10_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_9);
+ compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
mc->numa_auto_assign_ram = numa_legacy_auto_assign_ram;
smc->pre_2_10_has_unused_icps = true;
smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED;
@@ -4122,23 +4194,16 @@ DEFINE_SPAPR_MACHINE(2_9, "2.9", false);
/*
* pseries-2.8
*/
-#define SPAPR_COMPAT_2_8 \
- HW_COMPAT_2_8 \
- { \
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
- .property = "pcie-extended-configuration-space", \
- .value = "off", \
- },
-
-static void spapr_machine_2_8_instance_options(MachineState *machine)
-{
- spapr_machine_2_9_instance_options(machine);
-}
static void spapr_machine_2_8_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pcie-extended-configuration-space", "off" },
+ };
+
spapr_machine_2_9_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_8);
+ compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
mc->numa_mem_align_shift = 23;
}
@@ -4147,28 +4212,6 @@ DEFINE_SPAPR_MACHINE(2_8, "2.8", false);
/*
* pseries-2.7
*/
-#define SPAPR_COMPAT_2_7 \
- HW_COMPAT_2_7 \
- { \
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
- .property = "mem_win_size", \
- .value = stringify(SPAPR_PCI_2_7_MMIO_WIN_SIZE),\
- }, \
- { \
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
- .property = "mem64_win_size", \
- .value = "0", \
- }, \
- { \
- .driver = TYPE_POWERPC_CPU, \
- .property = "pre-2.8-migration", \
- .value = "on", \
- }, \
- { \
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE, \
- .property = "pre-2.8-migration", \
- .value = "on", \
- },
static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
@@ -4219,21 +4262,21 @@ static void phb_placement_2_7(sPAPRMachineState *spapr, uint32_t index,
*/
}
-static void spapr_machine_2_7_instance_options(MachineState *machine)
-{
- sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
-
- spapr_machine_2_8_instance_options(machine);
- spapr->use_hotplug_event_source = false;
-}
-
static void spapr_machine_2_7_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0xf80000000", },
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem64_win_size", "0", },
+ { TYPE_POWERPC_CPU, "pre-2.8-migration", "on", },
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pre-2.8-migration", "on", },
+ };
spapr_machine_2_8_class_options(mc);
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power7_v2.3");
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_7);
+ mc->default_machine_opts = "modern-hotplug-events=off";
+ compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
smc->phb_placement = phb_placement_2_7;
}
@@ -4242,24 +4285,17 @@ DEFINE_SPAPR_MACHINE(2_7, "2.7", false);
/*
* pseries-2.6
*/
-#define SPAPR_COMPAT_2_6 \
- HW_COMPAT_2_6 \
- { \
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
- .property = "ddw",\
- .value = stringify(off),\
- },
-
-static void spapr_machine_2_6_instance_options(MachineState *machine)
-{
- spapr_machine_2_7_instance_options(machine);
-}
static void spapr_machine_2_6_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "ddw", "off" },
+ };
+
spapr_machine_2_7_class_options(mc);
mc->has_hotpluggable_cpus = false;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6);
+ compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
@@ -4267,26 +4303,18 @@ DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
/*
* pseries-2.5
*/
-#define SPAPR_COMPAT_2_5 \
- HW_COMPAT_2_5 \
- { \
- .driver = "spapr-vlan", \
- .property = "use-rx-buffer-pools", \
- .value = "off", \
- },
-
-static void spapr_machine_2_5_instance_options(MachineState *machine)
-{
- spapr_machine_2_6_instance_options(machine);
-}
static void spapr_machine_2_5_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { "spapr-vlan", "use-rx-buffer-pools", "off" },
+ };
spapr_machine_2_6_class_options(mc);
smc->use_ohci_by_default = true;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_5);
+ compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
@@ -4294,13 +4322,6 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
/*
* pseries-2.4
*/
-#define SPAPR_COMPAT_2_4 \
- HW_COMPAT_2_4
-
-static void spapr_machine_2_4_instance_options(MachineState *machine)
-{
- spapr_machine_2_5_instance_options(machine);
-}
static void spapr_machine_2_4_class_options(MachineClass *mc)
{
@@ -4308,7 +4329,7 @@ static void spapr_machine_2_4_class_options(MachineClass *mc)
spapr_machine_2_5_class_options(mc);
smc->dr_lmb_enabled = false;
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_4);
+ compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
}
DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
@@ -4316,23 +4337,15 @@ DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
/*
* pseries-2.3
*/
-#define SPAPR_COMPAT_2_3 \
- HW_COMPAT_2_3 \
- {\
- .driver = "spapr-pci-host-bridge",\
- .property = "dynamic-reconfiguration",\
- .value = "off",\
- },
-
-static void spapr_machine_2_3_instance_options(MachineState *machine)
-{
- spapr_machine_2_4_instance_options(machine);
-}
static void spapr_machine_2_3_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { "spapr-pci-host-bridge", "dynamic-reconfiguration", "off" },
+ };
spapr_machine_2_4_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_3);
+ compat_props_add(mc->compat_props, hw_compat_2_3, hw_compat_2_3_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
@@ -4340,42 +4353,27 @@ DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
* pseries-2.2
*/
-#define SPAPR_COMPAT_2_2 \
- HW_COMPAT_2_2 \
- {\
- .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
- .property = "mem_win_size",\
- .value = "0x20000000",\
- },
-
-static void spapr_machine_2_2_instance_options(MachineState *machine)
-{
- spapr_machine_2_3_instance_options(machine);
- machine->suppress_vmdesc = true;
-}
-
static void spapr_machine_2_2_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "mem_win_size", "0x20000000" },
+ };
+
spapr_machine_2_3_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_2);
+ compat_props_add(mc->compat_props, hw_compat_2_2, hw_compat_2_2_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+ mc->default_machine_opts = "modern-hotplug-events=off,suppress-vmdesc=on";
}
DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
/*
* pseries-2.1
*/
-#define SPAPR_COMPAT_2_1 \
- HW_COMPAT_2_1
-
-static void spapr_machine_2_1_instance_options(MachineState *machine)
-{
- spapr_machine_2_2_instance_options(machine);
-}
static void spapr_machine_2_1_class_options(MachineClass *mc)
{
spapr_machine_2_2_class_options(mc);
- SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1);
+ compat_props_add(mc->compat_props, hw_compat_2_1, hw_compat_2_1_len);
}
DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 2398ce62c0..0405306d1e 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -11,7 +11,6 @@
#include "hw/ppc/spapr_cpu_core.h"
#include "target/ppc/cpu.h"
#include "hw/ppc/spapr.h"
-#include "hw/ppc/xics.h" /* for icp_create() - to be removed */
#include "hw/boards.h"
#include "qapi/error.h"
#include "sysemu/cpus.h"
@@ -195,7 +194,12 @@ static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
}
qemu_unregister_reset(spapr_cpu_reset, cpu);
- object_unparent(cpu->intc);
+ if (cpu->icp) {
+ object_unparent(OBJECT(cpu->icp));
+ }
+ if (cpu->tctx) {
+ object_unparent(OBJECT(cpu->tctx));
+ }
cpu_remove_sync(CPU(cpu));
object_unparent(OBJECT(cpu));
}
@@ -233,8 +237,7 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
qemu_register_reset(spapr_cpu_reset, cpu);
spapr_cpu_reset(cpu);
- cpu->intc = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
- &local_err);
+ spapr->irq->cpu_intc_create(spapr, cpu, &local_err);
if (local_err) {
goto error_unregister;
}
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index ae913d070f..17bcaa3822 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1654,6 +1654,17 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
(spapr_h_cas_compose_response(spapr, args[1], args[2],
ov5_updates) != 0);
}
+
+ /*
+ * Generate a machine reset when we have an update of the
+ * interrupt mode. Only required when the machine supports both
+ * modes.
+ */
+ if (!spapr->cas_reboot) {
+ spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT)
+ && spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH;
+ }
+
spapr_ovec_cleanup(ov5_updates);
if (spapr->cas_reboot) {
@@ -1663,6 +1674,42 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
return H_SUCCESS;
}
+static target_ulong h_home_node_associativity(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong procno = args[1];
+ PowerPCCPU *tcpu;
+ int idx;
+
+ /* only support procno from H_REGISTER_VPA */
+ if (flags != 0x1) {
+ return H_FUNCTION;
+ }
+
+ tcpu = spapr_find_cpu(procno);
+ if (tcpu == NULL) {
+ return H_P2;
+ }
+
+ /* sequence is the same as in the "ibm,associativity" property */
+
+ idx = 0;
+#define ASSOCIATIVITY(a, b) (((uint64_t)(a) << 32) | \
+ ((uint64_t)(b) & 0xffffffff))
+ args[idx++] = ASSOCIATIVITY(0, 0);
+ args[idx++] = ASSOCIATIVITY(0, tcpu->node_id);
+ args[idx++] = ASSOCIATIVITY(procno, -1);
+ for ( ; idx < 6; idx++) {
+ args[idx] = -1;
+ }
+#undef ASSOCIATIVITY
+
+ return H_SUCCESS;
+}
+
static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
sPAPRMachineState *spapr,
target_ulong opcode,
@@ -1717,6 +1764,46 @@ static target_ulong h_get_cpu_characteristics(PowerPCCPU *cpu,
args[0] = characteristics;
args[1] = behaviour;
+ return H_SUCCESS;
+}
+
+static target_ulong h_update_dt(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong dt = ppc64_phys_to_real(args[0]);
+ struct fdt_header hdr = { 0 };
+ unsigned cb;
+ sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ void *fdt;
+
+ cpu_physical_memory_read(dt, &hdr, sizeof(hdr));
+ cb = fdt32_to_cpu(hdr.totalsize);
+
+ if (!smc->update_dt_enabled) {
+ return H_SUCCESS;
+ }
+
+ /* Check that the fdt did not grow out of proportion */
+ if (cb > spapr->fdt_initial_size * 2) {
+ trace_spapr_update_dt_failed_size(spapr->fdt_initial_size, cb,
+ fdt32_to_cpu(hdr.magic));
+ return H_PARAMETER;
+ }
+
+ fdt = g_malloc0(cb);
+ cpu_physical_memory_read(dt, fdt, cb);
+
+ /* Check the fdt consistency */
+ if (fdt_check_full(fdt, cb)) {
+ trace_spapr_update_dt_failed_check(spapr->fdt_initial_size, cb,
+ fdt32_to_cpu(hdr.magic));
+ return H_PARAMETER;
+ }
+
+ g_free(spapr->fdt_blob);
+ spapr->fdt_size = cb;
+ spapr->fdt_blob = fdt;
+ trace_spapr_update_dt(cb);
return H_SUCCESS;
}
@@ -1822,6 +1909,12 @@ static void hypercall_register_types(void)
/* ibm,client-architecture-support support */
spapr_register_hypercall(KVMPPC_H_CAS, h_client_architecture_support);
+
+ spapr_register_hypercall(KVMPPC_H_UPDATE_DT, h_update_dt);
+
+ /* Virtual Processor Home Node */
+ spapr_register_hypercall(H_HOME_NODE_ASSOCIATIVITY,
+ h_home_node_associativity);
}
type_init(hypercall_register_types)
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 1b0880ac9e..37e98f9321 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -42,7 +42,7 @@ enum sPAPRTCEAccess {
#define IOMMU_PAGE_SIZE(shift) (1ULL << (shift))
#define IOMMU_PAGE_MASK(shift) (~(IOMMU_PAGE_SIZE(shift) - 1))
-static QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables;
+static QLIST_HEAD(, sPAPRTCETable) spapr_tce_tables;
sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn)
{
@@ -93,7 +93,7 @@ static uint64_t *spapr_tce_alloc_table(uint32_t liobn,
if (!table) {
*fd = -1;
- table = g_malloc0(nb_table * sizeof(uint64_t));
+ table = g_new0(uint64_t, nb_table);
}
trace_spapr_iommu_new_table(liobn, table, *fd);
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index e77b94cc68..1da7a32348 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -12,7 +12,9 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_xive.h"
#include "hw/ppc/xics.h"
+#include "hw/ppc/xics_spapr.h"
#include "sysemu/kvm.h"
#include "trace.h"
@@ -93,15 +95,9 @@ error:
static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
- int nr_irqs = smc->irq->nr_irqs;
+ int nr_irqs = spapr->irq->nr_irqs;
Error *local_err = NULL;
- /* Initialize the MSI IRQ allocator. */
- if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
- spapr_irq_msi_init(spapr, smc->irq->nr_msis);
- }
-
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
!xics_kvm_init(spapr, &local_err)) {
@@ -176,7 +172,7 @@ static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
uint32_t srcno = irq - ics->offset;
if (ics_valid_irq(ics, irq)) {
- return ics->qirqs[srcno];
+ return spapr->qirqs[srcno];
}
return NULL;
@@ -189,12 +185,57 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
- icp_pic_print_info(ICP(cpu->intc), mon);
+ icp_pic_print_info(cpu->icp, mon);
}
ics_pic_print_info(spapr->ics, mon);
}
+static void spapr_irq_cpu_intc_create_xics(sPAPRMachineState *spapr,
+ PowerPCCPU *cpu, Error **errp)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
+ &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cpu->icp = ICP(obj);
+}
+
+static int spapr_irq_post_load_xics(sPAPRMachineState *spapr, int version_id)
+{
+ if (!object_dynamic_cast(OBJECT(spapr->ics), TYPE_ICS_KVM)) {
+ CPUState *cs;
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ icp_resend(cpu->icp);
+ }
+ }
+ return 0;
+}
+
+static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val)
+{
+ sPAPRMachineState *spapr = opaque;
+ MachineState *machine = MACHINE(opaque);
+
+ if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) {
+ ics_kvm_set_irq(spapr->ics, srcno, val);
+ } else {
+ ics_simple_set_irq(spapr->ics, srcno, val);
+ }
+}
+
+static void spapr_irq_reset_xics(sPAPRMachineState *spapr, Error **errp)
+{
+ /* TODO: create the KVM XICS device */
+}
+
#define SPAPR_IRQ_XICS_NR_IRQS 0x1000
#define SPAPR_IRQ_XICS_NR_MSIS \
(XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
@@ -202,37 +243,396 @@ static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
sPAPRIrq spapr_irq_xics = {
.nr_irqs = SPAPR_IRQ_XICS_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_NR_MSIS,
+ .ov5 = SPAPR_OV5_XIVE_LEGACY,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
+ .dt_populate = spapr_dt_xics,
+ .cpu_intc_create = spapr_irq_cpu_intc_create_xics,
+ .post_load = spapr_irq_post_load_xics,
+ .reset = spapr_irq_reset_xics,
+ .set_irq = spapr_irq_set_irq_xics,
+};
+
+/*
+ * XIVE IRQ backend.
+ */
+static void spapr_irq_init_xive(sPAPRMachineState *spapr, Error **errp)
+{
+ MachineState *machine = MACHINE(spapr);
+ uint32_t nr_servers = spapr_max_server_number(spapr);
+ DeviceState *dev;
+ int i;
+
+ /* KVM XIVE device not yet available */
+ if (kvm_enabled()) {
+ if (machine_kernel_irqchip_required(machine)) {
+ error_setg(errp, "kernel_irqchip requested. no KVM XIVE support");
+ return;
+ }
+ }
+
+ dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
+ qdev_prop_set_uint32(dev, "nr-irqs", spapr->irq->nr_irqs);
+ /*
+ * 8 XIVE END structures per CPU. One for each available priority
+ */
+ qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
+ qdev_init_nofail(dev);
+
+ spapr->xive = SPAPR_XIVE(dev);
+
+ /* Enable the CPU IPIs */
+ for (i = 0; i < nr_servers; ++i) {
+ spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false);
+ }
+
+ spapr_xive_hcall_init(spapr);
+}
+
+static int spapr_irq_claim_xive(sPAPRMachineState *spapr, int irq, bool lsi,
+ Error **errp)
+{
+ if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) {
+ error_setg(errp, "IRQ %d is invalid", irq);
+ return -1;
+ }
+ return 0;
+}
+
+static void spapr_irq_free_xive(sPAPRMachineState *spapr, int irq, int num)
+{
+ int i;
+
+ for (i = irq; i < irq + num; ++i) {
+ spapr_xive_irq_free(spapr->xive, i);
+ }
+}
+
+static qemu_irq spapr_qirq_xive(sPAPRMachineState *spapr, int irq)
+{
+ sPAPRXive *xive = spapr->xive;
+
+ if (irq >= xive->nr_irqs) {
+ return NULL;
+ }
+
+ /* The sPAPR machine/device should have claimed the IRQ before */
+ assert(xive_eas_is_valid(&xive->eat[irq]));
+
+ return spapr->qirqs[irq];
+}
+
+static void spapr_irq_print_info_xive(sPAPRMachineState *spapr,
+ Monitor *mon)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ xive_tctx_pic_print_info(cpu->tctx, mon);
+ }
+
+ spapr_xive_pic_print_info(spapr->xive, mon);
+}
+
+static void spapr_irq_cpu_intc_create_xive(sPAPRMachineState *spapr,
+ PowerPCCPU *cpu, Error **errp)
+{
+ Error *local_err = NULL;
+ Object *obj;
+
+ obj = xive_tctx_create(OBJECT(cpu), XIVE_ROUTER(spapr->xive), &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cpu->tctx = XIVE_TCTX(obj);
+
+ /*
+ * (TCG) Early setting the OS CAM line for hotplugged CPUs as they
+ * don't beneficiate from the reset of the XIVE IRQ backend
+ */
+ spapr_xive_set_tctx_os_cam(cpu->tctx);
+}
+
+static int spapr_irq_post_load_xive(sPAPRMachineState *spapr, int version_id)
+{
+ return 0;
+}
+
+static void spapr_irq_reset_xive(sPAPRMachineState *spapr, Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ /* (TCG) Set the OS CAM line of the thread interrupt context. */
+ spapr_xive_set_tctx_os_cam(cpu->tctx);
+ }
+
+ /* Activate the XIVE MMIOs */
+ spapr_xive_mmio_set_enabled(spapr->xive, true);
+}
+
+static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val)
+{
+ sPAPRMachineState *spapr = opaque;
+
+ xive_source_set_irq(&spapr->xive->source, srcno, val);
+}
+
+/*
+ * XIVE uses the full IRQ number space. Set it to 8K to be compatible
+ * with XICS.
+ */
+
+#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
+#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
+
+sPAPRIrq spapr_irq_xive = {
+ .nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS,
+ .nr_msis = SPAPR_IRQ_XIVE_NR_MSIS,
+ .ov5 = SPAPR_OV5_XIVE_EXPLOIT,
+
+ .init = spapr_irq_init_xive,
+ .claim = spapr_irq_claim_xive,
+ .free = spapr_irq_free_xive,
+ .qirq = spapr_qirq_xive,
+ .print_info = spapr_irq_print_info_xive,
+ .dt_populate = spapr_dt_xive,
+ .cpu_intc_create = spapr_irq_cpu_intc_create_xive,
+ .post_load = spapr_irq_post_load_xive,
+ .reset = spapr_irq_reset_xive,
+ .set_irq = spapr_irq_set_irq_xive,
+};
+
+/*
+ * Dual XIVE and XICS IRQ backend.
+ *
+ * Both interrupt mode, XIVE and XICS, objects are created but the
+ * machine starts in legacy interrupt mode (XICS). It can be changed
+ * by the CAS negotiation process and, in that case, the new mode is
+ * activated after an extra machine reset.
+ */
+
+/*
+ * Returns the sPAPR IRQ backend negotiated by CAS. XICS is the
+ * default.
+ */
+static sPAPRIrq *spapr_irq_current(sPAPRMachineState *spapr)
+{
+ return spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT) ?
+ &spapr_irq_xive : &spapr_irq_xics;
+}
+
+static void spapr_irq_init_dual(sPAPRMachineState *spapr, Error **errp)
+{
+ MachineState *machine = MACHINE(spapr);
+ Error *local_err = NULL;
+
+ if (kvm_enabled() && machine_kernel_irqchip_allowed(machine)) {
+ error_setg(errp, "No KVM support for the 'dual' machine");
+ return;
+ }
+
+ spapr_irq_xics.init(spapr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /*
+ * Align the XICS and the XIVE IRQ number space under QEMU.
+ *
+ * However, the XICS KVM device still considers that the IRQ
+ * numbers should start at XICS_IRQ_BASE (0x1000). Either we
+ * should introduce a KVM device ioctl to set the offset or ignore
+ * the lower 4K numbers when using the get/set ioctl of the XICS
+ * KVM device. The second option seems the least intrusive.
+ */
+ spapr->ics->offset = 0;
+
+ spapr_irq_xive.init(spapr, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+}
+
+static int spapr_irq_claim_dual(sPAPRMachineState *spapr, int irq, bool lsi,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ int ret;
+
+ ret = spapr_irq_xics.claim(spapr, irq, lsi, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return ret;
+ }
+
+ ret = spapr_irq_xive.claim(spapr, irq, lsi, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void spapr_irq_free_dual(sPAPRMachineState *spapr, int irq, int num)
+{
+ spapr_irq_xics.free(spapr, irq, num);
+ spapr_irq_xive.free(spapr, irq, num);
+}
+
+static qemu_irq spapr_qirq_dual(sPAPRMachineState *spapr, int irq)
+{
+ sPAPRXive *xive = spapr->xive;
+ ICSState *ics = spapr->ics;
+
+ if (irq >= spapr->irq->nr_irqs) {
+ return NULL;
+ }
+
+ /*
+ * The IRQ number should have been claimed under both interrupt
+ * controllers.
+ */
+ assert(!ICS_IRQ_FREE(ics, irq - ics->offset));
+ assert(xive_eas_is_valid(&xive->eat[irq]));
+
+ return spapr->qirqs[irq];
+}
+
+static void spapr_irq_print_info_dual(sPAPRMachineState *spapr, Monitor *mon)
+{
+ spapr_irq_current(spapr)->print_info(spapr, mon);
+}
+
+static void spapr_irq_dt_populate_dual(sPAPRMachineState *spapr,
+ uint32_t nr_servers, void *fdt,
+ uint32_t phandle)
+{
+ spapr_irq_current(spapr)->dt_populate(spapr, nr_servers, fdt, phandle);
+}
+
+static void spapr_irq_cpu_intc_create_dual(sPAPRMachineState *spapr,
+ PowerPCCPU *cpu, Error **errp)
+{
+ Error *local_err = NULL;
+
+ spapr_irq_xive.cpu_intc_create(spapr, cpu, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ spapr_irq_xics.cpu_intc_create(spapr, cpu, errp);
+}
+
+static int spapr_irq_post_load_dual(sPAPRMachineState *spapr, int version_id)
+{
+ /*
+ * Force a reset of the XIVE backend after migration. The machine
+ * defaults to XICS at startup.
+ */
+ if (spapr_ovec_test(spapr->ov5_cas, OV5_XIVE_EXPLOIT)) {
+ spapr_irq_xive.reset(spapr, &error_fatal);
+ }
+
+ return spapr_irq_current(spapr)->post_load(spapr, version_id);
+}
+
+static void spapr_irq_reset_dual(sPAPRMachineState *spapr, Error **errp)
+{
+ /*
+ * Deactivate the XIVE MMIOs. The XIVE backend will reenable them
+ * if selected.
+ */
+ spapr_xive_mmio_set_enabled(spapr->xive, false);
+
+ spapr_irq_current(spapr)->reset(spapr, errp);
+}
+
+static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val)
+{
+ sPAPRMachineState *spapr = opaque;
+
+ spapr_irq_current(spapr)->set_irq(spapr, srcno, val);
+}
+
+/*
+ * Define values in sync with the XIVE and XICS backend
+ */
+#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000
+#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI)
+
+sPAPRIrq spapr_irq_dual = {
+ .nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS,
+ .nr_msis = SPAPR_IRQ_DUAL_NR_MSIS,
+ .ov5 = SPAPR_OV5_XIVE_BOTH,
+
+ .init = spapr_irq_init_dual,
+ .claim = spapr_irq_claim_dual,
+ .free = spapr_irq_free_dual,
+ .qirq = spapr_qirq_dual,
+ .print_info = spapr_irq_print_info_dual,
+ .dt_populate = spapr_irq_dt_populate_dual,
+ .cpu_intc_create = spapr_irq_cpu_intc_create_dual,
+ .post_load = spapr_irq_post_load_dual,
+ .reset = spapr_irq_reset_dual,
+ .set_irq = spapr_irq_set_irq_dual
};
/*
* sPAPR IRQ frontend routines for devices
*/
+void spapr_irq_init(sPAPRMachineState *spapr, Error **errp)
+{
+ /* Initialize the MSI IRQ allocator. */
+ if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
+ spapr_irq_msi_init(spapr, spapr->irq->nr_msis);
+ }
+
+ spapr->irq->init(spapr, errp);
+
+ spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr,
+ spapr->irq->nr_irqs);
+}
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
-
- return smc->irq->claim(spapr, irq, lsi, errp);
+ return spapr->irq->claim(spapr, irq, lsi, errp);
}
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
-
- smc->irq->free(spapr, irq, num);
+ spapr->irq->free(spapr, irq, num);
}
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
{
- sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ return spapr->irq->qirq(spapr, irq);
+}
+
+int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id)
+{
+ return spapr->irq->post_load(spapr, version_id);
+}
- return smc->irq->qirq(spapr, irq);
+void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp)
+{
+ if (spapr->irq->reset) {
+ spapr->irq->reset(spapr, errp);
+ }
}
/*
@@ -295,10 +695,15 @@ int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
sPAPRIrq spapr_irq_xics_legacy = {
.nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS,
+ .ov5 = SPAPR_OV5_XIVE_LEGACY,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
+ .dt_populate = spapr_dt_xics,
+ .cpu_intc_create = spapr_irq_cpu_intc_create_xics,
+ .post_load = spapr_irq_post_load_xics,
+ .set_irq = spapr_irq_set_irq_xics,
};
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 2374d55fc1..b74f2632ec 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1370,18 +1370,9 @@ static int spapr_create_pci_child_dt(sPAPRPHBState *phb, PCIDevice *dev,
/* Callback to be called during DRC release. */
void spapr_phb_remove_pci_device_cb(DeviceState *dev)
{
- /* some version guests do not wait for completion of a device
- * cleanup (generally done asynchronously by the kernel) before
- * signaling to QEMU that the device is safe, but instead sleep
- * for some 'safe' period of time. unfortunately on a busy host
- * this sleep isn't guaranteed to be long enough, resulting in
- * bad things like IRQ lines being left asserted during final
- * device removal. to deal with this we call reset just prior
- * to finalizing the device, which will put the device back into
- * an 'idle' state, as the device cleanup code expects.
- */
- pci_device_reset(PCI_DEVICE(dev));
- object_unparent(OBJECT(dev));
+ HotplugHandler *hotplug_ctrl = qdev_get_hotplug_handler(dev);
+
+ hotplug_handler_unplug(hotplug_ctrl, dev, &error_abort);
}
static sPAPRDRConnector *spapr_phb_get_pci_func_drc(sPAPRPHBState *phb,
@@ -1490,6 +1481,23 @@ out:
}
}
+static void spapr_pci_unplug(HotplugHandler *plug_handler,
+ DeviceState *plugged_dev, Error **errp)
+{
+ /* some version guests do not wait for completion of a device
+ * cleanup (generally done asynchronously by the kernel) before
+ * signaling to QEMU that the device is safe, but instead sleep
+ * for some 'safe' period of time. unfortunately on a busy host
+ * this sleep isn't guaranteed to be long enough, resulting in
+ * bad things like IRQ lines being left asserted during final
+ * device removal. to deal with this we call reset just prior
+ * to finalizing the device, which will put the device back into
+ * an 'idle' state, as the device cleanup code expects.
+ */
+ pci_device_reset(PCI_DEVICE(plugged_dev));
+ object_unparent(OBJECT(plugged_dev));
+}
+
static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev, Error **errp)
{
@@ -1965,6 +1973,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hp->plug = spapr_pci_plug;
+ hp->unplug = spapr_pci_unplug;
hp->unplug_request = spapr_pci_unplug_request;
}
@@ -1979,17 +1988,6 @@ static const TypeInfo spapr_phb_info = {
}
};
-PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index)
-{
- DeviceState *dev;
-
- dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
- qdev_prop_set_uint32(dev, "index", index);
- qdev_init_nofail(dev);
-
- return PCI_HOST_BRIDGE(dev);
-}
-
typedef struct sPAPRFDT {
void *fdt;
int node_off;
diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c
index 329feb148f..cb8a410359 100644
--- a/hw/ppc/spapr_rtas_ddw.c
+++ b/hw/ppc/spapr_rtas_ddw.c
@@ -96,9 +96,8 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
uint32_t nret, target_ulong rets)
{
sPAPRPHBState *sphb;
- uint64_t buid, max_window_size;
+ uint64_t buid;
uint32_t avail, addr, pgmask = 0;
- MachineState *machine = MACHINE(spapr);
if ((nargs != 3) || (nret != 5)) {
goto param_error_exit;
@@ -114,27 +113,15 @@ static void rtas_ibm_query_pe_dma_window(PowerPCCPU *cpu,
/* Translate page mask to LoPAPR format */
pgmask = spapr_page_mask_to_query_mask(sphb->page_size_mask);
- /*
- * This is "Largest contiguous block of TCEs allocated specifically
- * for (that is, are reserved for) this PE".
- * Return the maximum number as maximum supported RAM size was in 4K pages.
- */
- if (machine->ram_size == machine->maxram_size) {
- max_window_size = machine->ram_size;
- } else {
- max_window_size = machine->device_memory->base +
- memory_region_size(&machine->device_memory->mr);
- }
-
avail = SPAPR_PCI_DMA_MAX_WINDOWS - spapr_phb_get_active_win_num(sphb);
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, avail);
- rtas_st(rets, 2, max_window_size >> SPAPR_TCE_PAGE_SHIFT);
+ rtas_st(rets, 2, 0x80000000); /* The largest window we can possibly have */
rtas_st(rets, 3, pgmask);
rtas_st(rets, 4, 0); /* DMA migration mask, not supported */
- trace_spapr_iommu_ddw_query(buid, addr, avail, max_window_size, pgmask);
+ trace_spapr_iommu_ddw_query(buid, addr, avail, 0x80000000, pgmask);
return;
param_error_exit:
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 840d4a3c45..7e8a9ad093 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -730,7 +730,7 @@ void spapr_dt_vdevice(VIOsPAPRBus *bus, void *fdt)
}
/* Copy out into an array of pointers */
- qdevs = g_malloc(sizeof(qdev) * num);
+ qdevs = g_new(DeviceState *, num);
num = 0;
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
qdevs[num++] = kid->child;
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index dc5e65aee9..0af155ed32 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -22,6 +22,9 @@ spapr_cas_pvr_try(uint32_t pvr) "0x%x"
spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x"
spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
+spapr_update_dt(unsigned cb) "New blob %u bytes"
+spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
+spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index ee9b4b4490..5177120574 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -105,7 +105,7 @@ static PowerPCCPU *ppc440_init_xilinx(ram_addr_t *ram_size,
ppc_dcr_init(env, NULL, NULL);
/* interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs = g_new0(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];
ppcuic_init(env, irqs, 0x0C0, 0, 1);
diff --git a/hw/rdma/rdma_backend.c b/hw/rdma/rdma_backend.c
index d7a4bbd91f..fd571f21e5 100644
--- a/hw/rdma/rdma_backend.c
+++ b/hw/rdma/rdma_backend.c
@@ -15,41 +15,57 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
#include "qapi/error.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qapi-events-rdma.h"
#include <infiniband/verbs.h>
+#include <infiniband/umad_types.h>
+#include <infiniband/umad.h>
+#include <rdma/rdma_user_cm.h>
+#include "contrib/rdmacm-mux/rdmacm-mux.h"
#include "trace.h"
#include "rdma_utils.h"
#include "rdma_rm.h"
#include "rdma_backend.h"
-/* Vendor Errors */
-#define VENDOR_ERR_FAIL_BACKEND 0x201
-#define VENDOR_ERR_TOO_MANY_SGES 0x202
-#define VENDOR_ERR_NOMEM 0x203
-#define VENDOR_ERR_QP0 0x204
-#define VENDOR_ERR_NO_SGE 0x205
-#define VENDOR_ERR_MAD_SEND 0x206
-#define VENDOR_ERR_INVLKEY 0x207
-#define VENDOR_ERR_MR_SMALL 0x208
-
#define THR_NAME_LEN 16
#define THR_POLL_TO 5000
+#define MAD_HDR_SIZE sizeof(struct ibv_grh)
+
typedef struct BackendCtx {
- uint64_t req_id;
void *up_ctx;
bool is_tx_req;
+ struct ibv_sge sge; /* Used to save MAD recv buffer */
} BackendCtx;
-static void (*comp_handler)(int status, unsigned int vendor_err, void *ctx);
+struct backend_umad {
+ struct ib_user_mad hdr;
+ char mad[RDMA_MAX_PRIVATE_DATA];
+};
+
+static void (*comp_handler)(void *ctx, struct ibv_wc *wc);
-static void dummy_comp_handler(int status, unsigned int vendor_err, void *ctx)
+static void dummy_comp_handler(void *ctx, struct ibv_wc *wc)
{
pr_err("No completion handler is registered\n");
}
+static inline void complete_work(enum ibv_wc_status status, uint32_t vendor_err,
+ void *ctx)
+{
+ struct ibv_wc wc = {0};
+
+ wc.status = status;
+ wc.vendor_err = vendor_err;
+
+ comp_handler(ctx, &wc);
+}
+
static void poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
{
int i, ne;
@@ -74,7 +90,7 @@ static void poll_cq(RdmaDeviceResources *rdma_dev_res, struct ibv_cq *ibcq)
}
pr_dbg("Processing %s CQE\n", bctx->is_tx_req ? "send" : "recv");
- comp_handler(wc[i].status, wc[i].vendor_err, bctx->up_ctx);
+ comp_handler(bctx->up_ctx, &wc[i]);
rdma_rm_dealloc_cqe_ctx(rdma_dev_res, wc[i].wr_id);
g_free(bctx);
@@ -146,6 +162,77 @@ static void *comp_handler_thread(void *arg)
return NULL;
}
+static inline void disable_rdmacm_mux_async(RdmaBackendDev *backend_dev)
+{
+ atomic_set(&backend_dev->rdmacm_mux.can_receive, 0);
+}
+
+static inline void enable_rdmacm_mux_async(RdmaBackendDev *backend_dev)
+{
+ atomic_set(&backend_dev->rdmacm_mux.can_receive, sizeof(RdmaCmMuxMsg));
+}
+
+static inline int rdmacm_mux_can_process_async(RdmaBackendDev *backend_dev)
+{
+ return atomic_read(&backend_dev->rdmacm_mux.can_receive);
+}
+
+static int check_mux_op_status(CharBackend *mad_chr_be)
+{
+ RdmaCmMuxMsg msg = {};
+ int ret;
+
+ pr_dbg("Reading response\n");
+ ret = qemu_chr_fe_read_all(mad_chr_be, (uint8_t *)&msg, sizeof(msg));
+ if (ret != sizeof(msg)) {
+ pr_dbg("Invalid message size %d, expecting %ld\n", ret, sizeof(msg));
+ return -EIO;
+ }
+
+ pr_dbg("msg_type=%d\n", msg.hdr.msg_type);
+ pr_dbg("op_code=%d\n", msg.hdr.op_code);
+ pr_dbg("err_code=%d\n", msg.hdr.err_code);
+
+ if (msg.hdr.msg_type != RDMACM_MUX_MSG_TYPE_RESP) {
+ pr_dbg("Invalid message type %d\n", msg.hdr.msg_type);
+ return -EIO;
+ }
+
+ if (msg.hdr.err_code != RDMACM_MUX_ERR_CODE_OK) {
+ pr_dbg("Operation failed in mux, error code %d\n", msg.hdr.err_code);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int exec_rdmacm_mux_req(RdmaBackendDev *backend_dev, RdmaCmMuxMsg *msg)
+{
+ int rc = 0;
+
+ pr_dbg("Executing request %d\n", msg->hdr.op_code);
+
+ msg->hdr.msg_type = RDMACM_MUX_MSG_TYPE_REQ;
+ disable_rdmacm_mux_async(backend_dev);
+ rc = qemu_chr_fe_write(backend_dev->rdmacm_mux.chr_be,
+ (const uint8_t *)msg, sizeof(*msg));
+ if (rc != sizeof(*msg)) {
+ enable_rdmacm_mux_async(backend_dev);
+ pr_dbg("Fail to send request to rdmacm_mux (rc=%d)\n", rc);
+ return -EIO;
+ }
+
+ rc = check_mux_op_status(backend_dev->rdmacm_mux.chr_be);
+ if (rc) {
+ pr_dbg("Fail to execute rdmacm_mux request %d (rc=%d)\n",
+ msg->hdr.op_code, rc);
+ }
+
+ enable_rdmacm_mux_async(backend_dev);
+
+ return 0;
+}
+
static void stop_backend_thread(RdmaBackendThread *thread)
{
thread->run = false;
@@ -168,8 +255,8 @@ static void start_comp_thread(RdmaBackendDev *backend_dev)
comp_handler_thread, backend_dev, QEMU_THREAD_DETACHED);
}
-void rdma_backend_register_comp_handler(void (*handler)(int status,
- unsigned int vendor_err, void *ctx))
+void rdma_backend_register_comp_handler(void (*handler)(void *ctx,
+ struct ibv_wc *wc))
{
comp_handler = handler;
}
@@ -286,11 +373,73 @@ static int build_host_sge_array(RdmaDeviceResources *rdma_dev_res,
return 0;
}
+static int mad_send(RdmaBackendDev *backend_dev, uint8_t sgid_idx,
+ union ibv_gid *sgid, struct ibv_sge *sge, uint32_t num_sge)
+{
+ RdmaCmMuxMsg msg = {};
+ char *hdr, *data;
+ int ret;
+
+ pr_dbg("num_sge=%d\n", num_sge);
+
+ if (num_sge != 2) {
+ return -EINVAL;
+ }
+
+ msg.hdr.op_code = RDMACM_MUX_OP_CODE_MAD;
+ memcpy(msg.hdr.sgid.raw, sgid->raw, sizeof(msg.hdr.sgid));
+
+ msg.umad_len = sge[0].length + sge[1].length;
+ pr_dbg("umad_len=%d\n", msg.umad_len);
+
+ if (msg.umad_len > sizeof(msg.umad.mad)) {
+ return -ENOMEM;
+ }
+
+ msg.umad.hdr.addr.qpn = htobe32(1);
+ msg.umad.hdr.addr.grh_present = 1;
+ pr_dbg("sgid_idx=%d\n", sgid_idx);
+ pr_dbg("sgid=0x%llx\n", sgid->global.interface_id);
+ msg.umad.hdr.addr.gid_index = sgid_idx;
+ memcpy(msg.umad.hdr.addr.gid, sgid->raw, sizeof(msg.umad.hdr.addr.gid));
+ msg.umad.hdr.addr.hop_limit = 0xFF;
+
+ hdr = rdma_pci_dma_map(backend_dev->dev, sge[0].addr, sge[0].length);
+ if (!hdr) {
+ pr_dbg("Fail to map to sge[0]\n");
+ return -ENOMEM;
+ }
+ data = rdma_pci_dma_map(backend_dev->dev, sge[1].addr, sge[1].length);
+ if (!data) {
+ pr_dbg("Fail to map to sge[1]\n");
+ rdma_pci_dma_unmap(backend_dev->dev, hdr, sge[0].length);
+ return -ENOMEM;
+ }
+
+ pr_dbg_buf("mad_hdr", hdr, sge[0].length);
+ pr_dbg_buf("mad_data", data, sge[1].length);
+
+ memcpy(&msg.umad.mad[0], hdr, sge[0].length);
+ memcpy(&msg.umad.mad[sge[0].length], data, sge[1].length);
+
+ rdma_pci_dma_unmap(backend_dev->dev, data, sge[1].length);
+ rdma_pci_dma_unmap(backend_dev->dev, hdr, sge[0].length);
+
+ ret = exec_rdmacm_mux_req(backend_dev, &msg);
+ if (ret) {
+ pr_dbg("Fail to send MAD to rdma_umadmux (%d)\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
void rdma_backend_post_send(RdmaBackendDev *backend_dev,
RdmaBackendQP *qp, uint8_t qp_type,
struct ibv_sge *sge, uint32_t num_sge,
- union ibv_gid *dgid, uint32_t dqpn,
- uint32_t dqkey, void *ctx)
+ uint8_t sgid_idx, union ibv_gid *sgid,
+ union ibv_gid *dgid, uint32_t dqpn, uint32_t dqkey,
+ void *ctx)
{
BackendCtx *bctx;
struct ibv_sge new_sge[MAX_SGE];
@@ -301,21 +450,20 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev,
if (!qp->ibqp) { /* This field does not get initialized for QP0 and QP1 */
if (qp_type == IBV_QPT_SMI) {
pr_dbg("QP0 unsupported\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_QP0, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_QP0, ctx);
} else if (qp_type == IBV_QPT_GSI) {
pr_dbg("QP1\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_MAD_SEND, ctx);
+ rc = mad_send(backend_dev, sgid_idx, sgid, sge, num_sge);
+ if (rc) {
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_MAD_SEND, ctx);
+ } else {
+ complete_work(IBV_WC_SUCCESS, 0, ctx);
+ }
}
- pr_dbg("qp->ibqp is NULL for qp_type %d!!!\n", qp_type);
return;
}
pr_dbg("num_sge=%d\n", num_sge);
- if (!num_sge) {
- pr_dbg("num_sge=0\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_NO_SGE, ctx);
- return;
- }
bctx = g_malloc0(sizeof(*bctx));
bctx->up_ctx = ctx;
@@ -324,20 +472,23 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev,
rc = rdma_rm_alloc_cqe_ctx(backend_dev->rdma_dev_res, &bctx_id, bctx);
if (unlikely(rc)) {
pr_dbg("Failed to allocate cqe_ctx\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx);
goto out_free_bctx;
}
rc = build_host_sge_array(backend_dev->rdma_dev_res, new_sge, sge, num_sge);
if (rc) {
pr_dbg("Error: Failed to build host SGE array\n");
- comp_handler(IBV_WC_GENERAL_ERR, rc, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, rc, ctx);
goto out_dealloc_cqe_ctx;
}
if (qp_type == IBV_QPT_UD) {
- wr.wr.ud.ah = create_ah(backend_dev, qp->ibpd,
- backend_dev->backend_gid_idx, dgid);
+ wr.wr.ud.ah = create_ah(backend_dev, qp->ibpd, sgid_idx, dgid);
+ if (!wr.wr.ud.ah) {
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
+ goto out_dealloc_cqe_ctx;
+ }
wr.wr.ud.remote_qpn = dqpn;
wr.wr.ud.remote_qkey = dqkey;
}
@@ -353,7 +504,7 @@ void rdma_backend_post_send(RdmaBackendDev *backend_dev,
if (rc) {
pr_dbg("Fail (%d, %d) to post send WQE to qpn %d\n", rc, errno,
qp->ibqp->qp_num);
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
goto out_dealloc_cqe_ctx;
}
@@ -366,6 +517,48 @@ out_free_bctx:
g_free(bctx);
}
+static unsigned int save_mad_recv_buffer(RdmaBackendDev *backend_dev,
+ struct ibv_sge *sge, uint32_t num_sge,
+ void *ctx)
+{
+ BackendCtx *bctx;
+ int rc;
+ uint32_t bctx_id;
+
+ if (num_sge != 1) {
+ pr_dbg("Invalid num_sge (%d), expecting 1\n", num_sge);
+ return VENDOR_ERR_INV_NUM_SGE;
+ }
+
+ if (sge[0].length < RDMA_MAX_PRIVATE_DATA + sizeof(struct ibv_grh)) {
+ pr_dbg("Too small buffer for MAD\n");
+ return VENDOR_ERR_INV_MAD_BUFF;
+ }
+
+ pr_dbg("addr=0x%" PRIx64"\n", sge[0].addr);
+ pr_dbg("length=%d\n", sge[0].length);
+ pr_dbg("lkey=%d\n", sge[0].lkey);
+
+ bctx = g_malloc0(sizeof(*bctx));
+
+ rc = rdma_rm_alloc_cqe_ctx(backend_dev->rdma_dev_res, &bctx_id, bctx);
+ if (unlikely(rc)) {
+ g_free(bctx);
+ pr_dbg("Fail to allocate cqe_ctx\n");
+ return VENDOR_ERR_NOMEM;
+ }
+
+ pr_dbg("bctx_id %d, bctx %p, ctx %p\n", bctx_id, bctx, ctx);
+ bctx->up_ctx = ctx;
+ bctx->sge = *sge;
+
+ qemu_mutex_lock(&backend_dev->recv_mads_list.lock);
+ qlist_append_int(backend_dev->recv_mads_list.list, bctx_id);
+ qemu_mutex_unlock(&backend_dev->recv_mads_list.lock);
+
+ return 0;
+}
+
void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
RdmaDeviceResources *rdma_dev_res,
RdmaBackendQP *qp, uint8_t qp_type,
@@ -380,21 +573,19 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
if (!qp->ibqp) { /* This field does not get initialized for QP0 and QP1 */
if (qp_type == IBV_QPT_SMI) {
pr_dbg("QP0 unsupported\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_QP0, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_QP0, ctx);
}
if (qp_type == IBV_QPT_GSI) {
pr_dbg("QP1\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_MAD_SEND, ctx);
+ rc = save_mad_recv_buffer(backend_dev, sge, num_sge, ctx);
+ if (rc) {
+ complete_work(IBV_WC_GENERAL_ERR, rc, ctx);
+ }
}
return;
}
pr_dbg("num_sge=%d\n", num_sge);
- if (!num_sge) {
- pr_dbg("num_sge=0\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_NO_SGE, ctx);
- return;
- }
bctx = g_malloc0(sizeof(*bctx));
bctx->up_ctx = ctx;
@@ -403,14 +594,14 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
rc = rdma_rm_alloc_cqe_ctx(rdma_dev_res, &bctx_id, bctx);
if (unlikely(rc)) {
pr_dbg("Failed to allocate cqe_ctx\n");
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_NOMEM, ctx);
goto out_free_bctx;
}
rc = build_host_sge_array(rdma_dev_res, new_sge, sge, num_sge);
if (rc) {
pr_dbg("Error: Failed to build host SGE array\n");
- comp_handler(IBV_WC_GENERAL_ERR, rc, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, rc, ctx);
goto out_dealloc_cqe_ctx;
}
@@ -422,7 +613,7 @@ void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
if (rc) {
pr_dbg("Fail (%d, %d) to post recv WQE to qpn %d\n", rc, errno,
qp->ibqp->qp_num);
- comp_handler(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_FAIL_BACKEND, ctx);
goto out_dealloc_cqe_ctx;
}
@@ -513,7 +704,6 @@ int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
switch (qp_type) {
case IBV_QPT_GSI:
- pr_dbg("QP1 unsupported\n");
return 0;
case IBV_QPT_RC:
@@ -594,9 +784,9 @@ int rdma_backend_qp_state_init(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
}
int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
- uint8_t qp_type, union ibv_gid *dgid,
- uint32_t dqpn, uint32_t rq_psn, uint32_t qkey,
- bool use_qkey)
+ uint8_t qp_type, uint8_t sgid_idx,
+ union ibv_gid *dgid, uint32_t dqpn,
+ uint32_t rq_psn, uint32_t qkey, bool use_qkey)
{
struct ibv_qp_attr attr = {0};
union ibv_gid ibv_gid = {
@@ -608,13 +798,15 @@ int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
attr.qp_state = IBV_QPS_RTR;
attr_mask = IBV_QP_STATE;
+ qp->sgid_idx = sgid_idx;
+
switch (qp_type) {
case IBV_QPT_RC:
pr_dbg("dgid=0x%" PRIx64 ",%" PRIx64 "\n",
be64_to_cpu(ibv_gid.global.subnet_prefix),
be64_to_cpu(ibv_gid.global.interface_id));
pr_dbg("dqpn=0x%x\n", dqpn);
- pr_dbg("sgid_idx=%d\n", backend_dev->backend_gid_idx);
+ pr_dbg("sgid_idx=%d\n", qp->sgid_idx);
pr_dbg("sport_num=%d\n", backend_dev->port_num);
pr_dbg("rq_psn=0x%x\n", rq_psn);
@@ -626,7 +818,7 @@ int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
attr.ah_attr.is_global = 1;
attr.ah_attr.grh.hop_limit = 1;
attr.ah_attr.grh.dgid = ibv_gid;
- attr.ah_attr.grh.sgid_index = backend_dev->backend_gid_idx;
+ attr.ah_attr.grh.sgid_index = qp->sgid_idx;
attr.rq_psn = rq_psn;
attr_mask |= IBV_QP_AV | IBV_QP_PATH_MTU | IBV_QP_DEST_QPN |
@@ -635,8 +827,8 @@ int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
break;
case IBV_QPT_UD:
+ pr_dbg("qkey=0x%x\n", qkey);
if (use_qkey) {
- pr_dbg("qkey=0x%x\n", qkey);
attr.qkey = qkey;
attr_mask |= IBV_QP_QKEY;
}
@@ -725,21 +917,231 @@ void rdma_backend_destroy_qp(RdmaBackendQP *qp)
static int init_device_caps(RdmaBackendDev *backend_dev,
struct ibv_device_attr *dev_attr)
{
- if (ibv_query_device(backend_dev->context, &backend_dev->dev_attr)) {
+ struct ibv_device_attr bk_dev_attr;
+
+ if (ibv_query_device(backend_dev->context, &bk_dev_attr)) {
+ return -EIO;
+ }
+
+ dev_attr->max_sge = MAX_SGE;
+
+ CHK_ATTR(dev_attr, bk_dev_attr, max_mr_size, "%" PRId64);
+ CHK_ATTR(dev_attr, bk_dev_attr, max_qp, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_sge, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_qp_wr, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_cq, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_cqe, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_mr, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_pd, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_qp_rd_atom, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_qp_init_rd_atom, "%d");
+ CHK_ATTR(dev_attr, bk_dev_attr, max_ah, "%d");
+
+ return 0;
+}
+
+static inline void build_mad_hdr(struct ibv_grh *grh, union ibv_gid *sgid,
+ union ibv_gid *my_gid, int paylen)
+{
+ grh->paylen = htons(paylen);
+ grh->sgid = *sgid;
+ grh->dgid = *my_gid;
+
+ pr_dbg("paylen=%d (net=0x%x)\n", paylen, grh->paylen);
+ pr_dbg("dgid=0x%llx\n", my_gid->global.interface_id);
+ pr_dbg("sgid=0x%llx\n", sgid->global.interface_id);
+}
+
+static void process_incoming_mad_req(RdmaBackendDev *backend_dev,
+ RdmaCmMuxMsg *msg)
+{
+ QObject *o_ctx_id;
+ unsigned long cqe_ctx_id;
+ BackendCtx *bctx;
+ char *mad;
+
+ pr_dbg("umad_len=%d\n", msg->umad_len);
+
+#ifdef PVRDMA_DEBUG
+ struct umad_hdr *hdr = (struct umad_hdr *)&msg->umad.mad;
+ pr_dbg("bv %x cls %x cv %x mtd %x st %d tid %" PRIx64 " at %x atm %x\n",
+ hdr->base_version, hdr->mgmt_class, hdr->class_version,
+ hdr->method, hdr->status, be64toh(hdr->tid),
+ hdr->attr_id, hdr->attr_mod);
+#endif
+
+ qemu_mutex_lock(&backend_dev->recv_mads_list.lock);
+ o_ctx_id = qlist_pop(backend_dev->recv_mads_list.list);
+ qemu_mutex_unlock(&backend_dev->recv_mads_list.lock);
+ if (!o_ctx_id) {
+ pr_dbg("No more free MADs buffers, waiting for a while\n");
+ sleep(THR_POLL_TO);
+ return;
+ }
+
+ cqe_ctx_id = qnum_get_uint(qobject_to(QNum, o_ctx_id));
+ bctx = rdma_rm_get_cqe_ctx(backend_dev->rdma_dev_res, cqe_ctx_id);
+ if (unlikely(!bctx)) {
+ pr_dbg("Error: Fail to find ctx for %ld\n", cqe_ctx_id);
+ return;
+ }
+
+ pr_dbg("id %ld, bctx %p, ctx %p\n", cqe_ctx_id, bctx, bctx->up_ctx);
+
+ mad = rdma_pci_dma_map(backend_dev->dev, bctx->sge.addr,
+ bctx->sge.length);
+ if (!mad || bctx->sge.length < msg->umad_len + MAD_HDR_SIZE) {
+ complete_work(IBV_WC_GENERAL_ERR, VENDOR_ERR_INV_MAD_BUFF,
+ bctx->up_ctx);
+ } else {
+ struct ibv_wc wc = {0};
+ pr_dbg_buf("mad", msg->umad.mad, msg->umad_len);
+ memset(mad, 0, bctx->sge.length);
+ build_mad_hdr((struct ibv_grh *)mad,
+ (union ibv_gid *)&msg->umad.hdr.addr.gid, &msg->hdr.sgid,
+ msg->umad_len);
+ memcpy(&mad[MAD_HDR_SIZE], msg->umad.mad, msg->umad_len);
+ rdma_pci_dma_unmap(backend_dev->dev, mad, bctx->sge.length);
+
+ wc.byte_len = msg->umad_len;
+ wc.status = IBV_WC_SUCCESS;
+ wc.wc_flags = IBV_WC_GRH;
+ comp_handler(bctx->up_ctx, &wc);
+ }
+
+ g_free(bctx);
+ rdma_rm_dealloc_cqe_ctx(backend_dev->rdma_dev_res, cqe_ctx_id);
+}
+
+static inline int rdmacm_mux_can_receive(void *opaque)
+{
+ RdmaBackendDev *backend_dev = (RdmaBackendDev *)opaque;
+
+ return rdmacm_mux_can_process_async(backend_dev);
+}
+
+static void rdmacm_mux_read(void *opaque, const uint8_t *buf, int size)
+{
+ RdmaBackendDev *backend_dev = (RdmaBackendDev *)opaque;
+ RdmaCmMuxMsg *msg = (RdmaCmMuxMsg *)buf;
+
+ pr_dbg("Got %d bytes\n", size);
+ pr_dbg("msg_type=%d\n", msg->hdr.msg_type);
+ pr_dbg("op_code=%d\n", msg->hdr.op_code);
+
+ if (msg->hdr.msg_type != RDMACM_MUX_MSG_TYPE_REQ &&
+ msg->hdr.op_code != RDMACM_MUX_OP_CODE_MAD) {
+ pr_dbg("Error: Not a MAD request, skipping\n");
+ return;
+ }
+ process_incoming_mad_req(backend_dev, msg);
+}
+
+static int mad_init(RdmaBackendDev *backend_dev, CharBackend *mad_chr_be)
+{
+ int ret;
+
+ backend_dev->rdmacm_mux.chr_be = mad_chr_be;
+
+ ret = qemu_chr_fe_backend_connected(backend_dev->rdmacm_mux.chr_be);
+ if (!ret) {
+ pr_dbg("Missing chardev for MAD multiplexer\n");
+ return -EIO;
+ }
+
+ qemu_mutex_init(&backend_dev->recv_mads_list.lock);
+ backend_dev->recv_mads_list.list = qlist_new();
+
+ enable_rdmacm_mux_async(backend_dev);
+
+ qemu_chr_fe_set_handlers(backend_dev->rdmacm_mux.chr_be,
+ rdmacm_mux_can_receive, rdmacm_mux_read, NULL,
+ NULL, backend_dev, NULL, true);
+
+ return 0;
+}
+
+static void mad_fini(RdmaBackendDev *backend_dev)
+{
+ pr_dbg("Stopping MAD\n");
+ disable_rdmacm_mux_async(backend_dev);
+ qemu_chr_fe_disconnect(backend_dev->rdmacm_mux.chr_be);
+ if (backend_dev->recv_mads_list.list) {
+ qlist_destroy_obj(QOBJECT(backend_dev->recv_mads_list.list));
+ qemu_mutex_destroy(&backend_dev->recv_mads_list.lock);
+ }
+}
+
+int rdma_backend_get_gid_index(RdmaBackendDev *backend_dev,
+ union ibv_gid *gid)
+{
+ union ibv_gid sgid;
+ int ret;
+ int i = 0;
+
+ pr_dbg("0x%llx, 0x%llx\n",
+ (long long unsigned int)be64_to_cpu(gid->global.subnet_prefix),
+ (long long unsigned int)be64_to_cpu(gid->global.interface_id));
+
+ do {
+ ret = ibv_query_gid(backend_dev->context, backend_dev->port_num, i,
+ &sgid);
+ i++;
+ } while (!ret && (memcmp(&sgid, gid, sizeof(*gid))));
+
+ pr_dbg("gid_index=%d\n", i - 1);
+
+ return ret ? ret : i - 1;
+}
+
+int rdma_backend_add_gid(RdmaBackendDev *backend_dev, const char *ifname,
+ union ibv_gid *gid)
+{
+ RdmaCmMuxMsg msg = {};
+ int ret;
+
+ pr_dbg("0x%llx, 0x%llx\n",
+ (long long unsigned int)be64_to_cpu(gid->global.subnet_prefix),
+ (long long unsigned int)be64_to_cpu(gid->global.interface_id));
+
+ msg.hdr.op_code = RDMACM_MUX_OP_CODE_REG;
+ memcpy(msg.hdr.sgid.raw, gid->raw, sizeof(msg.hdr.sgid));
+
+ ret = exec_rdmacm_mux_req(backend_dev, &msg);
+ if (ret) {
+ pr_dbg("Fail to register GID to rdma_umadmux (%d)\n", ret);
return -EIO;
}
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_mr_size, "%" PRId64);
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_qp, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_sge, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_qp_wr, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_cq, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_cqe, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_mr, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_pd, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_qp_rd_atom, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_qp_init_rd_atom, "%d");
- CHK_ATTR(dev_attr, backend_dev->dev_attr, max_ah, "%d");
+ qapi_event_send_rdma_gid_status_changed(ifname, true,
+ gid->global.subnet_prefix,
+ gid->global.interface_id);
+
+ return ret;
+}
+
+int rdma_backend_del_gid(RdmaBackendDev *backend_dev, const char *ifname,
+ union ibv_gid *gid)
+{
+ RdmaCmMuxMsg msg = {};
+ int ret;
+
+ pr_dbg("0x%llx, 0x%llx\n",
+ (long long unsigned int)be64_to_cpu(gid->global.subnet_prefix),
+ (long long unsigned int)be64_to_cpu(gid->global.interface_id));
+
+ msg.hdr.op_code = RDMACM_MUX_OP_CODE_UNREG;
+ memcpy(msg.hdr.sgid.raw, gid->raw, sizeof(msg.hdr.sgid));
+
+ ret = exec_rdmacm_mux_req(backend_dev, &msg);
+ if (ret) {
+ pr_dbg("Fail to unregister GID from rdma_umadmux (%d)\n", ret);
+ return -EIO;
+ }
+
+ qapi_event_send_rdma_gid_status_changed(ifname, false,
+ gid->global.subnet_prefix,
+ gid->global.interface_id);
return 0;
}
@@ -747,20 +1149,17 @@ static int init_device_caps(RdmaBackendDev *backend_dev,
int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
RdmaDeviceResources *rdma_dev_res,
const char *backend_device_name, uint8_t port_num,
- uint8_t backend_gid_idx, struct ibv_device_attr *dev_attr,
+ struct ibv_device_attr *dev_attr, CharBackend *mad_chr_be,
Error **errp)
{
int i;
int ret = 0;
int num_ibv_devices;
struct ibv_device **dev_list;
- struct ibv_port_attr port_attr;
memset(backend_dev, 0, sizeof(*backend_dev));
backend_dev->dev = pdev;
-
- backend_dev->backend_gid_idx = backend_gid_idx;
backend_dev->port_num = port_num;
backend_dev->rdma_dev_res = rdma_dev_res;
@@ -797,9 +1196,9 @@ int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
backend_dev->ib_dev = *dev_list;
}
- pr_dbg("Using backend device %s, port %d, gid_idx %d\n",
- ibv_get_device_name(backend_dev->ib_dev),
- backend_dev->port_num, backend_dev->backend_gid_idx);
+ pr_dbg("Using backend device %s, port %d\n",
+ ibv_get_device_name(backend_dev->ib_dev), backend_dev->port_num);
+ pr_dbg("uverb device %s\n", backend_dev->ib_dev->dev_name);
backend_dev->context = ibv_open_device(backend_dev->ib_dev);
if (!backend_dev->context) {
@@ -816,20 +1215,6 @@ int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
}
pr_dbg("dev->backend_dev.channel=%p\n", backend_dev->channel);
- ret = ibv_query_port(backend_dev->context, backend_dev->port_num,
- &port_attr);
- if (ret) {
- error_setg(errp, "Error %d from ibv_query_port", ret);
- ret = -EIO;
- goto out_destroy_comm_channel;
- }
-
- if (backend_dev->backend_gid_idx >= port_attr.gid_tbl_len) {
- error_setg(errp, "Invalid backend_gid_idx, should be less than %d",
- port_attr.gid_tbl_len);
- goto out_destroy_comm_channel;
- }
-
ret = init_device_caps(backend_dev, dev_attr);
if (ret) {
error_setg(errp, "Failed to initialize device capabilities");
@@ -837,18 +1222,13 @@ int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
goto out_destroy_comm_channel;
}
- ret = ibv_query_gid(backend_dev->context, backend_dev->port_num,
- backend_dev->backend_gid_idx, &backend_dev->gid);
+
+ ret = mad_init(backend_dev, mad_chr_be);
if (ret) {
- error_setg(errp, "Failed to query gid %d",
- backend_dev->backend_gid_idx);
+ error_setg(errp, "Fail to initialize mad");
ret = -EIO;
goto out_destroy_comm_channel;
}
- pr_dbg("subnet_prefix=0x%" PRIx64 "\n",
- be64_to_cpu(backend_dev->gid.global.subnet_prefix));
- pr_dbg("interface_id=0x%" PRIx64 "\n",
- be64_to_cpu(backend_dev->gid.global.interface_id));
backend_dev->comp_thread.run = false;
backend_dev->comp_thread.is_running = false;
@@ -886,6 +1266,7 @@ void rdma_backend_stop(RdmaBackendDev *backend_dev)
void rdma_backend_fini(RdmaBackendDev *backend_dev)
{
rdma_backend_stop(backend_dev);
+ mad_fini(backend_dev);
g_hash_table_destroy(ah_hash);
ibv_destroy_comp_channel(backend_dev->channel);
ibv_close_device(backend_dev->context);
diff --git a/hw/rdma/rdma_backend.h b/hw/rdma/rdma_backend.h
index 86e8fe8ab6..5114c90e67 100644
--- a/hw/rdma/rdma_backend.h
+++ b/hw/rdma/rdma_backend.h
@@ -17,23 +17,32 @@
#define RDMA_BACKEND_H
#include "qapi/error.h"
+#include "chardev/char-fe.h"
+
#include "rdma_rm_defs.h"
#include "rdma_backend_defs.h"
+/* Vendor Errors */
+#define VENDOR_ERR_FAIL_BACKEND 0x201
+#define VENDOR_ERR_TOO_MANY_SGES 0x202
+#define VENDOR_ERR_NOMEM 0x203
+#define VENDOR_ERR_QP0 0x204
+#define VENDOR_ERR_INV_NUM_SGE 0x205
+#define VENDOR_ERR_MAD_SEND 0x206
+#define VENDOR_ERR_INVLKEY 0x207
+#define VENDOR_ERR_MR_SMALL 0x208
+#define VENDOR_ERR_INV_MAD_BUFF 0x209
+#define VENDOR_ERR_INV_GID_IDX 0x210
+
/* Add definition for QP0 and QP1 as there is no userspace enums for them */
enum ibv_special_qp_type {
IBV_QPT_SMI = 0,
IBV_QPT_GSI = 1,
};
-static inline union ibv_gid *rdma_backend_gid(RdmaBackendDev *dev)
-{
- return &dev->gid;
-}
-
static inline uint32_t rdma_backend_qpn(const RdmaBackendQP *qp)
{
- return qp->ibqp ? qp->ibqp->qp_num : 0;
+ return qp->ibqp ? qp->ibqp->qp_num : 1;
}
static inline uint32_t rdma_backend_mr_lkey(const RdmaBackendMR *mr)
@@ -49,13 +58,19 @@ static inline uint32_t rdma_backend_mr_rkey(const RdmaBackendMR *mr)
int rdma_backend_init(RdmaBackendDev *backend_dev, PCIDevice *pdev,
RdmaDeviceResources *rdma_dev_res,
const char *backend_device_name, uint8_t port_num,
- uint8_t backend_gid_idx, struct ibv_device_attr *dev_attr,
+ struct ibv_device_attr *dev_attr, CharBackend *mad_chr_be,
Error **errp);
void rdma_backend_fini(RdmaBackendDev *backend_dev);
+int rdma_backend_add_gid(RdmaBackendDev *backend_dev, const char *ifname,
+ union ibv_gid *gid);
+int rdma_backend_del_gid(RdmaBackendDev *backend_dev, const char *ifname,
+ union ibv_gid *gid);
+int rdma_backend_get_gid_index(RdmaBackendDev *backend_dev,
+ union ibv_gid *gid);
void rdma_backend_start(RdmaBackendDev *backend_dev);
void rdma_backend_stop(RdmaBackendDev *backend_dev);
-void rdma_backend_register_comp_handler(void (*handler)(int status,
- unsigned int vendor_err, void *ctx));
+void rdma_backend_register_comp_handler(void (*handler)(void *ctx,
+ struct ibv_wc *wc));
void rdma_backend_unregister_comp_handler(void);
int rdma_backend_query_port(RdmaBackendDev *backend_dev,
@@ -80,9 +95,9 @@ int rdma_backend_create_qp(RdmaBackendQP *qp, uint8_t qp_type,
int rdma_backend_qp_state_init(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
uint8_t qp_type, uint32_t qkey);
int rdma_backend_qp_state_rtr(RdmaBackendDev *backend_dev, RdmaBackendQP *qp,
- uint8_t qp_type, union ibv_gid *dgid,
- uint32_t dqpn, uint32_t rq_psn, uint32_t qkey,
- bool use_qkey);
+ uint8_t qp_type, uint8_t sgid_idx,
+ union ibv_gid *dgid, uint32_t dqpn,
+ uint32_t rq_psn, uint32_t qkey, bool use_qkey);
int rdma_backend_qp_state_rts(RdmaBackendQP *qp, uint8_t qp_type,
uint32_t sq_psn, uint32_t qkey, bool use_qkey);
int rdma_backend_query_qp(RdmaBackendQP *qp, struct ibv_qp_attr *attr,
@@ -92,6 +107,7 @@ void rdma_backend_destroy_qp(RdmaBackendQP *qp);
void rdma_backend_post_send(RdmaBackendDev *backend_dev,
RdmaBackendQP *qp, uint8_t qp_type,
struct ibv_sge *sge, uint32_t num_sge,
+ uint8_t sgid_idx, union ibv_gid *sgid,
union ibv_gid *dgid, uint32_t dqpn, uint32_t dqkey,
void *ctx);
void rdma_backend_post_recv(RdmaBackendDev *backend_dev,
diff --git a/hw/rdma/rdma_backend_defs.h b/hw/rdma/rdma_backend_defs.h
index 7404f64002..15ae8b970e 100644
--- a/hw/rdma/rdma_backend_defs.h
+++ b/hw/rdma/rdma_backend_defs.h
@@ -16,8 +16,10 @@
#ifndef RDMA_BACKEND_DEFS_H
#define RDMA_BACKEND_DEFS_H
-#include <infiniband/verbs.h>
#include "qemu/thread.h"
+#include "chardev/char-fe.h"
+#include <infiniband/verbs.h>
+#include "contrib/rdmacm-mux/rdmacm-mux.h"
typedef struct RdmaDeviceResources RdmaDeviceResources;
@@ -28,17 +30,26 @@ typedef struct RdmaBackendThread {
bool is_running; /* Set by the thread to report its status */
} RdmaBackendThread;
+typedef struct RecvMadList {
+ QemuMutex lock;
+ QList *list;
+} RecvMadList;
+
+typedef struct RdmaCmMux {
+ CharBackend *chr_be;
+ int can_receive;
+} RdmaCmMux;
+
typedef struct RdmaBackendDev {
- struct ibv_device_attr dev_attr;
RdmaBackendThread comp_thread;
- union ibv_gid gid;
PCIDevice *dev;
RdmaDeviceResources *rdma_dev_res;
struct ibv_device *ib_dev;
struct ibv_context *context;
struct ibv_comp_channel *channel;
uint8_t port_num;
- uint8_t backend_gid_idx;
+ RecvMadList recv_mads_list;
+ RdmaCmMux rdmacm_mux;
} RdmaBackendDev;
typedef struct RdmaBackendPD {
@@ -58,6 +69,7 @@ typedef struct RdmaBackendCQ {
typedef struct RdmaBackendQP {
struct ibv_pd *ibpd;
struct ibv_qp *ibqp;
+ uint8_t sgid_idx;
} RdmaBackendQP;
#endif
diff --git a/hw/rdma/rdma_rm.c b/hw/rdma/rdma_rm.c
index 8d59a42cd1..268ff633a4 100644
--- a/hw/rdma/rdma_rm.c
+++ b/hw/rdma/rdma_rm.c
@@ -41,9 +41,12 @@ static inline void res_tbl_init(const char *name, RdmaRmResTbl *tbl,
static inline void res_tbl_free(RdmaRmResTbl *tbl)
{
+ if (!tbl->bitmap) {
+ return;
+ }
qemu_mutex_destroy(&tbl->lock);
g_free(tbl->tbl);
- bitmap_zero_extend(tbl->bitmap, tbl->tbl_sz, 0);
+ g_free(tbl->bitmap);
}
static inline void *res_tbl_get(RdmaRmResTbl *tbl, uint32_t handle)
@@ -263,7 +266,7 @@ int rdma_rm_alloc_cq(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
}
cq->opaque = opaque;
- cq->notify = false;
+ cq->notify = CNT_CLEAR;
rc = rdma_backend_create_cq(backend_dev, &cq->backend_cq, cqe);
if (rc) {
@@ -291,7 +294,10 @@ void rdma_rm_req_notify_cq(RdmaDeviceResources *dev_res, uint32_t cq_handle,
return;
}
- cq->notify = notify;
+ if (cq->notify != CNT_SET) {
+ cq->notify = notify ? CNT_ARM : CNT_CLEAR;
+ }
+
pr_dbg("notify=%d\n", cq->notify);
}
@@ -349,6 +355,11 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
return -EINVAL;
}
+ if (qp_type == IBV_QPT_GSI) {
+ scq->notify = CNT_SET;
+ rcq->notify = CNT_SET;
+ }
+
qp = res_tbl_alloc(&dev_res->qp_tbl, &rm_qpn);
if (!qp) {
return -ENOMEM;
@@ -383,7 +394,7 @@ out_dealloc_qp:
}
int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
- uint32_t qp_handle, uint32_t attr_mask,
+ uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
union ibv_gid *dgid, uint32_t dqpn,
enum ibv_qp_state qp_state, uint32_t qkey,
uint32_t rq_psn, uint32_t sq_psn)
@@ -392,6 +403,7 @@ int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
int ret;
pr_dbg("qpn=0x%x\n", qp_handle);
+ pr_dbg("qkey=0x%x\n", qkey);
qp = rdma_rm_get_qp(dev_res, qp_handle);
if (!qp) {
@@ -422,9 +434,19 @@ int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
}
if (qp->qp_state == IBV_QPS_RTR) {
+ /* Get backend gid index */
+ pr_dbg("Guest sgid_idx=%d\n", sgid_idx);
+ sgid_idx = rdma_rm_get_backend_gid_index(dev_res, backend_dev,
+ sgid_idx);
+ if (sgid_idx <= 0) { /* TODO check also less than bk.max_sgid */
+ pr_dbg("Fail to get bk sgid_idx for sgid_idx %d\n", sgid_idx);
+ return -EIO;
+ }
+
ret = rdma_backend_qp_state_rtr(backend_dev, &qp->backend_qp,
- qp->qp_type, dgid, dqpn, rq_psn,
- qkey, attr_mask & IBV_QP_QKEY);
+ qp->qp_type, sgid_idx, dgid, dqpn,
+ rq_psn, qkey,
+ attr_mask & IBV_QP_QKEY);
if (ret) {
return -EIO;
}
@@ -515,11 +537,93 @@ void rdma_rm_dealloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id)
res_tbl_dealloc(&dev_res->cqe_ctx_tbl, cqe_ctx_id);
}
+int rdma_rm_add_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname, union ibv_gid *gid, int gid_idx)
+{
+ int rc;
+
+ rc = rdma_backend_add_gid(backend_dev, ifname, gid);
+ if (rc) {
+ pr_dbg("Fail to add gid\n");
+ return -EINVAL;
+ }
+
+ memcpy(&dev_res->port.gid_tbl[gid_idx].gid, gid, sizeof(*gid));
+
+ return 0;
+}
+
+int rdma_rm_del_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname, int gid_idx)
+{
+ int rc;
+
+ if (!dev_res->port.gid_tbl[gid_idx].gid.global.interface_id) {
+ return 0;
+ }
+
+ rc = rdma_backend_del_gid(backend_dev, ifname,
+ &dev_res->port.gid_tbl[gid_idx].gid);
+ if (rc) {
+ pr_dbg("Fail to delete gid\n");
+ return -EINVAL;
+ }
+
+ memset(dev_res->port.gid_tbl[gid_idx].gid.raw, 0,
+ sizeof(dev_res->port.gid_tbl[gid_idx].gid));
+ dev_res->port.gid_tbl[gid_idx].backend_gid_index = -1;
+
+ return 0;
+}
+
+int rdma_rm_get_backend_gid_index(RdmaDeviceResources *dev_res,
+ RdmaBackendDev *backend_dev, int sgid_idx)
+{
+ if (unlikely(sgid_idx < 0 || sgid_idx >= MAX_PORT_GIDS)) {
+ pr_dbg("Got invalid sgid_idx %d\n", sgid_idx);
+ return -EINVAL;
+ }
+
+ if (unlikely(dev_res->port.gid_tbl[sgid_idx].backend_gid_index == -1)) {
+ dev_res->port.gid_tbl[sgid_idx].backend_gid_index =
+ rdma_backend_get_gid_index(backend_dev,
+ &dev_res->port.gid_tbl[sgid_idx].gid);
+ }
+
+ pr_dbg("backend_gid_index=%d\n",
+ dev_res->port.gid_tbl[sgid_idx].backend_gid_index);
+
+ return dev_res->port.gid_tbl[sgid_idx].backend_gid_index;
+}
+
static void destroy_qp_hash_key(gpointer data)
{
g_bytes_unref(data);
}
+static void init_ports(RdmaDeviceResources *dev_res)
+{
+ int i;
+
+ memset(&dev_res->port, 0, sizeof(dev_res->port));
+
+ dev_res->port.state = IBV_PORT_DOWN;
+ for (i = 0; i < MAX_PORT_GIDS; i++) {
+ dev_res->port.gid_tbl[i].backend_gid_index = -1;
+ }
+}
+
+static void fini_ports(RdmaDeviceResources *dev_res,
+ RdmaBackendDev *backend_dev, const char *ifname)
+{
+ int i;
+
+ dev_res->port.state = IBV_PORT_DOWN;
+ for (i = 0; i < MAX_PORT_GIDS; i++) {
+ rdma_rm_del_gid(dev_res, backend_dev, ifname, i);
+ }
+}
+
int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
Error **errp)
{
@@ -537,11 +641,16 @@ int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
dev_attr->max_qp_wr, sizeof(void *));
res_tbl_init("UC", &dev_res->uc_tbl, MAX_UCS, sizeof(RdmaRmUC));
+ init_ports(dev_res);
+
return 0;
}
-void rdma_rm_fini(RdmaDeviceResources *dev_res)
+void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname)
{
+ fini_ports(dev_res, backend_dev, ifname);
+
res_tbl_free(&dev_res->uc_tbl);
res_tbl_free(&dev_res->cqe_ctx_tbl);
res_tbl_free(&dev_res->qp_tbl);
@@ -549,5 +658,7 @@ void rdma_rm_fini(RdmaDeviceResources *dev_res)
res_tbl_free(&dev_res->cq_tbl);
res_tbl_free(&dev_res->pd_tbl);
- g_hash_table_destroy(dev_res->qp_hash);
+ if (dev_res->qp_hash) {
+ g_hash_table_destroy(dev_res->qp_hash);
+ }
}
diff --git a/hw/rdma/rdma_rm.h b/hw/rdma/rdma_rm.h
index b4e04cc7b4..3c602c04c0 100644
--- a/hw/rdma/rdma_rm.h
+++ b/hw/rdma/rdma_rm.h
@@ -22,7 +22,8 @@
int rdma_rm_init(RdmaDeviceResources *dev_res, struct ibv_device_attr *dev_attr,
Error **errp);
-void rdma_rm_fini(RdmaDeviceResources *dev_res);
+void rdma_rm_fini(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname);
int rdma_rm_alloc_pd(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
uint32_t *pd_handle, uint32_t ctx_handle);
@@ -55,7 +56,7 @@ int rdma_rm_alloc_qp(RdmaDeviceResources *dev_res, uint32_t pd_handle,
uint32_t recv_cq_handle, void *opaque, uint32_t *qpn);
RdmaRmQP *rdma_rm_get_qp(RdmaDeviceResources *dev_res, uint32_t qpn);
int rdma_rm_modify_qp(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
- uint32_t qp_handle, uint32_t attr_mask,
+ uint32_t qp_handle, uint32_t attr_mask, uint8_t sgid_idx,
union ibv_gid *dgid, uint32_t dqpn,
enum ibv_qp_state qp_state, uint32_t qkey,
uint32_t rq_psn, uint32_t sq_psn);
@@ -69,4 +70,16 @@ int rdma_rm_alloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t *cqe_ctx_id,
void *rdma_rm_get_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id);
void rdma_rm_dealloc_cqe_ctx(RdmaDeviceResources *dev_res, uint32_t cqe_ctx_id);
+int rdma_rm_add_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname, union ibv_gid *gid, int gid_idx);
+int rdma_rm_del_gid(RdmaDeviceResources *dev_res, RdmaBackendDev *backend_dev,
+ const char *ifname, int gid_idx);
+int rdma_rm_get_backend_gid_index(RdmaDeviceResources *dev_res,
+ RdmaBackendDev *backend_dev, int sgid_idx);
+static inline union ibv_gid *rdma_rm_get_gid(RdmaDeviceResources *dev_res,
+ int sgid_idx)
+{
+ return &dev_res->port.gid_tbl[sgid_idx].gid;
+}
+
#endif
diff --git a/hw/rdma/rdma_rm_defs.h b/hw/rdma/rdma_rm_defs.h
index 7228151239..0ba61d1838 100644
--- a/hw/rdma/rdma_rm_defs.h
+++ b/hw/rdma/rdma_rm_defs.h
@@ -18,8 +18,8 @@
#include "rdma_backend_defs.h"
-#define MAX_PORTS 1
-#define MAX_PORT_GIDS 1
+#define MAX_PORTS 1 /* Do not change - we support only one port */
+#define MAX_PORT_GIDS 255
#define MAX_GIDS MAX_PORT_GIDS
#define MAX_PORT_PKEYS 1
#define MAX_PKEYS MAX_PORT_PKEYS
@@ -49,10 +49,16 @@ typedef struct RdmaRmPD {
uint32_t ctx_handle;
} RdmaRmPD;
+typedef enum CQNotificationType {
+ CNT_CLEAR,
+ CNT_ARM,
+ CNT_SET,
+} CQNotificationType;
+
typedef struct RdmaRmCQ {
RdmaBackendCQ backend_cq;
void *opaque;
- bool notify;
+ CQNotificationType notify;
} RdmaRmCQ;
/* MR (DMA region) */
@@ -80,13 +86,18 @@ typedef struct RdmaRmQP {
enum ibv_qp_state qp_state;
} RdmaRmQP;
+typedef struct RdmaRmGid {
+ union ibv_gid gid;
+ int backend_gid_index;
+} RdmaRmGid;
+
typedef struct RdmaRmPort {
- union ibv_gid gid_tbl[MAX_PORT_GIDS];
+ RdmaRmGid gid_tbl[MAX_PORT_GIDS];
enum ibv_port_state state;
} RdmaRmPort;
typedef struct RdmaDeviceResources {
- RdmaRmPort ports[MAX_PORTS];
+ RdmaRmPort port;
RdmaRmResTbl pd_tbl;
RdmaRmResTbl mr_tbl;
RdmaRmResTbl uc_tbl;
diff --git a/hw/rdma/rdma_utils.c b/hw/rdma/rdma_utils.c
index dc23f158f3..4fbea8cde2 100644
--- a/hw/rdma/rdma_utils.c
+++ b/hw/rdma/rdma_utils.c
@@ -13,6 +13,7 @@
*
*/
+#include "qemu/osdep.h"
#include "rdma_utils.h"
#ifdef PVRDMA_DEBUG
diff --git a/hw/rdma/rdma_utils.h b/hw/rdma/rdma_utils.h
index 04c7c2ef5b..4490ea0b94 100644
--- a/hw/rdma/rdma_utils.h
+++ b/hw/rdma/rdma_utils.h
@@ -17,9 +17,9 @@
#ifndef RDMA_UTILS_H
#define RDMA_UTILS_H
-#include "qemu/osdep.h"
#include "hw/pci/pci.h"
#include "sysemu/dma.h"
+#include "stdio.h"
#define pr_info(fmt, ...) \
fprintf(stdout, "%s: %-20s (%3d): " fmt, "rdma", __func__, __LINE__,\
@@ -40,12 +40,36 @@ extern unsigned long pr_dbg_cnt;
#define pr_dbg(fmt, ...) \
fprintf(stdout, "%lx %ld: %-20s (%3d): " fmt, pthread_self(), pr_dbg_cnt++, \
__func__, __LINE__, ## __VA_ARGS__)
+
+#define pr_dbg_buf(title, buf, len) \
+{ \
+ int i; \
+ char *b = g_malloc0(len * 3 + 1); \
+ char b1[4]; \
+ for (i = 0; i < len; i++) { \
+ sprintf(b1, "%.2X ", buf[i] & 0x000000FF); \
+ strcat(b, b1); \
+ } \
+ pr_dbg("%s (%d): %s\n", title, len, b); \
+ g_free(b); \
+}
+
#else
#define init_pr_dbg(void)
#define pr_dbg(fmt, ...)
+#define pr_dbg_buf(title, buf, len)
#endif
void *rdma_pci_dma_map(PCIDevice *dev, dma_addr_t addr, dma_addr_t plen);
void rdma_pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len);
+static inline void addrconf_addr_eui48(uint8_t *eui, const char *addr)
+{
+ memcpy(eui, addr, 3);
+ eui[3] = 0xFF;
+ eui[4] = 0xFE;
+ memcpy(eui + 5, addr + 3, 3);
+ eui[0] ^= 2;
+}
+
#endif
diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h
index e2d9f93cdf..ffae36986e 100644
--- a/hw/rdma/vmw/pvrdma.h
+++ b/hw/rdma/vmw/pvrdma.h
@@ -17,8 +17,11 @@
#define PVRDMA_PVRDMA_H
#include "qemu/units.h"
+#include "qemu/notify.h"
#include "hw/pci/pci.h"
#include "hw/pci/msix.h"
+#include "chardev/char-fe.h"
+#include "hw/net/vmxnet3_defs.h"
#include "../rdma_backend_defs.h"
#include "../rdma_rm_defs.h"
@@ -51,7 +54,7 @@
#define PVRDMA_FW_VERSION 14
/* Some defaults */
-#define PVRDMA_PKEY 0x7FFF
+#define PVRDMA_PKEY 0xFFFF
typedef struct DSRInfo {
dma_addr_t dma;
@@ -78,11 +81,14 @@ typedef struct PVRDMADev {
int interrupt_mask;
struct ibv_device_attr dev_attr;
uint64_t node_guid;
+ char *backend_eth_device_name;
char *backend_device_name;
- uint8_t backend_gid_idx;
uint8_t backend_port_num;
RdmaBackendDev backend_dev;
RdmaDeviceResources rdma_dev_res;
+ CharBackend mad_chr;
+ VMXNET3State *func0;
+ Notifier shutdown_notifier;
} PVRDMADev;
#define PVRDMA_DEV(dev) OBJECT_CHECK(PVRDMADev, (dev), PVRDMA_HW_NAME)
diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c
index 4faeb21631..89920887bf 100644
--- a/hw/rdma/vmw/pvrdma_cmd.c
+++ b/hw/rdma/vmw/pvrdma_cmd.c
@@ -128,6 +128,9 @@ static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req,
struct pvrdma_port_attr attrs = {0};
pr_dbg("port=%d\n", cmd->port_num);
+ if (cmd->port_num > MAX_PORTS) {
+ return -EINVAL;
+ }
if (rdma_backend_query_port(&dev->backend_dev,
(struct ibv_port_attr *)&attrs)) {
@@ -135,11 +138,9 @@ static int query_port(PVRDMADev *dev, union pvrdma_cmd_req *req,
}
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_QUERY_PORT_RESP;
- resp->hdr.err = 0;
- resp->attrs.state = attrs.state;
+ resp->attrs.state = dev->func0->device_active ? attrs.state :
+ PVRDMA_PORT_DOWN;
resp->attrs.max_mtu = attrs.max_mtu;
resp->attrs.active_mtu = attrs.active_mtu;
resp->attrs.phys_state = attrs.phys_state;
@@ -159,12 +160,16 @@ static int query_pkey(PVRDMADev *dev, union pvrdma_cmd_req *req,
struct pvrdma_cmd_query_pkey_resp *resp = &rsp->query_pkey_resp;
pr_dbg("port=%d\n", cmd->port_num);
+ if (cmd->port_num > MAX_PORTS) {
+ return -EINVAL;
+ }
+
pr_dbg("index=%d\n", cmd->index);
+ if (cmd->index > MAX_PKEYS) {
+ return -EINVAL;
+ }
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_QUERY_PKEY_RESP;
- resp->hdr.err = 0;
resp->pkey = PVRDMA_PKEY;
pr_dbg("pkey=0x%x\n", resp->pkey);
@@ -177,17 +182,15 @@ static int create_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
{
struct pvrdma_cmd_create_pd *cmd = &req->create_pd;
struct pvrdma_cmd_create_pd_resp *resp = &rsp->create_pd_resp;
+ int rc;
pr_dbg("context=0x%x\n", cmd->ctx_handle ? cmd->ctx_handle : 0);
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_CREATE_PD_RESP;
- resp->hdr.err = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev,
- &resp->pd_handle, cmd->ctx_handle);
+ rc = rdma_rm_alloc_pd(&dev->rdma_dev_res, &dev->backend_dev,
+ &resp->pd_handle, cmd->ctx_handle);
- pr_dbg("ret=%d\n", resp->hdr.err);
- return resp->hdr.err;
+ return rc;
}
static int destroy_pd(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -209,10 +212,9 @@ static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
struct pvrdma_cmd_create_mr_resp *resp = &rsp->create_mr_resp;
PCIDevice *pci_dev = PCI_DEVICE(dev);
void *host_virt = NULL;
+ int rc = 0;
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_CREATE_MR_RESP;
pr_dbg("pd_handle=%d\n", cmd->pd_handle);
pr_dbg("access_flags=0x%x\n", cmd->access_flags);
@@ -223,22 +225,18 @@ static int create_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
cmd->length);
if (!host_virt) {
pr_dbg("Failed to map to pdir\n");
- resp->hdr.err = -EINVAL;
- goto out;
+ return -EINVAL;
}
}
- resp->hdr.err = rdma_rm_alloc_mr(&dev->rdma_dev_res, cmd->pd_handle,
- cmd->start, cmd->length, host_virt,
- cmd->access_flags, &resp->mr_handle,
- &resp->lkey, &resp->rkey);
- if (host_virt && !resp->hdr.err) {
+ rc = rdma_rm_alloc_mr(&dev->rdma_dev_res, cmd->pd_handle, cmd->start,
+ cmd->length, host_virt, cmd->access_flags,
+ &resp->mr_handle, &resp->lkey, &resp->rkey);
+ if (rc && host_virt) {
munmap(host_virt, cmd->length);
}
-out:
- pr_dbg("ret=%d\n", resp->hdr.err);
- return resp->hdr.err;
+ return rc;
}
static int destroy_mr(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -261,6 +259,11 @@ static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring,
int rc = -EINVAL;
char ring_name[MAX_RING_NAME_SZ];
+ if (!nchunks || nchunks > PVRDMA_MAX_FAST_REG_PAGES) {
+ pr_dbg("invalid nchunks: %d\n", nchunks);
+ return rc;
+ }
+
pr_dbg("pdir_dma=0x%llx\n", (long long unsigned int)pdir_dma);
dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
if (!dir) {
@@ -310,34 +313,43 @@ out:
return rc;
}
+static void destroy_cq_ring(PvrdmaRing *ring)
+{
+ pvrdma_ring_free(ring);
+ /* ring_state was in slot 1, not 0 so need to jump back */
+ rdma_pci_dma_unmap(ring->dev, --ring->ring_state, TARGET_PAGE_SIZE);
+ g_free(ring);
+}
+
static int create_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp)
{
struct pvrdma_cmd_create_cq *cmd = &req->create_cq;
struct pvrdma_cmd_create_cq_resp *resp = &rsp->create_cq_resp;
PvrdmaRing *ring = NULL;
+ int rc;
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_CREATE_CQ_RESP;
resp->cqe = cmd->cqe;
- resp->hdr.err = create_cq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma,
- cmd->nchunks, cmd->cqe);
- if (resp->hdr.err) {
- goto out;
+ rc = create_cq_ring(PCI_DEVICE(dev), &ring, cmd->pdir_dma, cmd->nchunks,
+ cmd->cqe);
+ if (rc) {
+ return rc;
}
pr_dbg("ring=%p\n", ring);
- resp->hdr.err = rdma_rm_alloc_cq(&dev->rdma_dev_res, &dev->backend_dev,
- cmd->cqe, &resp->cq_handle, ring);
+ rc = rdma_rm_alloc_cq(&dev->rdma_dev_res, &dev->backend_dev, cmd->cqe,
+ &resp->cq_handle, ring);
+ if (rc) {
+ destroy_cq_ring(ring);
+ }
+
resp->cqe = cmd->cqe;
-out:
- pr_dbg("ret=%d\n", resp->hdr.err);
- return resp->hdr.err;
+ return rc;
}
static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -356,10 +368,7 @@ static int destroy_cq(PVRDMADev *dev, union pvrdma_cmd_req *req,
}
ring = (PvrdmaRing *)cq->opaque;
- pvrdma_ring_free(ring);
- /* ring_state was in slot 1, not 0 so need to jump back */
- rdma_pci_dma_unmap(PCI_DEVICE(dev), --ring->ring_state, TARGET_PAGE_SIZE);
- g_free(ring);
+ destroy_cq_ring(ring);
rdma_rm_dealloc_cq(&dev->rdma_dev_res, cmd->cq_handle);
@@ -377,6 +386,12 @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma,
char ring_name[MAX_RING_NAME_SZ];
uint32_t wqe_sz;
+ if (!spages || spages > PVRDMA_MAX_FAST_REG_PAGES
+ || !rpages || rpages > PVRDMA_MAX_FAST_REG_PAGES) {
+ pr_dbg("invalid pages: %d, %d\n", spages, rpages);
+ return rc;
+ }
+
pr_dbg("pdir_dma=0x%llx\n", (long long unsigned int)pdir_dma);
dir = rdma_pci_dma_map(pci_dev, pdir_dma, TARGET_PAGE_SIZE);
if (!dir) {
@@ -451,36 +466,49 @@ out:
return rc;
}
+static void destroy_qp_rings(PvrdmaRing *ring)
+{
+ pr_dbg("sring=%p\n", &ring[0]);
+ pvrdma_ring_free(&ring[0]);
+ pr_dbg("rring=%p\n", &ring[1]);
+ pvrdma_ring_free(&ring[1]);
+
+ rdma_pci_dma_unmap(ring->dev, ring->ring_state, TARGET_PAGE_SIZE);
+ g_free(ring);
+}
+
static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp)
{
struct pvrdma_cmd_create_qp *cmd = &req->create_qp;
struct pvrdma_cmd_create_qp_resp *resp = &rsp->create_qp_resp;
PvrdmaRing *rings = NULL;
+ int rc;
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_CREATE_QP_RESP;
pr_dbg("total_chunks=%d\n", cmd->total_chunks);
pr_dbg("send_chunks=%d\n", cmd->send_chunks);
- resp->hdr.err = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
- cmd->max_send_wr, cmd->max_send_sge,
- cmd->send_chunks, cmd->max_recv_wr,
- cmd->max_recv_sge, cmd->total_chunks -
- cmd->send_chunks - 1);
- if (resp->hdr.err) {
- goto out;
+ rc = create_qp_rings(PCI_DEVICE(dev), cmd->pdir_dma, &rings,
+ cmd->max_send_wr, cmd->max_send_sge, cmd->send_chunks,
+ cmd->max_recv_wr, cmd->max_recv_sge,
+ cmd->total_chunks - cmd->send_chunks - 1);
+ if (rc) {
+ return rc;
}
pr_dbg("rings=%p\n", rings);
- resp->hdr.err = rdma_rm_alloc_qp(&dev->rdma_dev_res, cmd->pd_handle,
- cmd->qp_type, cmd->max_send_wr,
- cmd->max_send_sge, cmd->send_cq_handle,
- cmd->max_recv_wr, cmd->max_recv_sge,
- cmd->recv_cq_handle, rings, &resp->qpn);
+ rc = rdma_rm_alloc_qp(&dev->rdma_dev_res, cmd->pd_handle, cmd->qp_type,
+ cmd->max_send_wr, cmd->max_send_sge,
+ cmd->send_cq_handle, cmd->max_recv_wr,
+ cmd->max_recv_sge, cmd->recv_cq_handle, rings,
+ &resp->qpn);
+ if (rc) {
+ destroy_qp_rings(rings);
+ return rc;
+ }
resp->max_send_wr = cmd->max_send_wr;
resp->max_recv_wr = cmd->max_recv_wr;
@@ -488,32 +516,31 @@ static int create_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
resp->max_recv_sge = cmd->max_recv_sge;
resp->max_inline_data = cmd->max_inline_data;
-out:
- pr_dbg("ret=%d\n", resp->hdr.err);
- return resp->hdr.err;
+ return 0;
}
static int modify_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp)
{
struct pvrdma_cmd_modify_qp *cmd = &req->modify_qp;
+ int rc;
pr_dbg("qp_handle=%d\n", cmd->qp_handle);
memset(rsp, 0, sizeof(*rsp));
- rsp->hdr.response = cmd->hdr.response;
- rsp->hdr.ack = PVRDMA_CMD_MODIFY_QP_RESP;
-
- rsp->hdr.err = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev,
- cmd->qp_handle, cmd->attr_mask,
- (union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid,
- cmd->attrs.dest_qp_num,
- (enum ibv_qp_state)cmd->attrs.qp_state,
- cmd->attrs.qkey, cmd->attrs.rq_psn,
- cmd->attrs.sq_psn);
-
- pr_dbg("ret=%d\n", rsp->hdr.err);
- return rsp->hdr.err;
+
+ /* No need to verify sgid_index since it is u8 */
+
+ rc = rdma_rm_modify_qp(&dev->rdma_dev_res, &dev->backend_dev,
+ cmd->qp_handle, cmd->attr_mask,
+ cmd->attrs.ah_attr.grh.sgid_index,
+ (union ibv_gid *)&cmd->attrs.ah_attr.grh.dgid,
+ cmd->attrs.dest_qp_num,
+ (enum ibv_qp_state)cmd->attrs.qp_state,
+ cmd->attrs.qkey, cmd->attrs.rq_psn,
+ cmd->attrs.sq_psn);
+
+ return rc;
}
static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -522,21 +549,18 @@ static int query_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
struct pvrdma_cmd_query_qp *cmd = &req->query_qp;
struct pvrdma_cmd_query_qp_resp *resp = &rsp->query_qp_resp;
struct ibv_qp_init_attr init_attr;
+ int rc;
pr_dbg("qp_handle=%d\n", cmd->qp_handle);
pr_dbg("attr_mask=0x%x\n", cmd->attr_mask);
memset(rsp, 0, sizeof(*rsp));
- rsp->hdr.response = cmd->hdr.response;
- rsp->hdr.ack = PVRDMA_CMD_QUERY_QP_RESP;
- rsp->hdr.err = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev,
- cmd->qp_handle,
- (struct ibv_qp_attr *)&resp->attrs,
- cmd->attr_mask, &init_attr);
+ rc = rdma_rm_query_qp(&dev->rdma_dev_res, &dev->backend_dev, cmd->qp_handle,
+ (struct ibv_qp_attr *)&resp->attrs, cmd->attr_mask,
+ &init_attr);
- pr_dbg("ret=%d\n", rsp->hdr.err);
- return rsp->hdr.err;
+ return rc;
}
static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -555,13 +579,7 @@ static int destroy_qp(PVRDMADev *dev, union pvrdma_cmd_req *req,
rdma_rm_dealloc_qp(&dev->rdma_dev_res, cmd->qp_handle);
ring = (PvrdmaRing *)qp->opaque;
- pr_dbg("sring=%p\n", &ring[0]);
- pvrdma_ring_free(&ring[0]);
- pr_dbg("rring=%p\n", &ring[1]);
- pvrdma_ring_free(&ring[1]);
-
- rdma_pci_dma_unmap(PCI_DEVICE(dev), ring->ring_state, TARGET_PAGE_SIZE);
- g_free(ring);
+ destroy_qp_rings(ring);
return 0;
}
@@ -570,10 +588,8 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp)
{
struct pvrdma_cmd_create_bind *cmd = &req->create_bind;
-#ifdef PVRDMA_DEBUG
- __be64 *subnet = (__be64 *)&cmd->new_gid[0];
- __be64 *if_id = (__be64 *)&cmd->new_gid[8];
-#endif
+ int rc;
+ union ibv_gid *gid = (union ibv_gid *)&cmd->new_gid;
pr_dbg("index=%d\n", cmd->index);
@@ -582,26 +598,20 @@ static int create_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
}
pr_dbg("gid[%d]=0x%llx,0x%llx\n", cmd->index,
- (long long unsigned int)be64_to_cpu(*subnet),
- (long long unsigned int)be64_to_cpu(*if_id));
-
- /* Driver forces to one port only */
- memcpy(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw, &cmd->new_gid,
- sizeof(cmd->new_gid));
+ (long long unsigned int)be64_to_cpu(gid->global.subnet_prefix),
+ (long long unsigned int)be64_to_cpu(gid->global.interface_id));
- /* TODO: Since drivers stores node_guid at load_dsr phase then this
- * assignment is not relevant, i need to figure out a way how to
- * retrieve MAC of our netdev */
- dev->node_guid = dev->rdma_dev_res.ports[0].gid_tbl[0].global.interface_id;
- pr_dbg("dev->node_guid=0x%llx\n",
- (long long unsigned int)be64_to_cpu(dev->node_guid));
+ rc = rdma_rm_add_gid(&dev->rdma_dev_res, &dev->backend_dev,
+ dev->backend_eth_device_name, gid, cmd->index);
- return 0;
+ return rc;
}
static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp)
{
+ int rc;
+
struct pvrdma_cmd_destroy_bind *cmd = &req->destroy_bind;
pr_dbg("index=%d\n", cmd->index);
@@ -610,10 +620,10 @@ static int destroy_bind(PVRDMADev *dev, union pvrdma_cmd_req *req,
return -EINVAL;
}
- memset(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw, 0,
- sizeof(dev->rdma_dev_res.ports[0].gid_tbl[cmd->index].raw));
+ rc = rdma_rm_del_gid(&dev->rdma_dev_res, &dev->backend_dev,
+ dev->backend_eth_device_name, cmd->index);
- return 0;
+ return rc;
}
static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -621,18 +631,14 @@ static int create_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
{
struct pvrdma_cmd_create_uc *cmd = &req->create_uc;
struct pvrdma_cmd_create_uc_resp *resp = &rsp->create_uc_resp;
+ int rc;
pr_dbg("pfn=%d\n", cmd->pfn);
memset(resp, 0, sizeof(*resp));
- resp->hdr.response = cmd->hdr.response;
- resp->hdr.ack = PVRDMA_CMD_CREATE_UC_RESP;
- resp->hdr.err = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn,
- &resp->ctx_handle);
-
- pr_dbg("ret=%d\n", resp->hdr.err);
+ rc = rdma_rm_alloc_uc(&dev->rdma_dev_res, cmd->pfn, &resp->ctx_handle);
- return 0;
+ return rc;
}
static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
@@ -646,30 +652,32 @@ static int destroy_uc(PVRDMADev *dev, union pvrdma_cmd_req *req,
return 0;
}
+
struct cmd_handler {
uint32_t cmd;
+ uint32_t ack;
int (*exec)(PVRDMADev *dev, union pvrdma_cmd_req *req,
union pvrdma_cmd_resp *rsp);
};
static struct cmd_handler cmd_handlers[] = {
- {PVRDMA_CMD_QUERY_PORT, query_port},
- {PVRDMA_CMD_QUERY_PKEY, query_pkey},
- {PVRDMA_CMD_CREATE_PD, create_pd},
- {PVRDMA_CMD_DESTROY_PD, destroy_pd},
- {PVRDMA_CMD_CREATE_MR, create_mr},
- {PVRDMA_CMD_DESTROY_MR, destroy_mr},
- {PVRDMA_CMD_CREATE_CQ, create_cq},
- {PVRDMA_CMD_RESIZE_CQ, NULL},
- {PVRDMA_CMD_DESTROY_CQ, destroy_cq},
- {PVRDMA_CMD_CREATE_QP, create_qp},
- {PVRDMA_CMD_MODIFY_QP, modify_qp},
- {PVRDMA_CMD_QUERY_QP, query_qp},
- {PVRDMA_CMD_DESTROY_QP, destroy_qp},
- {PVRDMA_CMD_CREATE_UC, create_uc},
- {PVRDMA_CMD_DESTROY_UC, destroy_uc},
- {PVRDMA_CMD_CREATE_BIND, create_bind},
- {PVRDMA_CMD_DESTROY_BIND, destroy_bind},
+ {PVRDMA_CMD_QUERY_PORT, PVRDMA_CMD_QUERY_PORT_RESP, query_port},
+ {PVRDMA_CMD_QUERY_PKEY, PVRDMA_CMD_QUERY_PKEY_RESP, query_pkey},
+ {PVRDMA_CMD_CREATE_PD, PVRDMA_CMD_CREATE_PD_RESP, create_pd},
+ {PVRDMA_CMD_DESTROY_PD, PVRDMA_CMD_DESTROY_PD_RESP_NOOP, destroy_pd},
+ {PVRDMA_CMD_CREATE_MR, PVRDMA_CMD_CREATE_MR_RESP, create_mr},
+ {PVRDMA_CMD_DESTROY_MR, PVRDMA_CMD_DESTROY_MR_RESP_NOOP, destroy_mr},
+ {PVRDMA_CMD_CREATE_CQ, PVRDMA_CMD_CREATE_CQ_RESP, create_cq},
+ {PVRDMA_CMD_RESIZE_CQ, PVRDMA_CMD_RESIZE_CQ_RESP, NULL},
+ {PVRDMA_CMD_DESTROY_CQ, PVRDMA_CMD_DESTROY_CQ_RESP_NOOP, destroy_cq},
+ {PVRDMA_CMD_CREATE_QP, PVRDMA_CMD_CREATE_QP_RESP, create_qp},
+ {PVRDMA_CMD_MODIFY_QP, PVRDMA_CMD_MODIFY_QP_RESP, modify_qp},
+ {PVRDMA_CMD_QUERY_QP, PVRDMA_CMD_QUERY_QP_RESP, query_qp},
+ {PVRDMA_CMD_DESTROY_QP, PVRDMA_CMD_DESTROY_QP_RESP, destroy_qp},
+ {PVRDMA_CMD_CREATE_UC, PVRDMA_CMD_CREATE_UC_RESP, create_uc},
+ {PVRDMA_CMD_DESTROY_UC, PVRDMA_CMD_DESTROY_UC_RESP_NOOP, destroy_uc},
+ {PVRDMA_CMD_CREATE_BIND, PVRDMA_CMD_CREATE_BIND_RESP_NOOP, create_bind},
+ {PVRDMA_CMD_DESTROY_BIND, PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, destroy_bind},
};
int execute_command(PVRDMADev *dev)
@@ -692,7 +700,12 @@ int execute_command(PVRDMADev *dev)
}
err = cmd_handlers[dsr_info->req->hdr.cmd].exec(dev, dsr_info->req,
- dsr_info->rsp);
+ dsr_info->rsp);
+ dsr_info->rsp->hdr.response = dsr_info->req->hdr.response;
+ dsr_info->rsp->hdr.ack = cmd_handlers[dsr_info->req->hdr.cmd].ack;
+ dsr_info->rsp->hdr.err = err < 0 ? -err : 0;
+ pr_dbg("rsp->hdr.err=%d\n", dsr_info->rsp->hdr.err);
+
out:
set_reg_val(dev, PVRDMA_REG_ERR, err);
post_interrupt(dev, INTR_VEC_CMD_RING);
diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c
index 01247fc041..e8e5b502f6 100644
--- a/hw/rdma/vmw/pvrdma_dev_ring.c
+++ b/hw/rdma/vmw/pvrdma_dev_ring.c
@@ -73,23 +73,16 @@ out:
void *pvrdma_ring_next_elem_read(PvrdmaRing *ring)
{
+ int e;
unsigned int idx = 0, offset;
- /*
- pr_dbg("%s: t=%d, h=%d\n", ring->name, ring->ring_state->prod_tail,
- ring->ring_state->cons_head);
- */
-
- if (!pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx)) {
+ e = pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx);
+ if (e <= 0) {
pr_dbg("No more data in ring\n");
return NULL;
}
offset = idx * ring->elem_sz;
- /*
- pr_dbg("idx=%d\n", idx);
- pr_dbg("offset=%d\n", offset);
- */
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
}
@@ -105,20 +98,20 @@ void pvrdma_ring_read_inc(PvrdmaRing *ring)
void *pvrdma_ring_next_elem_write(PvrdmaRing *ring)
{
- unsigned int idx, offset, tail;
+ int idx;
+ unsigned int offset, tail;
- /*
- pr_dbg("%s: t=%d, h=%d\n", ring->name, ring->ring_state->prod_tail,
- ring->ring_state->cons_head);
- */
-
- if (!pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail)) {
+ idx = pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail);
+ if (idx <= 0) {
pr_dbg("CQ is full\n");
return NULL;
}
idx = pvrdma_idx(&ring->ring_state->prod_tail, ring->max_elems);
- /* TODO: tail == idx */
+ if (idx < 0 || tail != idx) {
+ pr_dbg("invalid idx\n");
+ return NULL;
+ }
offset = idx * ring->elem_sz;
return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE);
diff --git a/hw/rdma/vmw/pvrdma_dev_ring.h b/hw/rdma/vmw/pvrdma_dev_ring.h
index 411d244603..5f2a0cf9b9 100644
--- a/hw/rdma/vmw/pvrdma_dev_ring.h
+++ b/hw/rdma/vmw/pvrdma_dev_ring.h
@@ -16,7 +16,6 @@
#ifndef PVRDMA_DEV_RING_H
#define PVRDMA_DEV_RING_H
-#include "qemu/typedefs.h"
#define MAX_RING_NAME_SZ 32
diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c
index ca5fa8d981..d2bdb5ba8c 100644
--- a/hw/rdma/vmw/pvrdma_main.c
+++ b/hw/rdma/vmw/pvrdma_main.c
@@ -24,6 +24,7 @@
#include "hw/qdev-properties.h"
#include "cpu.h"
#include "trace.h"
+#include "sysemu/sysemu.h"
#include "../rdma_rm.h"
#include "../rdma_backend.h"
@@ -36,13 +37,12 @@
#include "pvrdma_qp_ops.h"
static Property pvrdma_dev_properties[] = {
- DEFINE_PROP_STRING("backend-dev", PVRDMADev, backend_device_name),
- DEFINE_PROP_UINT8("backend-port", PVRDMADev, backend_port_num, 1),
- DEFINE_PROP_UINT8("backend-gid-idx", PVRDMADev, backend_gid_idx, 0),
+ DEFINE_PROP_STRING("netdev", PVRDMADev, backend_eth_device_name),
+ DEFINE_PROP_STRING("ibdev", PVRDMADev, backend_device_name),
+ DEFINE_PROP_UINT8("ibport", PVRDMADev, backend_port_num, 1),
DEFINE_PROP_UINT64("dev-caps-max-mr-size", PVRDMADev, dev_attr.max_mr_size,
MAX_MR_SIZE),
DEFINE_PROP_INT32("dev-caps-max-qp", PVRDMADev, dev_attr.max_qp, MAX_QP),
- DEFINE_PROP_INT32("dev-caps-max-sge", PVRDMADev, dev_attr.max_sge, MAX_SGE),
DEFINE_PROP_INT32("dev-caps-max-cq", PVRDMADev, dev_attr.max_cq, MAX_CQ),
DEFINE_PROP_INT32("dev-caps-max-mr", PVRDMADev, dev_attr.max_mr, MAX_MR),
DEFINE_PROP_INT32("dev-caps-max-pd", PVRDMADev, dev_attr.max_pd, MAX_PD),
@@ -51,6 +51,7 @@ static Property pvrdma_dev_properties[] = {
DEFINE_PROP_INT32("dev-caps-max-qp-init-rd-atom", PVRDMADev,
dev_attr.max_qp_init_rd_atom, MAX_QP_INIT_RD_ATOM),
DEFINE_PROP_INT32("dev-caps-max-ah", PVRDMADev, dev_attr.max_ah, MAX_AH),
+ DEFINE_PROP_CHR("mad-chardev", PVRDMADev, mad_chr),
DEFINE_PROP_END_OF_LIST(),
};
@@ -263,7 +264,7 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
dsr->caps.sys_image_guid = 0;
pr_dbg("sys_image_guid=%" PRIx64 "\n", dsr->caps.sys_image_guid);
- dsr->caps.node_guid = cpu_to_be64(dev->node_guid);
+ dsr->caps.node_guid = dev->node_guid;
pr_dbg("node_guid=%" PRIx64 "\n", be64_to_cpu(dsr->caps.node_guid));
dsr->caps.phys_port_cnt = MAX_PORTS;
@@ -275,17 +276,6 @@ static void init_dsr_dev_caps(PVRDMADev *dev)
pr_dbg("Initialized\n");
}
-static void init_ports(PVRDMADev *dev, Error **errp)
-{
- int i;
-
- memset(dev->rdma_dev_res.ports, 0, sizeof(dev->rdma_dev_res.ports));
-
- for (i = 0; i < MAX_PORTS; i++) {
- dev->rdma_dev_res.ports[i].state = IBV_PORT_DOWN;
- }
-}
-
static void uninit_msix(PCIDevice *pdev, int used_vectors)
{
PVRDMADev *dev = PVRDMA_DEV(pdev);
@@ -334,7 +324,8 @@ static void pvrdma_fini(PCIDevice *pdev)
pvrdma_qp_ops_fini();
- rdma_rm_fini(&dev->rdma_dev_res);
+ rdma_rm_fini(&dev->rdma_dev_res, &dev->backend_dev,
+ dev->backend_eth_device_name);
rdma_backend_fini(&dev->backend_dev);
@@ -343,6 +334,9 @@ static void pvrdma_fini(PCIDevice *pdev)
if (msix_enabled(pdev)) {
uninit_msix(pdev, RDMA_MAX_INTRS);
}
+
+ pr_dbg("Device %s %x.%x is down\n", pdev->name, PCI_SLOT(pdev->devfn),
+ PCI_FUNC(pdev->devfn));
}
static void pvrdma_stop(PVRDMADev *dev)
@@ -368,13 +362,11 @@ static int unquiesce_device(PVRDMADev *dev)
return 0;
}
-static int reset_device(PVRDMADev *dev)
+static void reset_device(PVRDMADev *dev)
{
pvrdma_stop(dev);
pr_dbg("Device reset complete\n");
-
- return 0;
}
static uint64_t regs_read(void *opaque, hwaddr addr, unsigned size)
@@ -455,6 +447,11 @@ static const MemoryRegionOps regs_ops = {
},
};
+static uint64_t uar_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0xffffffff;
+}
+
static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
PVRDMADev *dev = opaque;
@@ -496,6 +493,7 @@ static void uar_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
}
static const MemoryRegionOps uar_ops = {
+ .read = uar_read,
.write = uar_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
@@ -550,8 +548,9 @@ static void init_dev_caps(PVRDMADev *dev)
sizeof(struct pvrdma_rq_wqe_hdr));
dev->dev_attr.max_qp_wr = pg_tbl_bytes /
- (wr_sz + sizeof(struct pvrdma_sge) * MAX_SGE) -
- TARGET_PAGE_SIZE; /* First page is ring state */
+ (wr_sz + sizeof(struct pvrdma_sge) *
+ dev->dev_attr.max_sge) - TARGET_PAGE_SIZE;
+ /* First page is ring state ^^^^ */
pr_dbg("max_qp_wr=%d\n", dev->dev_attr.max_qp_wr);
dev->dev_attr.max_cqe = pg_tbl_bytes / sizeof(struct pvrdma_cqe) -
@@ -570,12 +569,21 @@ static int pvrdma_check_ram_shared(Object *obj, void *opaque)
return 0;
}
+static void pvrdma_shutdown_notifier(Notifier *n, void *opaque)
+{
+ PVRDMADev *dev = container_of(n, PVRDMADev, shutdown_notifier);
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
+
+ pvrdma_fini(pci_dev);
+}
+
static void pvrdma_realize(PCIDevice *pdev, Error **errp)
{
- int rc;
+ int rc = 0;
PVRDMADev *dev = PVRDMA_DEV(pdev);
Object *memdev_root;
bool ram_shared = false;
+ PCIDevice *func0;
init_pr_dbg();
@@ -587,6 +595,20 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
return;
}
+ func0 = pci_get_function_0(pdev);
+ /* Break if not vmxnet3 device in slot 0 */
+ if (strcmp(object_get_typename(&func0->qdev.parent_obj), TYPE_VMXNET3)) {
+ pr_dbg("func0 type is %s\n",
+ object_get_typename(&func0->qdev.parent_obj));
+ error_setg(errp, "Device on %x.0 must be %s", PCI_SLOT(pdev->devfn),
+ TYPE_VMXNET3);
+ return;
+ }
+ dev->func0 = VMXNET3(func0);
+
+ addrconf_addr_eui48((unsigned char *)&dev->node_guid,
+ (const char *)&dev->func0->conf.macaddr.a);
+
memdev_root = object_resolve_path("/objects", NULL);
if (memdev_root) {
object_child_foreach(memdev_root, pvrdma_check_ram_shared, &ram_shared);
@@ -604,8 +626,6 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
init_regs(pdev);
- init_dev_caps(dev);
-
rc = init_msix(pdev, errp);
if (rc) {
goto out;
@@ -613,25 +633,29 @@ static void pvrdma_realize(PCIDevice *pdev, Error **errp)
rc = rdma_backend_init(&dev->backend_dev, pdev, &dev->rdma_dev_res,
dev->backend_device_name, dev->backend_port_num,
- dev->backend_gid_idx, &dev->dev_attr, errp);
+ &dev->dev_attr, &dev->mad_chr, errp);
if (rc) {
goto out;
}
+ init_dev_caps(dev);
+
rc = rdma_rm_init(&dev->rdma_dev_res, &dev->dev_attr, errp);
if (rc) {
goto out;
}
- init_ports(dev, errp);
-
rc = pvrdma_qp_ops_init();
if (rc) {
goto out;
}
+ dev->shutdown_notifier.notify = pvrdma_shutdown_notifier;
+ qemu_register_shutdown_notifier(&dev->shutdown_notifier);
+
out:
if (rc) {
+ pvrdma_fini(pdev);
error_append_hint(errp, "Device fail to load\n");
}
}
diff --git a/hw/rdma/vmw/pvrdma_qp_ops.c b/hw/rdma/vmw/pvrdma_qp_ops.c
index c668afd0ed..ce5a60e184 100644
--- a/hw/rdma/vmw/pvrdma_qp_ops.c
+++ b/hw/rdma/vmw/pvrdma_qp_ops.c
@@ -47,7 +47,7 @@ typedef struct PvrdmaRqWqe {
* 3. Interrupt host
*/
static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
- struct pvrdma_cqe *cqe)
+ struct pvrdma_cqe *cqe, struct ibv_wc *wc)
{
struct pvrdma_cqe *cqe1;
struct pvrdma_cqne *cqne;
@@ -66,6 +66,7 @@ static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
pr_dbg("Writing CQE\n");
cqe1 = pvrdma_ring_next_elem_write(ring);
if (unlikely(!cqe1)) {
+ pr_dbg("No CQEs in ring\n");
return -EINVAL;
}
@@ -73,8 +74,20 @@ static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
cqe1->wr_id = cqe->wr_id;
cqe1->qp = cqe->qp;
cqe1->opcode = cqe->opcode;
- cqe1->status = cqe->status;
- cqe1->vendor_err = cqe->vendor_err;
+ cqe1->status = wc->status;
+ cqe1->byte_len = wc->byte_len;
+ cqe1->src_qp = wc->src_qp;
+ cqe1->wc_flags = wc->wc_flags;
+ cqe1->vendor_err = wc->vendor_err;
+
+ pr_dbg("wr_id=%" PRIx64 "\n", cqe1->wr_id);
+ pr_dbg("qp=0x%lx\n", cqe1->qp);
+ pr_dbg("opcode=%d\n", cqe1->opcode);
+ pr_dbg("status=%d\n", cqe1->status);
+ pr_dbg("byte_len=%d\n", cqe1->byte_len);
+ pr_dbg("src_qp=%d\n", cqe1->src_qp);
+ pr_dbg("wc_flags=%d\n", cqe1->wc_flags);
+ pr_dbg("vendor_err=%d\n", cqe1->vendor_err);
pvrdma_ring_write_inc(ring);
@@ -89,29 +102,35 @@ static int pvrdma_post_cqe(PVRDMADev *dev, uint32_t cq_handle,
pvrdma_ring_write_inc(&dev->dsr_info.cq);
pr_dbg("cq->notify=%d\n", cq->notify);
- if (cq->notify) {
- cq->notify = false;
+ if (cq->notify != CNT_CLEAR) {
+ if (cq->notify == CNT_ARM) {
+ cq->notify = CNT_CLEAR;
+ }
post_interrupt(dev, INTR_VEC_CMD_COMPLETION_Q);
}
return 0;
}
-static void pvrdma_qp_ops_comp_handler(int status, unsigned int vendor_err,
- void *ctx)
+static void pvrdma_qp_ops_comp_handler(void *ctx, struct ibv_wc *wc)
{
CompHandlerCtx *comp_ctx = (CompHandlerCtx *)ctx;
- pr_dbg("cq_handle=%d\n", comp_ctx->cq_handle);
- pr_dbg("wr_id=%" PRIx64 "\n", comp_ctx->cqe.wr_id);
- pr_dbg("status=%d\n", status);
- pr_dbg("vendor_err=0x%x\n", vendor_err);
- comp_ctx->cqe.status = status;
- comp_ctx->cqe.vendor_err = vendor_err;
- pvrdma_post_cqe(comp_ctx->dev, comp_ctx->cq_handle, &comp_ctx->cqe);
+ pvrdma_post_cqe(comp_ctx->dev, comp_ctx->cq_handle, &comp_ctx->cqe, wc);
+
g_free(ctx);
}
+static void complete_with_error(uint32_t vendor_err, void *ctx)
+{
+ struct ibv_wc wc = {0};
+
+ wc.status = IBV_WC_GENERAL_ERR;
+ wc.vendor_err = vendor_err;
+
+ pvrdma_qp_ops_comp_handler(ctx, &wc);
+}
+
void pvrdma_qp_ops_fini(void)
{
rdma_backend_unregister_comp_handler();
@@ -124,17 +143,20 @@ int pvrdma_qp_ops_init(void)
return 0;
}
-int pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle)
+void pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle)
{
RdmaRmQP *qp;
PvrdmaSqWqe *wqe;
PvrdmaRing *ring;
+ int sgid_idx;
+ union ibv_gid *sgid;
pr_dbg("qp_handle=0x%x\n", qp_handle);
qp = rdma_rm_get_qp(&dev->rdma_dev_res, qp_handle);
if (unlikely(!qp)) {
- return -EINVAL;
+ pr_dbg("Invalid qpn\n");
+ return;
}
ring = (PvrdmaRing *)qp->opaque;
@@ -152,10 +174,37 @@ int pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle)
comp_ctx->cq_handle = qp->send_cq_handle;
comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
comp_ctx->cqe.qp = qp_handle;
- comp_ctx->cqe.opcode = wqe->hdr.opcode;
+ comp_ctx->cqe.opcode = IBV_WC_SEND;
+
+ sgid = rdma_rm_get_gid(&dev->rdma_dev_res, wqe->hdr.wr.ud.av.gid_index);
+ if (!sgid) {
+ pr_dbg("Fail to get gid for idx %d\n", wqe->hdr.wr.ud.av.gid_index);
+ complete_with_error(VENDOR_ERR_INV_GID_IDX, comp_ctx);
+ continue;
+ }
+ pr_dbg("sgid_id=%d, sgid=0x%llx\n", wqe->hdr.wr.ud.av.gid_index,
+ sgid->global.interface_id);
+
+ sgid_idx = rdma_rm_get_backend_gid_index(&dev->rdma_dev_res,
+ &dev->backend_dev,
+ wqe->hdr.wr.ud.av.gid_index);
+ if (sgid_idx <= 0) {
+ pr_dbg("Fail to get bk sgid_idx for sgid_idx %d\n",
+ wqe->hdr.wr.ud.av.gid_index);
+ complete_with_error(VENDOR_ERR_INV_GID_IDX, comp_ctx);
+ continue;
+ }
+
+ if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
+ pr_dbg("Invalid num_sge=%d (max %d)\n", wqe->hdr.num_sge,
+ dev->dev_attr.max_sge);
+ complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
+ continue;
+ }
rdma_backend_post_send(&dev->backend_dev, &qp->backend_qp, qp->qp_type,
(struct ibv_sge *)&wqe->sge[0], wqe->hdr.num_sge,
+ sgid_idx, sgid,
(union ibv_gid *)wqe->hdr.wr.ud.av.dgid,
wqe->hdr.wr.ud.remote_qpn,
wqe->hdr.wr.ud.remote_qkey, comp_ctx);
@@ -164,11 +213,9 @@ int pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle)
wqe = pvrdma_ring_next_elem_read(ring);
}
-
- return 0;
}
-int pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
+void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
{
RdmaRmQP *qp;
PvrdmaRqWqe *wqe;
@@ -178,7 +225,8 @@ int pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
qp = rdma_rm_get_qp(&dev->rdma_dev_res, qp_handle);
if (unlikely(!qp)) {
- return -EINVAL;
+ pr_dbg("Invalid qpn\n");
+ return;
}
ring = &((PvrdmaRing *)qp->opaque)[1];
@@ -194,8 +242,16 @@ int pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
comp_ctx = g_malloc(sizeof(CompHandlerCtx));
comp_ctx->dev = dev;
comp_ctx->cq_handle = qp->recv_cq_handle;
- comp_ctx->cqe.qp = qp_handle;
comp_ctx->cqe.wr_id = wqe->hdr.wr_id;
+ comp_ctx->cqe.qp = qp_handle;
+ comp_ctx->cqe.opcode = IBV_WC_RECV;
+
+ if (wqe->hdr.num_sge > dev->dev_attr.max_sge) {
+ pr_dbg("Invalid num_sge=%d (max %d)\n", wqe->hdr.num_sge,
+ dev->dev_attr.max_sge);
+ complete_with_error(VENDOR_ERR_INV_NUM_SGE, comp_ctx);
+ continue;
+ }
rdma_backend_post_recv(&dev->backend_dev, &dev->rdma_dev_res,
&qp->backend_qp, qp->qp_type,
@@ -206,8 +262,6 @@ int pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle)
wqe = pvrdma_ring_next_elem_read(ring);
}
-
- return 0;
}
void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle)
diff --git a/hw/rdma/vmw/pvrdma_qp_ops.h b/hw/rdma/vmw/pvrdma_qp_ops.h
index ac46bf7fdf..31cb48ba29 100644
--- a/hw/rdma/vmw/pvrdma_qp_ops.h
+++ b/hw/rdma/vmw/pvrdma_qp_ops.h
@@ -20,8 +20,8 @@
int pvrdma_qp_ops_init(void);
void pvrdma_qp_ops_fini(void);
-int pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle);
-int pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle);
+void pvrdma_qp_send(PVRDMADev *dev, uint32_t qp_handle);
+void pvrdma_qp_recv(PVRDMADev *dev, uint32_t qp_handle);
void pvrdma_cq_poll(RdmaDeviceResources *dev_res, uint32_t cq_handle);
#endif
diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c
index 0d2fd52487..d4c159e937 100644
--- a/hw/riscv/sifive_clint.c
+++ b/hw/riscv/sifive_clint.c
@@ -146,15 +146,15 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
error_report("clint: invalid timecmp hartid: %zu", hartid);
} else if ((addr & 0x7) == 0) {
/* timecmp_lo */
- uint64_t timecmp = env->timecmp;
+ uint64_t timecmp_hi = env->timecmp >> 32;
sifive_clint_write_timecmp(RISCV_CPU(cpu),
- timecmp << 32 | (value & 0xFFFFFFFF));
+ timecmp_hi << 32 | (value & 0xFFFFFFFF));
return;
} else if ((addr & 0x7) == 4) {
/* timecmp_hi */
- uint64_t timecmp = env->timecmp;
+ uint64_t timecmp_lo = env->timecmp;
sifive_clint_write_timecmp(RISCV_CPU(cpu),
- value << 32 | (timecmp & 0xFFFFFFFF));
+ value << 32 | (timecmp_lo & 0xFFFFFFFF));
} else {
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
}
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index cb513cc3bb..5d9d65ff29 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -192,9 +192,8 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size);
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
- /* sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
- serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
- SIFIVE_E_UART1_IRQ)); */
+ sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
+ serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ));
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
index 9cf9a1f986..d12ec3fc9a 100644
--- a/hw/riscv/sifive_plic.c
+++ b/hw/riscv/sifive_plic.c
@@ -214,7 +214,7 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
} else if (addr >= plic->pending_base && /* 1 bit per source */
addr < plic->pending_base + (plic->num_sources >> 3))
{
- uint32_t word = (addr - plic->priority_base) >> 2;
+ uint32_t word = (addr - plic->pending_base) >> 2;
if (RISCV_DEBUG_PLIC) {
qemu_log("plic: read pending: word=%d value=%d\n",
word, plic->pending[word]);
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index ef07df2442..3bd3b67507 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -85,7 +85,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
int cpu;
uint32_t *cells;
char *nodename;
- uint32_t plic_phandle;
+ char ethclk_names[] = "pclk\0hclk\0tx_clk";
+ uint32_t plic_phandle, ethclk_phandle;
fdt = s->fdt = create_device_tree(&s->fdt_size);
if (!fdt) {
@@ -197,6 +198,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
g_free(cells);
g_free(nodename);
+ nodename = g_strdup_printf("/soc/ethclk");
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock");
+ qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0);
+ qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
+ SIFIVE_U_GEM_CLOCK_FREQ);
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", 3);
+ qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", 3);
+ ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename);
+ g_free(nodename);
+
nodename = g_strdup_printf("/soc/ethernet@%lx",
(long)memmap[SIFIVE_U_GEM].base);
qemu_fdt_add_subnode(fdt, nodename);
@@ -208,6 +220,10 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
+ qemu_fdt_setprop_cells(fdt, nodename, "clocks",
+ ethclk_phandle, ethclk_phandle, ethclk_phandle);
+ qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names,
+ sizeof(ethclk_names));
qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1);
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
g_free(nodename);
@@ -225,6 +241,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_UART0].base,
0x0, memmap[SIFIVE_U_UART0].size);
+ qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
+ SIFIVE_U_CLOCK_FREQ / 2);
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1);
@@ -350,9 +368,8 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_U_PLIC].size);
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
- /* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
- serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
- SIFIVE_U_UART1_IRQ)); */
+ sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
+ serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
memmap[SIFIVE_U_CLINT].size, smp_cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c
index b0c3798cf2..456a3d3697 100644
--- a/hw/riscv/sifive_uart.c
+++ b/hw/riscv/sifive_uart.c
@@ -28,12 +28,26 @@
* Not yet implemented:
*
* Transmit FIFO using "qemu/fifo8.h"
- * SIFIVE_UART_IE_TXWM interrupts
- * SIFIVE_UART_IE_RXWM interrupts must honor fifo watermark
- * Rx FIFO watermark interrupt trigger threshold
- * Tx FIFO watermark interrupt trigger threshold.
*/
+/* Returns the state of the IP (interrupt pending) register */
+static uint64_t uart_ip(SiFiveUARTState *s)
+{
+ uint64_t ret = 0;
+
+ uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl);
+ uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl);
+
+ if (txcnt != 0) {
+ ret |= SIFIVE_UART_IP_TXWM;
+ }
+ if (s->rx_fifo_len > rxcnt) {
+ ret |= SIFIVE_UART_IP_RXWM;
+ }
+
+ return ret;
+}
+
static void update_irq(SiFiveUARTState *s)
{
int cond = 0;
@@ -69,7 +83,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
case SIFIVE_UART_IE:
return s->ie;
case SIFIVE_UART_IP:
- return s->rx_fifo_len ? SIFIVE_UART_IP_RXWM : 0;
+ return uart_ip(s);
case SIFIVE_UART_TXCTRL:
return s->txctrl;
case SIFIVE_UART_RXCTRL:
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 2b38f89070..e7f0716fb6 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -39,6 +39,8 @@
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "exec/address-spaces.h"
+#include "hw/pci/pci.h"
+#include "hw/pci-host/gpex.h"
#include "elf.h"
#include <libfdt.h>
@@ -47,14 +49,17 @@ static const struct MemmapEntry {
hwaddr base;
hwaddr size;
} virt_memmap[] = {
- [VIRT_DEBUG] = { 0x0, 0x100 },
- [VIRT_MROM] = { 0x1000, 0x11000 },
- [VIRT_TEST] = { 0x100000, 0x1000 },
- [VIRT_CLINT] = { 0x2000000, 0x10000 },
- [VIRT_PLIC] = { 0xc000000, 0x4000000 },
- [VIRT_UART0] = { 0x10000000, 0x100 },
- [VIRT_VIRTIO] = { 0x10001000, 0x1000 },
- [VIRT_DRAM] = { 0x80000000, 0x0 },
+ [VIRT_DEBUG] = { 0x0, 0x100 },
+ [VIRT_MROM] = { 0x1000, 0x11000 },
+ [VIRT_TEST] = { 0x100000, 0x1000 },
+ [VIRT_CLINT] = { 0x2000000, 0x10000 },
+ [VIRT_PLIC] = { 0xc000000, 0x4000000 },
+ [VIRT_UART0] = { 0x10000000, 0x100 },
+ [VIRT_VIRTIO] = { 0x10001000, 0x1000 },
+ [VIRT_DRAM] = { 0x80000000, 0x0 },
+ [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
+ [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
+ [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
};
static uint64_t load_kernel(const char *kernel_filename)
@@ -98,6 +103,51 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size,
return *start + size;
}
+static void create_pcie_irq_map(void *fdt, char *nodename,
+ uint32_t plic_phandle)
+{
+ int pin, dev;
+ uint32_t
+ full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {};
+ uint32_t *irq_map = full_irq_map;
+
+ /* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+ for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+ int devfn = dev * 0x8;
+
+ for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
+ int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+ int i = 0;
+
+ irq_map[i] = cpu_to_be32(devfn << 8);
+
+ i += FDT_PCI_ADDR_CELLS;
+ irq_map[i] = cpu_to_be32(pin + 1);
+
+ i += FDT_PCI_INT_CELLS;
+ irq_map[i++] = cpu_to_be32(plic_phandle);
+
+ i += FDT_PLIC_ADDR_CELLS;
+ irq_map[i] = cpu_to_be32(irq_nr);
+
+ irq_map += FDT_INT_MAP_WIDTH;
+ }
+ }
+
+ qemu_fdt_setprop(fdt, nodename, "interrupt-map",
+ full_irq_map, sizeof(full_irq_map));
+
+ qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
uint64_t mem_size, const char *cmdline)
{
@@ -203,7 +253,10 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
(long)memmap[VIRT_PLIC].base);
qemu_fdt_add_subnode(fdt, nodename);
- qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
+ qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
+ FDT_PLIC_ADDR_CELLS);
+ qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
+ FDT_PLIC_INT_CELLS);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
@@ -233,6 +286,33 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
g_free(nodename);
}
+ nodename = g_strdup_printf("/soc/pci@%lx",
+ (long) memmap[VIRT_PCIE_ECAM].base);
+ qemu_fdt_add_subnode(fdt, nodename);
+ qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
+ FDT_PCI_ADDR_CELLS);
+ qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells",
+ FDT_PCI_INT_CELLS);
+ qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2);
+ qemu_fdt_setprop_string(fdt, nodename, "compatible",
+ "pci-host-ecam-generic");
+ qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
+ qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0);
+ qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0,
+ memmap[VIRT_PCIE_ECAM].base /
+ PCIE_MMCFG_SIZE_MIN - 1);
+ qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
+ qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base,
+ 0, memmap[VIRT_PCIE_ECAM].size);
+ qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges",
+ 1, FDT_PCI_RANGE_IOPORT, 2, 0,
+ 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
+ 1, FDT_PCI_RANGE_MMIO,
+ 2, memmap[VIRT_PCIE_MMIO].base,
+ 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size);
+ create_pcie_irq_map(fdt, nodename, plic_phandle);
+ g_free(nodename);
+
nodename = g_strdup_printf("/test@%lx",
(long)memmap[VIRT_TEST].base);
qemu_fdt_add_subnode(fdt, nodename);
@@ -263,6 +343,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
return fdt;
}
+
+static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
+ hwaddr ecam_base, hwaddr ecam_size,
+ hwaddr mmio_base, hwaddr mmio_size,
+ hwaddr pio_base,
+ DeviceState *plic, bool link_up)
+{
+ DeviceState *dev;
+ MemoryRegion *ecam_alias, *ecam_reg;
+ MemoryRegion *mmio_alias, *mmio_reg;
+ qemu_irq irq;
+ int i;
+
+ dev = qdev_create(NULL, TYPE_GPEX_HOST);
+
+ qdev_init_nofail(dev);
+
+ ecam_alias = g_new0(MemoryRegion, 1);
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+ ecam_reg, 0, ecam_size);
+ memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
+
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg, mmio_base, mmio_size);
+ memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ irq = qdev_get_gpio_in(plic, PCIE_IRQ + i);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+ gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
+ }
+
+ return dev;
+}
+
static void riscv_virt_board_init(MachineState *machine)
{
const struct MemmapEntry *memmap = virt_memmap;
@@ -385,6 +506,14 @@ static void riscv_virt_board_init(MachineState *machine)
qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i));
}
+ gpex_pcie_init(system_memory,
+ memmap[VIRT_PCIE_ECAM].base,
+ memmap[VIRT_PCIE_ECAM].size,
+ memmap[VIRT_PCIE_MMIO].base,
+ memmap[VIRT_PCIE_MMIO].size,
+ memmap[VIRT_PCIE_PIO].base,
+ DEVICE(s->plic), true);
+
serial_mm_init(system_memory, memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN);
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 04ec5cc970..f92b046cd3 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -1290,9 +1290,19 @@ void copy_scsw_to_guest(SCSW *dest, const SCSW *src)
static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
{
int i;
-
- copy_pmcw_to_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_to_guest(&dest->scsw, &src->scsw);
+ /*
+ * We copy the PMCW and SCSW in and out of local variables to
+ * avoid taking the address of members of a packed struct.
+ */
+ PMCW src_pmcw, dest_pmcw;
+ SCSW src_scsw, dest_scsw;
+
+ src_pmcw = src->pmcw;
+ copy_pmcw_to_guest(&dest_pmcw, &src_pmcw);
+ dest->pmcw = dest_pmcw;
+ src_scsw = src->scsw;
+ copy_scsw_to_guest(&dest_scsw, &src_scsw);
+ dest->scsw = dest_scsw;
dest->mba = cpu_to_be64(src->mba);
for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
dest->mda[i] = src->mda[i];
@@ -1339,9 +1349,19 @@ static void copy_scsw_from_guest(SCSW *dest, const SCSW *src)
static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src)
{
int i;
-
- copy_pmcw_from_guest(&dest->pmcw, &src->pmcw);
- copy_scsw_from_guest(&dest->scsw, &src->scsw);
+ /*
+ * We copy the PMCW and SCSW in and out of local variables to
+ * avoid taking the address of members of a packed struct.
+ */
+ PMCW src_pmcw, dest_pmcw;
+ SCSW src_scsw, dest_scsw;
+
+ src_pmcw = src->pmcw;
+ copy_pmcw_from_guest(&dest_pmcw, &src_pmcw);
+ dest->pmcw = dest_pmcw;
+ src_scsw = src->scsw;
+ copy_scsw_from_guest(&dest_scsw, &src_scsw);
+ dest->scsw = dest_scsw;
dest->mba = be64_to_cpu(src->mba);
for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
dest->mda[i] = src->mda[i];
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 060ff062bc..f017c1ded0 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -660,7 +660,7 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
- name, iommu->pal + 1);
+ name, iommu->pal - iommu->pba + 1);
iommu->enabled = true;
memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
g_free(name);
@@ -731,9 +731,7 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp)
css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false,
S390_ADAPTER_SUPPRESSIBLE, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- }
+ error_propagate(errp, local_err);
}
static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
@@ -745,7 +743,6 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX);
if (!pos) {
- pbdev->msix.available = false;
return -1;
}
@@ -761,7 +758,6 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
pbdev->msix.pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
- pbdev->msix.available = true;
name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
@@ -822,27 +818,42 @@ static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
}
pbdev->idx = idx;
- s->next_idx = (idx + 1) & FH_MASK_INDEX;
-
return true;
}
-static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
+static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
- PCIDevice *pdev = NULL;
- S390PCIBusDevice *pbdev = NULL;
- S390pciState *s = s390_get_phb();
+ S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
- if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
- BusState *bus;
- PCIBridge *pb = PCI_BRIDGE(dev);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
PCIDevice *pdev = PCI_DEVICE(dev);
if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
error_setg(errp, "multifunction not supported in s390");
return;
}
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
+ S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev);
+
+ if (!s390_pci_alloc_idx(s, pbdev)) {
+ error_setg(errp, "no slot for plugging zpci device");
+ return;
+ }
+ }
+}
+
+static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
+ PCIDevice *pdev = NULL;
+ S390PCIBusDevice *pbdev = NULL;
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
+ BusState *bus;
+ PCIBridge *pb = PCI_BRIDGE(dev);
+ PCIDevice *pdev = PCI_DEVICE(dev);
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
@@ -863,11 +874,6 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
pdev = PCI_DEVICE(dev);
- if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
- error_setg(errp, "multifunction not supported in s390");
- return;
- }
-
if (!dev->id) {
/* In the case the PCI device does not define an id */
/* we generate one based on the PCI address */
@@ -903,19 +909,19 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
}
if (dev->hotplugged) {
- s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
+ s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED ,
pbdev->fh, pbdev->fid);
}
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
pbdev = S390_PCI_DEVICE(dev);
- if (!s390_pci_alloc_idx(s, pbdev)) {
- error_setg(errp, "no slot for plugging zpci device");
- return;
- }
+ /* the allocated idx is actually getting used */
+ s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX;
pbdev->fh = pbdev->idx;
QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link);
g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
+ } else {
+ g_assert_not_reached();
}
}
@@ -936,14 +942,14 @@ static void s390_pcihost_timer_cb(void *opaque)
qdev_unplug(DEVICE(pbdev), NULL);
}
-static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp)
+static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
{
+ S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
PCIDevice *pci_dev = NULL;
PCIBus *bus;
int32_t devfn;
S390PCIBusDevice *pbdev = NULL;
- S390pciState *s = s390_get_phb();
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
error_setg(errp, "PCI bridge hot unplug currently not supported");
@@ -960,6 +966,8 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
pbdev = S390_PCI_DEVICE(dev);
pci_dev = pbdev->pdev;
+ } else {
+ g_assert_not_reached();
}
switch (pbdev->state) {
@@ -968,6 +976,9 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
case ZPCI_FS_STANDBY:
break;
default:
+ if (pbdev->release_timer) {
+ return;
+ }
s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST,
pbdev->fh, pbdev->fid);
pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
@@ -978,7 +989,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
return;
}
- if (pbdev->release_timer && timer_pending(pbdev->release_timer)) {
+ if (pbdev->release_timer) {
timer_del(pbdev->release_timer);
timer_free(pbdev->release_timer);
pbdev->release_timer = NULL;
@@ -989,6 +1000,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
bus = pci_get_bus(pci_dev);
devfn = pci_dev->devfn;
object_unparent(OBJECT(pci_dev));
+ fmb_timer_free(pbdev);
s390_pci_msix_free(pbdev);
s390_pci_iommu_free(s, bus, devfn);
pbdev->pdev = NULL;
@@ -1045,8 +1057,9 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
dc->reset = s390_pcihost_reset;
dc->realize = s390_pcihost_realize;
- hc->plug = s390_pcihost_hot_plug;
- hc->unplug = s390_pcihost_hot_unplug;
+ hc->pre_plug = s390_pcihost_pre_plug;
+ hc->plug = s390_pcihost_plug;
+ hc->unplug = s390_pcihost_unplug;
msi_nonbroken = true;
}
@@ -1136,6 +1149,7 @@ static void s390_pci_device_realize(DeviceState *dev, Error **errp)
}
zpci->state = ZPCI_FS_RESERVED;
+ zpci->fmb.format = ZPCI_FMB_FORMAT;
}
static void s390_pci_device_reset(DeviceState *dev)
@@ -1160,7 +1174,7 @@ static void s390_pci_device_reset(DeviceState *dev)
pci_dereg_ioat(pbdev->iommu);
}
- pbdev->fmb_addr = 0;
+ fmb_timer_free(pbdev);
}
static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name,
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 1f7f9b5814..dadad1f758 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -252,7 +252,6 @@ typedef struct ChscSeiNt2Res {
} QEMU_PACKED ChscSeiNt2Res;
typedef struct S390MsixInfo {
- bool available;
uint8_t table_bar;
uint8_t pba_bar;
uint16_t entries;
@@ -286,6 +285,33 @@ typedef struct S390PCIIOMMUTable {
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
} S390PCIIOMMUTable;
+/* Function Measurement Block */
+#define DEFAULT_MUI 4000
+#define UPDATE_U_BIT 0x1ULL
+#define FMBK_MASK 0xfULL
+
+typedef struct ZpciFmbFmt0 {
+ uint64_t dma_rbytes;
+ uint64_t dma_wbytes;
+} ZpciFmbFmt0;
+
+#define ZPCI_FMB_CNT_LD 0
+#define ZPCI_FMB_CNT_ST 1
+#define ZPCI_FMB_CNT_STB 2
+#define ZPCI_FMB_CNT_RPCIT 3
+#define ZPCI_FMB_CNT_MAX 4
+
+#define ZPCI_FMB_FORMAT 0
+
+typedef struct ZpciFmb {
+ uint32_t format;
+ uint32_t sample;
+ uint64_t last_update;
+ uint64_t counter[ZPCI_FMB_CNT_MAX];
+ ZpciFmbFmt0 fmt0;
+} ZpciFmb;
+QEMU_BUILD_BUG_MSG(offsetof(ZpciFmb, fmt0) != 48, "padding in ZpciFmb");
+
struct S390PCIBusDevice {
DeviceState qdev;
PCIDevice *pdev;
@@ -297,6 +323,8 @@ struct S390PCIBusDevice {
uint32_t fid;
bool fid_defined;
uint64_t fmb_addr;
+ ZpciFmb fmb;
+ QEMUTimer *fmb_timer;
uint8_t isc;
uint16_t noi;
uint16_t maxstbl;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 7b61367ee3..be2896232d 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -19,6 +19,7 @@
#include "exec/memory-internal.h"
#include "qemu/error-report.h"
#include "sysemu/hw_accel.h"
+#include "hw/s390x/tod.h"
#ifndef DEBUG_S390PCI_INST
#define DEBUG_S390PCI_INST 0
@@ -293,7 +294,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
resgrp->fr = 1;
stq_p(&resgrp->dasm, 0);
stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
- stw_p(&resgrp->mui, 0);
+ stw_p(&resgrp->mui, DEFAULT_MUI);
stw_p(&resgrp->i, 128);
stw_p(&resgrp->maxstbl, 128);
resgrp->version = 0;
@@ -456,6 +457,8 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
return 0;
}
+ pbdev->fmb.counter[ZPCI_FMB_CNT_LD]++;
+
env->regs[r1] = data;
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
@@ -561,6 +564,8 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
return 0;
}
+ pbdev->fmb.counter[ZPCI_FMB_CNT_ST]++;
+
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
}
@@ -681,6 +686,7 @@ err:
s390_set_status_code(env, r1, ZPCI_PCI_ST_FUNC_IN_ERR);
s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, start, 0);
} else {
+ pbdev->fmb.counter[ZPCI_FMB_CNT_RPCIT]++;
setcc(cpu, ZPCI_PCI_LS_OK);
}
return 0;
@@ -783,6 +789,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
}
+ pbdev->fmb.counter[ZPCI_FMB_CNT_STB]++;
+
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
@@ -889,6 +897,99 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu)
iommu->g_iota = 0;
}
+void fmb_timer_free(S390PCIBusDevice *pbdev)
+{
+ if (pbdev->fmb_timer) {
+ timer_del(pbdev->fmb_timer);
+ timer_free(pbdev->fmb_timer);
+ pbdev->fmb_timer = NULL;
+ }
+ pbdev->fmb_addr = 0;
+ memset(&pbdev->fmb, 0, sizeof(ZpciFmb));
+}
+
+static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val,
+ int len)
+{
+ MemTxResult ret;
+ uint64_t dst = pbdev->fmb_addr + offset;
+
+ switch (len) {
+ case 8:
+ address_space_stq_be(&address_space_memory, dst, val,
+ MEMTXATTRS_UNSPECIFIED,
+ &ret);
+ break;
+ case 4:
+ address_space_stl_be(&address_space_memory, dst, val,
+ MEMTXATTRS_UNSPECIFIED,
+ &ret);
+ break;
+ case 2:
+ address_space_stw_be(&address_space_memory, dst, val,
+ MEMTXATTRS_UNSPECIFIED,
+ &ret);
+ break;
+ case 1:
+ address_space_stb(&address_space_memory, dst, val,
+ MEMTXATTRS_UNSPECIFIED,
+ &ret);
+ break;
+ default:
+ ret = MEMTX_ERROR;
+ break;
+ }
+ if (ret != MEMTX_OK) {
+ s390_pci_generate_error_event(ERR_EVENT_FMBA, pbdev->fh, pbdev->fid,
+ pbdev->fmb_addr, 0);
+ fmb_timer_free(pbdev);
+ }
+
+ return ret;
+}
+
+static void fmb_update(void *opaque)
+{
+ S390PCIBusDevice *pbdev = opaque;
+ int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ int i;
+
+ /* Update U bit */
+ pbdev->fmb.last_update *= 2;
+ pbdev->fmb.last_update |= UPDATE_U_BIT;
+ if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update),
+ pbdev->fmb.last_update,
+ sizeof(pbdev->fmb.last_update))) {
+ return;
+ }
+
+ /* Update FMB sample count */
+ if (fmb_do_update(pbdev, offsetof(ZpciFmb, sample),
+ pbdev->fmb.sample++,
+ sizeof(pbdev->fmb.sample))) {
+ return;
+ }
+
+ /* Update FMB counters */
+ for (i = 0; i < ZPCI_FMB_CNT_MAX; i++) {
+ if (fmb_do_update(pbdev, offsetof(ZpciFmb, counter[i]),
+ pbdev->fmb.counter[i],
+ sizeof(pbdev->fmb.counter[0]))) {
+ return;
+ }
+ }
+
+ /* Clear U bit and update the time */
+ pbdev->fmb.last_update = time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
+ pbdev->fmb.last_update *= 2;
+ if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update),
+ pbdev->fmb.last_update,
+ sizeof(pbdev->fmb.last_update))) {
+ return;
+ }
+ timer_mod(pbdev->fmb_timer, t + DEFAULT_MUI);
+}
+
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra)
{
@@ -1018,9 +1119,35 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
}
break;
- case ZPCI_MOD_FC_SET_MEASURE:
- pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
+ case ZPCI_MOD_FC_SET_MEASURE: {
+ uint64_t fmb_addr = ldq_p(&fib.fmb_addr);
+
+ if (fmb_addr & FMBK_MASK) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_pci_generate_error_event(ERR_EVENT_FMBPRO, pbdev->fh,
+ pbdev->fid, fmb_addr, 0);
+ fmb_timer_free(pbdev);
+ break;
+ }
+
+ if (!fmb_addr) {
+ /* Stop updating FMB. */
+ fmb_timer_free(pbdev);
+ break;
+ }
+
+ if (!pbdev->fmb_timer) {
+ pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ fmb_update, pbdev);
+ } else if (timer_pending(pbdev->fmb_timer)) {
+ /* Remove pending timer to update FMB address. */
+ timer_del(pbdev->fmb_timer);
+ }
+ pbdev->fmb_addr = fmb_addr;
+ timer_mod(pbdev->fmb_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI);
break;
+ }
default:
s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra);
cc = ZPCI_PCI_LS_ERR;
diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h
index 91c3d61f2a..fa3bf8b5aa 100644
--- a/hw/s390x/s390-pci-inst.h
+++ b/hw/s390x/s390-pci-inst.h
@@ -303,6 +303,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra);
int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra);
+void fmb_timer_free(S390PCIBusDevice *pbdev);
#define ZPCI_IO_BAR_MIN 0
#define ZPCI_IO_BAR_MAX 5
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index a0615a8b35..811fdf913d 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -28,7 +28,6 @@
#include "hw/s390x/storage-keys.h"
#include "hw/s390x/storage-attributes.h"
#include "hw/s390x/event-facility.h"
-#include "hw/compat.h"
#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/css-bridge.h"
@@ -651,105 +650,26 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
-#define CCW_COMPAT_3_0 \
- HW_COMPAT_3_0
-
-#define CCW_COMPAT_2_12 \
- HW_COMPAT_2_12
-
-#define CCW_COMPAT_2_11 \
- HW_COMPAT_2_11 \
- {\
- .driver = TYPE_SCLP_EVENT_FACILITY,\
- .property = "allow_all_mask_sizes",\
- .value = "off",\
- },
-
-#define CCW_COMPAT_2_10 \
- HW_COMPAT_2_10
-
-#define CCW_COMPAT_2_9 \
- HW_COMPAT_2_9 \
- {\
- .driver = TYPE_S390_STATTRIB,\
- .property = "migration-enabled",\
- .value = "off",\
- },
-
-#define CCW_COMPAT_2_8 \
- HW_COMPAT_2_8 \
- {\
- .driver = TYPE_S390_FLIC_COMMON,\
- .property = "adapter_routes_max_batch",\
- .value = "64",\
- },
-
-#define CCW_COMPAT_2_7 \
- HW_COMPAT_2_7
-
-#define CCW_COMPAT_2_6 \
- HW_COMPAT_2_6 \
- {\
- .driver = TYPE_S390_IPL,\
- .property = "iplbext_migration",\
- .value = "off",\
- }, {\
- .driver = TYPE_VIRTUAL_CSS_BRIDGE,\
- .property = "css_dev_path",\
- .value = "off",\
- },
-
-#define CCW_COMPAT_2_5 \
- HW_COMPAT_2_5
-
-#define CCW_COMPAT_2_4 \
- HW_COMPAT_2_4 \
- {\
- .driver = TYPE_S390_SKEYS,\
- .property = "migration-enabled",\
- .value = "off",\
- },{\
- .driver = "virtio-blk-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-balloon-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-serial-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-9p-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-rng-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-net-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "virtio-scsi-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },{\
- .driver = "vhost-scsi-ccw",\
- .property = "max_revision",\
- .value = "0",\
- },
+static void ccw_machine_4_0_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_4_0_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(4_0, "4.0", true);
static void ccw_machine_3_1_instance_options(MachineState *machine)
{
+ ccw_machine_4_0_instance_options(machine);
}
static void ccw_machine_3_1_class_options(MachineClass *mc)
{
+ ccw_machine_4_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_3_1, hw_compat_3_1_len);
}
-DEFINE_CCW_MACHINE(3_1, "3.1", true);
+DEFINE_CCW_MACHINE(3_1, "3.1", false);
static void ccw_machine_3_0_instance_options(MachineState *machine)
{
@@ -762,7 +682,7 @@ static void ccw_machine_3_0_class_options(MachineClass *mc)
s390mc->hpage_1m_allowed = false;
ccw_machine_3_1_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_3_0);
+ compat_props_add(mc->compat_props, hw_compat_3_0, hw_compat_3_0_len);
}
DEFINE_CCW_MACHINE(3_0, "3.0", false);
@@ -776,7 +696,7 @@ static void ccw_machine_2_12_instance_options(MachineState *machine)
static void ccw_machine_2_12_class_options(MachineClass *mc)
{
ccw_machine_3_0_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_12);
+ compat_props_add(mc->compat_props, hw_compat_2_12, hw_compat_2_12_len);
}
DEFINE_CCW_MACHINE(2_12, "2.12", false);
@@ -791,8 +711,13 @@ static void ccw_machine_2_11_instance_options(MachineState *machine)
static void ccw_machine_2_11_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_SCLP_EVENT_FACILITY, "allow_all_mask_sizes", "off", },
+ };
+
ccw_machine_2_12_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_11);
+ compat_props_add(mc->compat_props, hw_compat_2_11, hw_compat_2_11_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_CCW_MACHINE(2_11, "2.11", false);
@@ -804,7 +729,7 @@ static void ccw_machine_2_10_instance_options(MachineState *machine)
static void ccw_machine_2_10_class_options(MachineClass *mc)
{
ccw_machine_2_11_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_10);
+ compat_props_add(mc->compat_props, hw_compat_2_10, hw_compat_2_10_len);
}
DEFINE_CCW_MACHINE(2_10, "2.10", false);
@@ -821,9 +746,13 @@ static void ccw_machine_2_9_instance_options(MachineState *machine)
static void ccw_machine_2_9_class_options(MachineClass *mc)
{
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_S390_STATTRIB, "migration-enabled", "off", },
+ };
ccw_machine_2_10_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
+ compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
s390mc->css_migration_enabled = false;
}
DEFINE_CCW_MACHINE(2_9, "2.9", false);
@@ -835,8 +764,13 @@ static void ccw_machine_2_8_instance_options(MachineState *machine)
static void ccw_machine_2_8_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_S390_FLIC_COMMON, "adapter_routes_max_batch", "64", },
+ };
+
ccw_machine_2_9_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8);
+ compat_props_add(mc->compat_props, hw_compat_2_8, hw_compat_2_8_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_CCW_MACHINE(2_8, "2.8", false);
@@ -851,7 +785,7 @@ static void ccw_machine_2_7_class_options(MachineClass *mc)
s390mc->cpu_model_allowed = false;
ccw_machine_2_8_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7);
+ compat_props_add(mc->compat_props, hw_compat_2_7, hw_compat_2_7_len);
}
DEFINE_CCW_MACHINE(2_7, "2.7", false);
@@ -863,10 +797,15 @@ static void ccw_machine_2_6_instance_options(MachineState *machine)
static void ccw_machine_2_6_class_options(MachineClass *mc)
{
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_S390_IPL, "iplbext_migration", "off", },
+ { TYPE_VIRTUAL_CSS_BRIDGE, "css_dev_path", "off", },
+ };
s390mc->ri_allowed = false;
ccw_machine_2_7_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
+ compat_props_add(mc->compat_props, hw_compat_2_6, hw_compat_2_6_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_CCW_MACHINE(2_6, "2.6", false);
@@ -878,7 +817,7 @@ static void ccw_machine_2_5_instance_options(MachineState *machine)
static void ccw_machine_2_5_class_options(MachineClass *mc)
{
ccw_machine_2_6_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
+ compat_props_add(mc->compat_props, hw_compat_2_5, hw_compat_2_5_len);
}
DEFINE_CCW_MACHINE(2_5, "2.5", false);
@@ -889,8 +828,21 @@ static void ccw_machine_2_4_instance_options(MachineState *machine)
static void ccw_machine_2_4_class_options(MachineClass *mc)
{
+ static GlobalProperty compat[] = {
+ { TYPE_S390_SKEYS, "migration-enabled", "off", },
+ { "virtio-blk-ccw", "max_revision", "0", },
+ { "virtio-balloon-ccw", "max_revision", "0", },
+ { "virtio-serial-ccw", "max_revision", "0", },
+ { "virtio-9p-ccw", "max_revision", "0", },
+ { "virtio-rng-ccw", "max_revision", "0", },
+ { "virtio-net-ccw", "max_revision", "0", },
+ { "virtio-scsi-ccw", "max_revision", "0", },
+ { "vhost-scsi-ccw", "max_revision", "0", },
+ };
+
ccw_machine_2_5_class_options(mc);
- SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
+ compat_props_add(mc->compat_props, hw_compat_2_4, hw_compat_2_4_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
DEFINE_CCW_MACHINE(2_4, "2.4", false);
diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c
index df564ab89c..2456bf7b24 100644
--- a/hw/s390x/tod-kvm.c
+++ b/hw/s390x/tod-kvm.c
@@ -10,10 +10,11 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "sysemu/sysemu.h"
#include "hw/s390x/tod.h"
#include "kvm_s390x.h"
-static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp)
+static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp)
{
int r;
@@ -27,7 +28,17 @@ static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp)
}
}
-static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp)
+static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp)
+{
+ if (td->stopped) {
+ *tod = td->base;
+ return;
+ }
+
+ kvm_s390_get_tod_raw(tod, errp);
+}
+
+static void kvm_s390_set_tod_raw(const S390TOD *tod, Error **errp)
{
int r;
@@ -41,18 +52,105 @@ static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp)
}
}
+static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp)
+{
+ Error *local_err = NULL;
+
+ /*
+ * Somebody (e.g. migration) set the TOD. We'll store it into KVM to
+ * properly detect errors now but take a look at the runstate to decide
+ * whether really to keep the tod running. E.g. during migration, this
+ * is the point where we want to stop the initially running TOD to fire
+ * it back up when actually starting the migrated guest.
+ */
+ kvm_s390_set_tod_raw(tod, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ if (runstate_is_running()) {
+ td->stopped = false;
+ } else {
+ td->stopped = true;
+ td->base = *tod;
+ }
+}
+
+static void kvm_s390_tod_vm_state_change(void *opaque, int running,
+ RunState state)
+{
+ S390TODState *td = opaque;
+ Error *local_err = NULL;
+
+ if (running && td->stopped) {
+ /* Set the old TOD when running the VM - start the TOD clock. */
+ kvm_s390_set_tod_raw(&td->base, &local_err);
+ if (local_err) {
+ warn_report_err(local_err);
+ }
+ /* Treat errors like the TOD was running all the time. */
+ td->stopped = false;
+ } else if (!running && !td->stopped) {
+ /* Store the TOD when stopping the VM - stop the TOD clock. */
+ kvm_s390_get_tod_raw(&td->base, &local_err);
+ if (local_err) {
+ /* Keep the TOD running in case we could not back it up. */
+ warn_report_err(local_err);
+ } else {
+ td->stopped = true;
+ }
+ }
+}
+
+static void kvm_s390_tod_realize(DeviceState *dev, Error **errp)
+{
+ S390TODState *td = S390_TOD(dev);
+ S390TODClass *tdc = S390_TOD_GET_CLASS(td);
+ Error *local_err = NULL;
+
+ tdc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ /*
+ * We need to know when the VM gets started/stopped to start/stop the TOD.
+ * As we can never have more than one TOD instance (and that will never be
+ * removed), registering here and never unregistering is good enough.
+ */
+ qemu_add_vm_change_state_handler(kvm_s390_tod_vm_state_change, td);
+}
+
static void kvm_s390_tod_class_init(ObjectClass *oc, void *data)
{
S390TODClass *tdc = S390_TOD_CLASS(oc);
+ device_class_set_parent_realize(DEVICE_CLASS(oc), kvm_s390_tod_realize,
+ &tdc->parent_realize);
tdc->get = kvm_s390_tod_get;
tdc->set = kvm_s390_tod_set;
}
+static void kvm_s390_tod_init(Object *obj)
+{
+ S390TODState *td = S390_TOD(obj);
+
+ /*
+ * The TOD is initially running (value stored in KVM). Avoid needless
+ * loading/storing of the TOD when starting a simple VM, so let it
+ * run although the (never started) VM is stopped. For migration, we
+ * will properly set the TOD later.
+ */
+ td->stopped = false;
+}
+
static TypeInfo kvm_s390_tod_info = {
.name = TYPE_KVM_S390_TOD,
.parent = TYPE_S390_TOD,
.instance_size = sizeof(S390TODState),
+ .instance_init = kvm_s390_tod_init,
.class_init = kvm_s390_tod_class_init,
.class_size = sizeof(S390TODClass),
};
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 212b3d3dea..c2b78c8e9b 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -287,18 +287,18 @@ static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len,
}
if (is_legacy) {
ccw_dstream_read(&sch->cds, linfo);
- be64_to_cpus(&linfo.queue);
- be32_to_cpus(&linfo.align);
- be16_to_cpus(&linfo.index);
- be16_to_cpus(&linfo.num);
+ linfo.queue = be64_to_cpu(linfo.queue);
+ linfo.align = be32_to_cpu(linfo.align);
+ linfo.index = be16_to_cpu(linfo.index);
+ linfo.num = be16_to_cpu(linfo.num);
ret = virtio_ccw_set_vqs(sch, NULL, &linfo);
} else {
ccw_dstream_read(&sch->cds, info);
- be64_to_cpus(&info.desc);
- be16_to_cpus(&info.index);
- be16_to_cpus(&info.num);
- be64_to_cpus(&info.avail);
- be64_to_cpus(&info.used);
+ info.desc = be64_to_cpu(info.desc);
+ info.index = be16_to_cpu(info.index);
+ info.num = be16_to_cpu(info.num);
+ info.avail = be64_to_cpu(info.avail);
+ info.used = be64_to_cpu(info.used);
ret = virtio_ccw_set_vqs(sch, &info, NULL);
}
sch->curr_status.scsw.count = 0;
@@ -382,7 +382,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
features.features = 0;
}
ccw_dstream_rewind(&sch->cds);
- cpu_to_le32s(&features.features);
+ features.features = cpu_to_le32(features.features);
ccw_dstream_write(&sch->cds, features.features);
sch->curr_status.scsw.count = ccw.count - sizeof(features);
ret = 0;
@@ -403,7 +403,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT;
} else {
ccw_dstream_read(&sch->cds, features);
- le32_to_cpus(&features.features);
+ features.features = le32_to_cpu(features.features);
if (features.index == 0) {
virtio_set_features(vdev,
(vdev->guest_features & 0xffffffff00000000ULL) |
@@ -546,7 +546,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT;
} else {
ccw_dstream_read(&sch->cds, indicators);
- be64_to_cpus(&indicators);
+ indicators = be64_to_cpu(indicators);
dev->indicators = get_indicator(indicators, sizeof(uint64_t));
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
ret = 0;
@@ -567,7 +567,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT;
} else {
ccw_dstream_read(&sch->cds, indicators);
- be64_to_cpus(&indicators);
+ indicators = be64_to_cpu(indicators);
dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
ret = 0;
@@ -588,14 +588,14 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT;
} else {
ccw_dstream_read(&sch->cds, vq_config.index);
- be16_to_cpus(&vq_config.index);
+ vq_config.index = be16_to_cpu(vq_config.index);
if (vq_config.index >= VIRTIO_QUEUE_MAX) {
ret = -EINVAL;
break;
}
vq_config.num_max = virtio_queue_get_num(vdev,
vq_config.index);
- cpu_to_be16s(&vq_config.num_max);
+ vq_config.num_max = cpu_to_be16(vq_config.num_max);
ccw_dstream_write(&sch->cds, vq_config.num_max);
sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
ret = 0;
@@ -621,9 +621,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
if (ccw_dstream_read(&sch->cds, thinint)) {
ret = -EFAULT;
} else {
- be64_to_cpus(&thinint.ind_bit);
- be64_to_cpus(&thinint.summary_indicator);
- be64_to_cpus(&thinint.device_indicator);
+ thinint.ind_bit = be64_to_cpu(thinint.ind_bit);
+ thinint.summary_indicator =
+ be64_to_cpu(thinint.summary_indicator);
+ thinint.device_indicator =
+ be64_to_cpu(thinint.device_indicator);
dev->summary_indicator =
get_indicator(thinint.summary_indicator, sizeof(uint8_t));
@@ -654,8 +656,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
break;
}
ccw_dstream_read_buf(&sch->cds, &revinfo, 4);
- be16_to_cpus(&revinfo.revision);
- be16_to_cpus(&revinfo.length);
+ revinfo.revision = be16_to_cpu(revinfo.revision);
+ revinfo.length = be16_to_cpu(revinfo.length);
if (ccw.count < len + revinfo.length ||
(check_len && ccw.count > len + revinfo.length)) {
ret = -EINVAL;
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 419fc668ac..6b0bbb9b7f 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -59,7 +59,7 @@
#define DMA_STAT_SCSIINT 0x10
#define DMA_STAT_BCMBLT 0x20
-#define SBAC_STATUS 0x1000
+#define SBAC_STATUS (1 << 24)
typedef struct PCIESPState {
/*< private >*/
@@ -136,7 +136,7 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
pci->dma_regs[saddr] = val;
break;
case DMA_STAT:
- if (!(pci->sbac & SBAC_STATUS)) {
+ if (pci->sbac & SBAC_STATUS) {
/* clear some bits on write */
uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
pci->dma_regs[DMA_STAT] &= ~(val & mask);
@@ -157,7 +157,7 @@ static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
val |= DMA_STAT_SCSIINT;
}
- if (pci->sbac & SBAC_STATUS) {
+ if (!(pci->sbac & SBAC_STATUS)) {
pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
DMA_STAT_DONE);
}
@@ -313,8 +313,8 @@ static void esp_pci_hard_reset(DeviceState *dev)
static const VMStateDescription vmstate_esp_pci_scsi = {
.name = "pciespscsi",
- .version_id = 0,
- .minimum_version_id = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 630d923623..ca8b36c0c5 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -286,11 +286,8 @@ static void esp_do_dma(ESPState *s)
esp_dma_done(s);
}
-void esp_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
+static void esp_report_command_complete(ESPState *s, uint32_t status)
{
- ESPState *s = req->hba_private;
-
trace_esp_command_complete();
if (s->ti_size != 0) {
trace_esp_command_complete_unexpected();
@@ -311,6 +308,23 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
}
}
+void esp_command_complete(SCSIRequest *req, uint32_t status,
+ size_t resid)
+{
+ ESPState *s = req->hba_private;
+
+ if (s->rregs[ESP_RSTAT] & STAT_INT) {
+ /* Defer handling command complete until the previous
+ * interrupt has been handled.
+ */
+ trace_esp_command_complete_deferred();
+ s->deferred_status = status;
+ s->deferred_complete = true;
+ return;
+ }
+ esp_report_command_complete(s, status);
+}
+
void esp_transfer_data(SCSIRequest *req, uint32_t len)
{
ESPState *s = req->hba_private;
@@ -422,7 +436,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
s->rregs[ESP_RSTAT] &= ~STAT_TC;
s->rregs[ESP_RSEQ] = SEQ_CD;
esp_lower_irq(s);
-
+ if (s->deferred_complete) {
+ esp_report_command_complete(s, s->deferred_status);
+ s->deferred_complete = false;
+ }
return old_val;
case ESP_TCHI:
/* Return the unique id if the value has never been written */
@@ -582,6 +599,8 @@ const VMStateDescription vmstate_esp = {
VMSTATE_UINT32(ti_wptr, ESPState),
VMSTATE_BUFFER(ti_buf, ESPState),
VMSTATE_UINT32(status, ESPState),
+ VMSTATE_UINT32(deferred_status, ESPState),
+ VMSTATE_BOOL(deferred_complete, ESPState),
VMSTATE_UINT32(dma, ESPState),
VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
@@ -671,8 +690,8 @@ static void sysbus_esp_hard_reset(DeviceState *dev)
static const VMStateDescription vmstate_sysbus_esp_scsi = {
.name = "sysbusespscsi",
- .version_id = 0,
- .minimum_version_id = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
VMSTATE_END_OF_LIST()
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 52a38933b6..89def1421f 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -1850,7 +1850,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x0a: case 0x0b:
/* Openserver writes to these readonly registers on startup */
- return;
+ return;
case 0x0c: case 0x0d: case 0x0e: case 0x0f:
/* Linux writes to these readonly registers on startup. */
return;
@@ -1884,8 +1884,8 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
/* nothing to do */
break;
case 0x1a: /* CTEST2 */
- s->ctest2 = val & LSI_CTEST2_PCICIE;
- break;
+ s->ctest2 = val & LSI_CTEST2_PCICIE;
+ break;
case 0x1b: /* CTEST3 */
s->ctest3 = val & 0x0f;
break;
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 97cd167114..c480553083 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1554,7 +1554,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
BusChild *kid;
SCSIDevice *target_dev = NULL;
- QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
+ QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, sibling) {
DeviceState *qdev = kid->child;
SCSIDevice *dev = SCSI_DEVICE(qdev);
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 0fb6a99616..2fe8a7c062 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -167,6 +167,7 @@ esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d"
esp_write_response(uint32_t status) "Transfer status (status=%d)"
esp_do_dma(uint32_t cmdlen, uint32_t len) "command len %d + %d"
esp_command_complete(void) "SCSI Command complete"
+esp_command_complete_deferred(void) "SCSI Command complete deferred"
esp_command_complete_unexpected(void) "SCSI command completed unexpectedly"
esp_command_complete_fail(void) "Command failed"
esp_transfer_data(uint32_t dma_left, int32_t ti_size) "transfer %d/%d"
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 7f21b4f9d6..61e2e57da9 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -215,6 +215,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
+ struct vhost_virtqueue *vqs = vsc->dev.vqs;
migrate_del_blocker(vsc->migration_blocker);
error_free(vsc->migration_blocker);
@@ -223,7 +224,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
vhost_scsi_set_status(vdev, 0);
vhost_dev_cleanup(&vsc->dev);
- g_free(vsc->dev.vqs);
+ g_free(vqs);
virtio_scsi_common_unrealize(dev, errp);
}
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index 2e1ba4a87b..6728878a52 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -121,12 +121,13 @@ static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserSCSI *s = VHOST_USER_SCSI(dev);
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
+ struct vhost_virtqueue *vqs = vsc->dev.vqs;
/* This will stop the vhost backend. */
vhost_user_scsi_set_status(vdev, 0);
vhost_dev_cleanup(&vsc->dev);
- g_free(vsc->dev.vqs);
+ g_free(vqs);
virtio_scsi_common_unrealize(dev, errp);
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 81bbf03279..83f1574ffd 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1371,7 +1371,7 @@ static void sdhci_common_realize(SDHCIState *s, Error **errp)
s->buf_maxsz = sdhci_get_fifolen(s);
s->fifo_buffer = g_malloc0(s->buf_maxsz);
- memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
+ memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
SDHC_REGISTERS_MAP_SIZE);
}
@@ -1565,9 +1565,6 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
sysbus_init_irq(sbd, &s->irq);
- memory_region_init_io(&s->iomem, OBJECT(s), s->io_ops, s, "sdhci",
- SDHC_REGISTERS_MAP_SIZE);
-
sysbus_init_mmio(sbd, &s->iomem);
}
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index 6a5fc46a47..5b399e7161 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -139,11 +139,11 @@ static uint64_t r2d_fpga_read(void *opaque, hwaddr addr, unsigned int size)
case PA_IRLMSK:
return s->irlmsk;
case PA_OUTPORT:
- return s->outport;
+ return s->outport;
case PA_POWOFF:
- return 0x00;
+ return 0x00;
case PA_VERREG:
- return 0x10;
+ return 0x10;
}
return 0;
@@ -158,18 +158,18 @@ r2d_fpga_write(void *opaque, hwaddr addr, uint64_t value, unsigned int size)
case PA_IRLMSK:
s->irlmsk = value;
update_irl(s);
- break;
+ break;
case PA_OUTPORT:
- s->outport = value;
- break;
+ s->outport = value;
+ break;
case PA_POWOFF:
if (value & 1) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
break;
case PA_VERREG:
- /* Discard writes */
- break;
+ /* Discard writes */
+ break;
}
}
diff --git a/hw/smbios/smbios-stub.c b/hw/smbios/smbios-stub.c
index d3a385441a..64e5ba93ec 100644
--- a/hw/smbios/smbios-stub.c
+++ b/hw/smbios/smbios-stub.c
@@ -23,7 +23,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
void smbios_entry_add(QemuOpts *opts, Error **errp)
{
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 920939454e..818be8a838 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -24,11 +24,10 @@
#include "sysemu/sysemu.h"
#include "qemu/uuid.h"
#include "sysemu/cpus.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "hw/loader.h"
#include "exec/cpu-common.h"
#include "smbios_build.h"
-#include "hw/smbios/ipmi.h"
/* legacy structures and constants for <= 2.0 machines */
struct smbios_header {
@@ -982,7 +981,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
header = (struct smbios_structure_header *)(smbios_tables +
smbios_tables_len);
- if (load_image(val, (uint8_t *)header) != size) {
+ if (load_image_size(val, (uint8_t *)header, size) != size) {
error_setg(errp, "Failed to load SMBIOS file %s", val);
return;
}
diff --git a/hw/smbios/smbios_build.h b/hw/smbios/smbios_build.h
index 93b360d520..56b5a1e3f3 100644
--- a/hw/smbios/smbios_build.h
+++ b/hw/smbios/smbios_build.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
*
* Authors:
* Alex Williamson <alex.williamson@hp.com>
@@ -96,4 +97,7 @@ extern unsigned smbios_table_cnt;
smbios_table_cnt++; \
} while (0)
+/* IPMI SMBIOS firmware handling */
+void smbios_build_type_38_table(void);
+
#endif /* QEMU_SMBIOS_BUILD_H */
diff --git a/hw/smbios/smbios_type_38-stub.c b/hw/smbios/smbios_type_38-stub.c
index 5b83c9b1f1..14b53d004b 100644
--- a/hw/smbios/smbios_type_38-stub.c
+++ b/hw/smbios/smbios_type_38-stub.c
@@ -8,7 +8,7 @@
*/
#include "qemu/osdep.h"
-#include "hw/smbios/ipmi.h"
+#include "smbios_build.h"
void smbios_build_type_38_table(void)
{
diff --git a/hw/smbios/smbios_type_38.c b/hw/smbios/smbios_type_38.c
index 56e8609c00..0c08f282de 100644
--- a/hw/smbios/smbios_type_38.c
+++ b/hw/smbios/smbios_type_38.c
@@ -9,8 +9,7 @@
#include "qemu/osdep.h"
#include "hw/ipmi/ipmi.h"
-#include "hw/smbios/ipmi.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "qemu/error-report.h"
#include "smbios_build.h"
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 3c29b68e67..709ee37e08 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -37,7 +37,6 @@
#include "net/net.h"
#include "hw/boards.h"
#include "hw/scsi/esp.h"
-#include "hw/isa/isa.h"
#include "hw/nvram/sun_nvram.h"
#include "hw/nvram/chrp_nvram.h"
#include "hw/nvram/fw_cfg.h"
@@ -559,8 +558,9 @@ static void idreg_init(hwaddr addr)
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, addr);
- cpu_physical_memory_write_rom(&address_space_memory,
- addr, idreg_data, sizeof(idreg_data));
+ address_space_write_rom(&address_space_memory, addr,
+ MEMTXATTRS_UNSPECIFIED,
+ idreg_data, sizeof(idreg_data));
}
#define MACIO_ID_REGISTER(obj) \
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index b32194d153..0e9a4530f8 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -23,6 +23,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o
common-obj-$(CONFIG_LM32) += lm32_timer.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o
+common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
index d13bc30b2d..2280914b1d 100644
--- a/hw/timer/etraxfs_timer.c
+++ b/hw/timer/etraxfs_timer.c
@@ -315,9 +315,10 @@ static void etraxfs_timer_reset(void *opaque)
qemu_irq_lower(t->irq);
}
-static int etraxfs_timer_init(SysBusDevice *dev)
+static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
{
ETRAXTimerState *t = ETRAX_TIMER(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
t->bh_t0 = qemu_bh_new(timer0_hit, t);
t->bh_t1 = qemu_bh_new(timer1_hit, t);
@@ -326,21 +327,20 @@ static int etraxfs_timer_init(SysBusDevice *dev)
t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT);
t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT);
- sysbus_init_irq(dev, &t->irq);
- sysbus_init_irq(dev, &t->nmi);
+ sysbus_init_irq(sbd, &t->irq);
+ sysbus_init_irq(sbd, &t->nmi);
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
"etraxfs-timer", 0x5c);
- sysbus_init_mmio(dev, &t->mmio);
+ sysbus_init_mmio(sbd, &t->mmio);
qemu_register_reset(etraxfs_timer_reset, t);
- return 0;
}
static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = etraxfs_timer_init;
+ dc->realize = etraxfs_timer_realize;
}
static const TypeInfo etraxfs_timer_info = {
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index 4ed96e970a..183eddc073 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -347,10 +347,11 @@ static void grlib_gptimer_reset(DeviceState *d)
}
}
-static int grlib_gptimer_init(SysBusDevice *dev)
+static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
{
GPTimerUnit *unit = GRLIB_GPTIMER(dev);
unsigned int i;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
assert(unit->nr_timers > 0);
assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
@@ -366,7 +367,7 @@ static int grlib_gptimer_init(SysBusDevice *dev)
timer->id = i;
/* One IRQ line for each timer */
- sysbus_init_irq(dev, &timer->irq);
+ sysbus_init_irq(sbd, &timer->irq);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
}
@@ -375,8 +376,7 @@ static int grlib_gptimer_init(SysBusDevice *dev)
unit, "gptimer",
UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
- sysbus_init_mmio(dev, &unit->iomem);
- return 0;
+ sysbus_init_mmio(sbd, &unit->iomem);
}
static Property grlib_gptimer_properties[] = {
@@ -389,9 +389,8 @@ static Property grlib_gptimer_properties[] = {
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->realize = grlib_gptimer_realize;
dc->reset = grlib_gptimer_reset;
dc->props = grlib_gptimer_properties;
}
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index 1057850808..20f834e7da 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
#include "hw/hw.h"
-#include "hw/isa/isa.h"
#include "qemu/timer.h"
#include "hw/timer/i8254.h"
#include "hw/timer/i8254_internal.h"
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index e4e4de8b8a..69483152c3 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -455,7 +455,7 @@ static void rtc_update_timer(void *opaque)
if (qemu_clock_get_ns(rtc_clock) >= s->next_alarm_time) {
irqs |= REG_C_AF;
if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC, NULL);
}
}
diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
new file mode 100644
index 0000000000..0c90662896
--- /dev/null
+++ b/hw/timer/nrf51_timer.c
@@ -0,0 +1,393 @@
+/*
+ * nRF51 System-on-Chip Timer peripheral
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ * Copyright (c) 2019 Red Hat, Inc.
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/arm/nrf51.h"
+#include "hw/timer/nrf51_timer.h"
+#include "trace.h"
+
+#define TIMER_CLK_FREQ 16000000UL
+
+static uint32_t const bitwidths[] = {16, 8, 24, 32};
+
+static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
+{
+ uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
+
+ return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
+}
+
+static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
+{
+ uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
+
+ return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
+}
+
+/* Returns number of ticks since last call */
+static uint32_t update_counter(NRF51TimerState *s, int64_t now)
+{
+ uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
+
+ s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
+ s->update_counter_ns = now;
+ return ticks;
+}
+
+/* Assumes s->counter is up-to-date */
+static void rearm_timer(NRF51TimerState *s, int64_t now)
+{
+ int64_t min_ns = INT64_MAX;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ int64_t delta_ns;
+
+ if (s->events_compare[i]) {
+ continue; /* already expired, ignore it for now */
+ }
+
+ if (s->cc[i] <= s->counter) {
+ delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
+ s->counter + s->cc[i]);
+ } else {
+ delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
+ }
+
+ if (delta_ns < min_ns) {
+ min_ns = delta_ns;
+ }
+ }
+
+ if (min_ns != INT64_MAX) {
+ timer_mod_ns(&s->timer, now + min_ns);
+ }
+}
+
+static void update_irq(NRF51TimerState *s)
+{
+ bool flag = false;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
+ }
+ qemu_set_irq(s->irq, flag);
+}
+
+static void timer_expire(void *opaque)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
+ bool should_stop = false;
+ uint32_t ticks;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (s->cc[i] > s->counter) {
+ cc_remaining[i] = s->cc[i] - s->counter;
+ } else {
+ cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
+ s->counter + s->cc[i];
+ }
+ }
+
+ ticks = update_counter(s, now);
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (cc_remaining[i] <= ticks) {
+ s->events_compare[i] = 1;
+
+ if (s->shorts & BIT(i)) {
+ s->timer_start_ns = now;
+ s->update_counter_ns = s->timer_start_ns;
+ s->counter = 0;
+ }
+
+ should_stop |= s->shorts & BIT(i + 8);
+ }
+ }
+
+ update_irq(s);
+
+ if (should_stop) {
+ s->running = false;
+ timer_del(&s->timer);
+ } else {
+ rearm_timer(s, now);
+ }
+}
+
+static void counter_compare(NRF51TimerState *s)
+{
+ uint32_t counter = s->counter;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (counter == s->cc[i]) {
+ s->events_compare[i] = 1;
+
+ if (s->shorts & BIT(i)) {
+ s->counter = 0;
+ }
+ }
+ }
+}
+
+static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ uint64_t r = 0;
+
+ switch (offset) {
+ case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
+ r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
+ break;
+ case NRF51_TIMER_REG_SHORTS:
+ r = s->shorts;
+ break;
+ case NRF51_TIMER_REG_INTENSET:
+ r = s->inten;
+ break;
+ case NRF51_TIMER_REG_INTENCLR:
+ r = s->inten;
+ break;
+ case NRF51_TIMER_REG_MODE:
+ r = s->mode;
+ break;
+ case NRF51_TIMER_REG_BITMODE:
+ r = s->bitmode;
+ break;
+ case NRF51_TIMER_REG_PRESCALER:
+ r = s->prescaler;
+ break;
+ case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
+ r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_nrf51_timer_read(offset, r, size);
+
+ return r;
+}
+
+static void nrf51_timer_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ size_t idx;
+
+ trace_nrf51_timer_write(offset, value, size);
+
+ switch (offset) {
+ case NRF51_TIMER_TASK_START:
+ if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
+ s->running = true;
+ s->timer_start_ns = now - ticks_to_ns(s, s->counter);
+ s->update_counter_ns = s->timer_start_ns;
+ rearm_timer(s, now);
+ }
+ break;
+ case NRF51_TIMER_TASK_STOP:
+ case NRF51_TIMER_TASK_SHUTDOWN:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->running = false;
+ timer_del(&s->timer);
+ }
+ break;
+ case NRF51_TIMER_TASK_COUNT:
+ if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
+ s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
+ counter_compare(s);
+ }
+ break;
+ case NRF51_TIMER_TASK_CLEAR:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->timer_start_ns = now;
+ s->update_counter_ns = s->timer_start_ns;
+ s->counter = 0;
+ if (s->running) {
+ rearm_timer(s, now);
+ }
+ }
+ break;
+ case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
+ if (value == NRF51_TRIGGER_TASK) {
+ if (s->running) {
+ timer_expire(s); /* update counter and all state */
+ }
+
+ idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
+ s->cc[idx] = s->counter;
+ }
+ break;
+ case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
+ if (value == NRF51_EVENT_CLEAR) {
+ s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
+
+ if (s->running) {
+ timer_expire(s); /* update counter and all state */
+ }
+ }
+ break;
+ case NRF51_TIMER_REG_SHORTS:
+ s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
+ break;
+ case NRF51_TIMER_REG_INTENSET:
+ s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
+ break;
+ case NRF51_TIMER_REG_INTENCLR:
+ s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
+ break;
+ case NRF51_TIMER_REG_MODE:
+ s->mode = value;
+ break;
+ case NRF51_TIMER_REG_BITMODE:
+ if (s->mode == NRF51_TIMER_TIMER && s->running) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: erroneous change of BITMODE while timer is running\n",
+ __func__);
+ }
+ s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
+ break;
+ case NRF51_TIMER_REG_PRESCALER:
+ if (s->mode == NRF51_TIMER_TIMER && s->running) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: erroneous change of PRESCALER while timer is running\n",
+ __func__);
+ }
+ s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
+ break;
+ case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
+ if (s->running) {
+ timer_expire(s); /* update counter */
+ }
+
+ idx = (offset - NRF51_TIMER_REG_CC0) / 4;
+ s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
+
+ if (s->running) {
+ rearm_timer(s, now);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_irq(s);
+}
+
+static const MemoryRegionOps rng_ops = {
+ .read = nrf51_timer_read,
+ .write = nrf51_timer_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void nrf51_timer_init(Object *obj)
+{
+ NRF51TimerState *s = NRF51_TIMER(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->iomem, obj, &rng_ops, s,
+ TYPE_NRF51_TIMER, NRF51_TIMER_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+
+ timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
+}
+
+static void nrf51_timer_reset(DeviceState *dev)
+{
+ NRF51TimerState *s = NRF51_TIMER(dev);
+
+ timer_del(&s->timer);
+ s->timer_start_ns = 0x00;
+ s->update_counter_ns = 0x00;
+ s->counter = 0x00;
+ s->running = false;
+
+ memset(s->events_compare, 0x00, sizeof(s->events_compare));
+ memset(s->cc, 0x00, sizeof(s->cc));
+
+ s->shorts = 0x00;
+ s->inten = 0x00;
+ s->mode = 0x00;
+ s->bitmode = 0x00;
+ s->prescaler = 0x00;
+}
+
+static int nrf51_timer_post_load(void *opaque, int version_id)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+
+ if (s->running && s->mode == NRF51_TIMER_TIMER) {
+ timer_expire(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_nrf51_timer = {
+ .name = TYPE_NRF51_TIMER,
+ .version_id = 1,
+ .post_load = nrf51_timer_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_TIMER(timer, NRF51TimerState),
+ VMSTATE_INT64(timer_start_ns, NRF51TimerState),
+ VMSTATE_INT64(update_counter_ns, NRF51TimerState),
+ VMSTATE_UINT32(counter, NRF51TimerState),
+ VMSTATE_BOOL(running, NRF51TimerState),
+ VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
+ NRF51_TIMER_REG_COUNT),
+ VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
+ VMSTATE_UINT32(shorts, NRF51TimerState),
+ VMSTATE_UINT32(inten, NRF51TimerState),
+ VMSTATE_UINT32(mode, NRF51TimerState),
+ VMSTATE_UINT32(bitmode, NRF51TimerState),
+ VMSTATE_UINT32(prescaler, NRF51TimerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = nrf51_timer_reset;
+ dc->vmsd = &vmstate_nrf51_timer;
+}
+
+static const TypeInfo nrf51_timer_info = {
+ .name = TYPE_NRF51_TIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51TimerState),
+ .instance_init = nrf51_timer_init,
+ .class_init = nrf51_timer_class_init
+};
+
+static void nrf51_timer_register_types(void)
+{
+ type_register_static(&nrf51_timer_info);
+}
+
+type_init(nrf51_timer_register_types)
diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c
index 0b3d717e60..3be58c7fdd 100644
--- a/hw/timer/puv3_ost.c
+++ b/hw/timer/puv3_ost.c
@@ -113,16 +113,17 @@ static void puv3_ost_tick(void *opaque)
}
}
-static int puv3_ost_init(SysBusDevice *dev)
+static void puv3_ost_realize(DeviceState *dev, Error **errp)
{
PUV3OSTState *s = PUV3_OST(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
s->reg_OIER = 0;
s->reg_OSSR = 0;
s->reg_OSMR0 = 0;
s->reg_OSCR = 0;
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(sbd, &s->irq);
s->bh = qemu_bh_new(puv3_ost_tick, s);
s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT);
@@ -130,16 +131,14 @@ static int puv3_ost_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
PUV3_REGS_OFFSET);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
+ sysbus_init_mmio(sbd, &s->iomem);
}
static void puv3_ost_class_init(ObjectClass *klass, void *data)
{
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- sdc->init = puv3_ost_init;
+ dc->realize = puv3_ost_realize;
}
static const TypeInfo puv3_ost_info = {
diff --git a/hw/timer/sun4v-rtc.c b/hw/timer/sun4v-rtc.c
index 4e7f6a1eff..b93cbd6a81 100644
--- a/hw/timer/sun4v-rtc.c
+++ b/hw/timer/sun4v-rtc.c
@@ -41,7 +41,7 @@ static uint64_t sun4v_rtc_read(void *opaque, hwaddr addr,
static void sun4v_rtc_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
- trace_sun4v_rtc_read(addr, val);
+ trace_sun4v_rtc_write(addr, val);
}
static const MemoryRegionOps sun4v_rtc_ops = {
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 75bd3b1042..0144a68951 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -72,3 +72,8 @@ sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value
# hw/timer/xlnx-zynqmp-rtc.c
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
+
+# hw/timer/nrf51_timer.c
+nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 1dc9f8bf2c..700c878622 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,4 +1,5 @@
common-obj-y += tpm_util.o
+obj-y += tpm_ppi.o
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index a92dd50437..3087acc4ab 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -29,6 +29,7 @@
#include "sysemu/reset.h"
#include "tpm_int.h"
#include "tpm_util.h"
+#include "tpm_ppi.h"
#include "trace.h"
typedef struct CRBState {
@@ -41,6 +42,9 @@ typedef struct CRBState {
MemoryRegion cmdmem;
size_t be_buffer_size;
+
+ bool ppi_enabled;
+ TPMPPI ppi;
} CRBState;
#define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
@@ -221,6 +225,7 @@ static const VMStateDescription vmstate_tpm_crb = {
static Property tpm_crb_properties[] = {
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
+ DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -228,6 +233,9 @@ static void tpm_crb_reset(void *dev)
{
CRBState *s = CRB(dev);
+ if (s->ppi_enabled) {
+ tpm_ppi_reset(&s->ppi);
+ }
tpm_backend_reset(s->tpmbe);
memset(s->regs, 0, sizeof(s->regs));
@@ -291,6 +299,11 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(get_system_memory(),
TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
+ if (s->ppi_enabled) {
+ tpm_ppi_init(&s->ppi, get_system_memory(),
+ TPM_PPI_ADDR_BASE, OBJECT(s));
+ }
+
qemu_register_reset(tpm_crb_reset, dev);
}
diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
new file mode 100644
index 0000000000..cd8205f212
--- /dev/null
+++ b/hw/tpm/tpm_ppi.c
@@ -0,0 +1,53 @@
+/*
+ * tpm_ppi.c - TPM Physical Presence Interface
+ *
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@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/osdep.h"
+
+#include "qapi/error.h"
+#include "cpu.h"
+#include "sysemu/memory_mapping.h"
+#include "sysemu/reset.h"
+#include "migration/vmstate.h"
+#include "tpm_ppi.h"
+#include "trace.h"
+
+void tpm_ppi_reset(TPMPPI *tpmppi)
+{
+ if (tpmppi->buf[0x15a /* movv, docs/specs/tpm.txt */] & 0x1) {
+ GuestPhysBlockList guest_phys_blocks;
+ GuestPhysBlock *block;
+
+ guest_phys_blocks_init(&guest_phys_blocks);
+ guest_phys_blocks_append(&guest_phys_blocks);
+ QTAILQ_FOREACH(block, &guest_phys_blocks.head, next) {
+ trace_tpm_ppi_memset(block->host_addr,
+ block->target_end - block->target_start);
+ memset(block->host_addr, 0,
+ block->target_end - block->target_start);
+ memory_region_set_dirty(block->mr, 0,
+ block->target_end - block->target_start);
+ }
+ guest_phys_blocks_free(&guest_phys_blocks);
+ }
+}
+
+void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m,
+ hwaddr addr, Object *obj)
+{
+ tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE));
+ memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi",
+ TPM_PPI_ADDR_SIZE, tpmppi->buf);
+ vmstate_register_ram(&tpmppi->ram, DEVICE(obj));
+
+ memory_region_add_subregion(m, addr, &tpmppi->ram);
+}
diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
new file mode 100644
index 0000000000..d33ef27de6
--- /dev/null
+++ b/hw/tpm/tpm_ppi.h
@@ -0,0 +1,46 @@
+/*
+ * TPM Physical Presence Interface
+ *
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@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 TPM_TPM_PPI_H
+#define TPM_TPM_PPI_H
+
+#include "hw/acpi/tpm.h"
+#include "exec/address-spaces.h"
+
+typedef struct TPMPPI {
+ MemoryRegion ram;
+ uint8_t *buf;
+} TPMPPI;
+
+/**
+ * tpm_ppi_init:
+ * @tpmppi: a TPMPPI
+ * @m: the address-space / MemoryRegion to use
+ * @addr: the address of the PPI region
+ * @obj: the owner object
+ *
+ * Register the TPM PPI memory region at @addr on the given address
+ * space for the object @obj.
+ **/
+void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m,
+ hwaddr addr, Object *obj);
+
+/**
+ * tpm_ppi_reset:
+ * @tpmppi: a TPMPPI
+ *
+ * Function to call on machine reset. It will check if the "Memory
+ * overwrite" variable is set, and perform a memory clear on volatile
+ * memory if requested.
+ **/
+void tpm_ppi_reset(TPMPPI *tpmppi);
+
+#endif /* TPM_TPM_PPI_H */
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index d9322692ee..fd6bb9b59a 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -31,6 +31,7 @@
#include "sysemu/tpm_backend.h"
#include "tpm_int.h"
#include "tpm_util.h"
+#include "tpm_ppi.h"
#include "trace.h"
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
@@ -81,6 +82,9 @@ typedef struct TPMState {
TPMVersion be_tpm_version;
size_t be_buffer_size;
+
+ bool ppi_enabled;
+ TPMPPI ppi;
} TPMState;
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
@@ -233,7 +237,7 @@ static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
}
/* abort -- this function switches the locality */
-static void tpm_tis_abort(TPMState *s, uint8_t locty)
+static void tpm_tis_abort(TPMState *s)
{
s->rw_offset = 0;
@@ -263,7 +267,9 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
{
uint8_t busy_locty;
- s->aborting_locty = locty;
+ assert(TPM_TIS_IS_VALID_LOCTY(newlocty));
+
+ s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */
s->next_locty = newlocty; /* locality after successful abort */
/*
@@ -281,7 +287,7 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
}
}
- tpm_tis_abort(s, locty);
+ tpm_tis_abort(s);
}
/*
@@ -293,6 +299,8 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret)
uint8_t locty = s->cmd.locty;
uint8_t l;
+ assert(TPM_TIS_IS_VALID_LOCTY(locty));
+
if (s->cmd.selftest_done) {
for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE;
@@ -311,7 +319,7 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret)
}
if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
- tpm_tis_abort(s, locty);
+ tpm_tis_abort(s);
}
tpm_tis_raise_irq(s, locty,
@@ -864,6 +872,9 @@ static void tpm_tis_reset(DeviceState *dev)
s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
TPM_TIS_BUFFER_MAX);
+ if (s->ppi_enabled) {
+ tpm_ppi_reset(&s->ppi);
+ }
tpm_backend_reset(s->be_driver);
s->active_locty = TPM_TIS_NO_LOCALITY;
@@ -950,6 +961,7 @@ static const VMStateDescription vmstate_tpm_tis = {
static Property tpm_tis_properties[] = {
DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
+ DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -976,6 +988,11 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
TPM_TIS_ADDR_BASE, &s->mmio);
+
+ if (s->ppi_enabled) {
+ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)),
+ TPM_PPI_ADDR_BASE, OBJECT(s));
+ }
}
static void tpm_tis_initfn(Object *obj)
diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
index 25bee0cecf..920d32ad55 100644
--- a/hw/tpm/trace-events
+++ b/hw/tpm/trace-events
@@ -51,3 +51,6 @@ tpm_tis_mmio_write_init_abort(void) "Initiating abort"
tpm_tis_mmio_write_lowering_irq(void) "Lowering IRQ"
tpm_tis_mmio_write_data2send(uint32_t value, unsigned size) "Data to send to TPM: 0x%08x (size=%d)"
tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
+
+# hw/tpm/tpm_ppi.c
+tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu"
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index bf796d67e6..6fffab7bfa 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -59,12 +59,6 @@ static int usb_device_post_load(void *opaque, int version_id)
} else {
dev->attached = true;
}
- if (dev->setup_index < 0 ||
- dev->setup_len < 0 ||
- dev->setup_index > dev->setup_len ||
- dev->setup_len > sizeof(dev->data_buf)) {
- return -EINVAL;
- }
return 0;
}
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 25976ed84f..963373ba95 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -119,11 +119,11 @@ struct EmulatedState {
char *db;
uint8_t atr[MAX_ATR_SIZE];
uint8_t atr_length;
- QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
+ QSIMPLEQ_HEAD(, EmulEvent) event_list;
QemuMutex event_list_mutex;
QemuThread event_thread_id;
VReader *reader;
- QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
+ QSIMPLEQ_HEAD(, EmulEvent) guest_apdu_list;
QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
QemuMutex handle_apdu_mutex;
QemuCond handle_apdu_cond;
@@ -549,6 +549,8 @@ static void emulated_realize(CCIDCardState *base, Error **errp)
qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread,
card, QEMU_THREAD_JOINABLE);
+ return;
+
out2:
clean_event_notifier(card);
out1:
diff --git a/hw/usb/combined-packet.c b/hw/usb/combined-packet.c
index 01a7ed0848..fc98383d30 100644
--- a/hw/usb/combined-packet.c
+++ b/hw/usb/combined-packet.c
@@ -64,7 +64,7 @@ void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p)
status = combined->first->status;
actual_length = combined->first->actual_length;
- short_not_ok = QTAILQ_LAST(&combined->packets, packets_head)->short_not_ok;
+ short_not_ok = QTAILQ_LAST(&combined->packets)->short_not_ok;
QTAILQ_FOREACH_SAFE(p, &combined->packets, combined_entry, next) {
if (!done) {
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index ee43e4914d..28ac7c5165 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -321,6 +321,9 @@ static int streambuf_put(struct streambuf *buf, USBPacket *p)
if (!free) {
return 0;
}
+ if (p->iov.size != USBAUDIO_PACKET_SIZE) {
+ return 0;
+ }
assert(free >= USBAUDIO_PACKET_SIZE);
usb_packet_copy(p, buf->data + (buf->prod % buf->size),
USBAUDIO_PACKET_SIZE);
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index eac7365b0a..c539a1afc6 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -46,7 +46,7 @@ struct USBBtState {
struct usb_hci_out_fifo_s {
uint8_t data[4096];
- int len;
+ int len;
} outcmd, outacl, outsco;
};
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index 62d18290dc..90cd745f06 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -592,12 +592,12 @@ static void usb_hid_handle_control(USBDevice *dev, USBPacket *p,
switch (value >> 8) {
case 0x22:
if (hs->kind == HID_MOUSE) {
- memcpy(data, qemu_mouse_hid_report_descriptor,
- sizeof(qemu_mouse_hid_report_descriptor));
+ memcpy(data, qemu_mouse_hid_report_descriptor,
+ sizeof(qemu_mouse_hid_report_descriptor));
p->actual_length = sizeof(qemu_mouse_hid_report_descriptor);
} else if (hs->kind == HID_TABLET) {
memcpy(data, qemu_tablet_hid_report_descriptor,
- sizeof(qemu_tablet_hid_report_descriptor));
+ sizeof(qemu_tablet_hid_report_descriptor));
p->actual_length = sizeof(qemu_tablet_hid_report_descriptor);
} else if (hs->kind == HID_KEYBOARD) {
memcpy(data, qemu_keyboard_hid_report_descriptor,
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index dc368179d1..7e9339b8a8 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -147,13 +147,13 @@ static const USBDesc desc_hub = {
static const uint8_t qemu_hub_hub_descriptor[] =
{
- 0x00, /* u8 bLength; patched in later */
- 0x29, /* u8 bDescriptorType; Hub-descriptor */
- 0x00, /* u8 bNbrPorts; (patched later) */
- 0x0a, /* u16 wHubCharacteristics; */
- 0x00, /* (per-port OC, no power switching) */
- 0x01, /* u8 bPwrOn2pwrGood; 2ms */
- 0x00 /* u8 bHubContrCurrent; 0 mA */
+ 0x00, /* u8 bLength; patched in later */
+ 0x29, /* u8 bDescriptorType; Hub-descriptor */
+ 0x00, /* u8 bNbrPorts; (patched later) */
+ 0x0a, /* u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x01, /* u8 bPwrOn2pwrGood; 2ms */
+ 0x00 /* u8 bHubContrCurrent; 0 mA */
/* DeviceRemovable and PortPwrCtrlMask patched in later */
};
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 100b7171f4..68c5eb8eaa 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -191,7 +191,7 @@ struct MTPState {
#ifdef CONFIG_INOTIFY1
/* inotify descriptor */
int inotifyfd;
- QTAILQ_HEAD(events, MTPMonEntry) events;
+ QTAILQ_HEAD(, MTPMonEntry) events;
#endif
/* Responder is expecting a write operation */
bool write_pending;
@@ -653,13 +653,18 @@ static void usb_mtp_object_readdir(MTPState *s, MTPObject *o)
{
struct dirent *entry;
DIR *dir;
+ int fd;
if (o->have_children) {
return;
}
o->have_children = true;
- dir = opendir(o->path);
+ fd = open(o->path, O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
+ if (fd < 0) {
+ return;
+ }
+ dir = fdopendir(fd);
if (!dir) {
return;
}
@@ -1007,7 +1012,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
trace_usb_mtp_op_get_object(s->dev.addr, o->handle, o->path);
- d->fd = open(o->path, O_RDONLY);
+ d->fd = open(o->path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
if (d->fd == -1) {
usb_mtp_data_free(d);
return NULL;
@@ -1031,7 +1036,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
c->argv[1], c->argv[2]);
d = usb_mtp_data_alloc(c);
- d->fd = open(o->path, O_RDONLY);
+ d->fd = open(o->path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
if (d->fd == -1) {
usb_mtp_data_free(d);
return NULL;
@@ -1658,7 +1663,7 @@ static void usb_mtp_write_data(MTPState *s)
0, 0, 0, 0);
goto done;
}
- d->fd = open(path, O_CREAT | O_WRONLY, mask);
+ d->fd = open(path, O_CREAT | O_WRONLY | O_CLOEXEC | O_NOFOLLOW, mask);
if (d->fd == -1) {
usb_mtp_queue_result(s, RES_STORE_FULL, d->trans,
0, 0, 0, 0);
@@ -1705,7 +1710,7 @@ free:
s->write_pending = false;
}
-static void usb_mtp_write_metadata(MTPState *s)
+static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
{
MTPData *d = s->data_out;
ObjectInfo *dataset = (ObjectInfo *)d->data;
@@ -1717,11 +1722,14 @@ static void usb_mtp_write_metadata(MTPState *s)
assert(!s->write_pending);
assert(p != NULL);
- filename = utf16_to_str(dataset->length, dataset->filename);
+ filename = utf16_to_str(MIN(dataset->length,
+ dlen - offsetof(ObjectInfo, filename)),
+ dataset->filename);
if (strchr(filename, '/')) {
usb_mtp_queue_result(s, RES_PARAMETER_NOT_SUPPORTED, d->trans,
0, 0, 0, 0);
+ g_free(filename);
return;
}
@@ -1733,7 +1741,6 @@ static void usb_mtp_write_metadata(MTPState *s)
s->dataset.filename = filename;
s->dataset.format = dataset->format;
s->dataset.size = dataset->size;
- s->dataset.filename = filename;
s->write_pending = true;
if (s->dataset.format == FMT_ASSOCIATION) {
@@ -1802,7 +1809,7 @@ static void usb_mtp_get_data(MTPState *s, mtp_container *container,
if (d->offset == d->length) {
/* The operation might have already failed */
if (!s->result) {
- usb_mtp_write_metadata(s);
+ usb_mtp_write_metadata(s, dlen);
}
usb_mtp_data_free(s->data_out);
s->data_out = NULL;
@@ -1982,7 +1989,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
case EP_EVENT:
#ifdef CONFIG_INOTIFY1
if (!QTAILQ_EMPTY(&s->events)) {
- struct MTPMonEntry *e = QTAILQ_LAST(&s->events, events);
+ struct MTPMonEntry *e = QTAILQ_LAST(&s->events);
uint32_t handle;
int len = sizeof(container) + sizeof(uint32_t);
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 385e090336..ffab3fabee 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -648,7 +648,7 @@ typedef struct USBNetState {
char usbstring_mac[13];
NICState *nic;
NICConf conf;
- QTAILQ_HEAD(rndis_resp_head, rndis_response) rndis_resp;
+ QTAILQ_HEAD(, rndis_response) rndis_resp;
} USBNetState;
#define TYPE_USB_NET "usb-net"
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 8c0fc53a26..69abbf7b7b 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -230,56 +230,3 @@ static void ehci_pci_register_types(void)
}
type_init(ehci_pci_register_types)
-
-struct ehci_companions {
- const char *name;
- int func;
- int port;
-};
-
-static const struct ehci_companions ich9_1d[] = {
- { .name = "ich9-usb-uhci1", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci2", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci3", .func = 2, .port = 4 },
-};
-
-static const struct ehci_companions ich9_1a[] = {
- { .name = "ich9-usb-uhci4", .func = 0, .port = 0 },
- { .name = "ich9-usb-uhci5", .func = 1, .port = 2 },
- { .name = "ich9-usb-uhci6", .func = 2, .port = 4 },
-};
-
-int ehci_create_ich9_with_companions(PCIBus *bus, int slot)
-{
- const struct ehci_companions *comp;
- PCIDevice *ehci, *uhci;
- BusState *usbbus;
- const char *name;
- int i;
-
- switch (slot) {
- case 0x1d:
- name = "ich9-usb-ehci1";
- comp = ich9_1d;
- break;
- case 0x1a:
- name = "ich9-usb-ehci2";
- comp = ich9_1a;
- break;
- default:
- return -1;
- }
-
- ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name);
- qdev_init_nofail(&ehci->qdev);
- usbbus = QLIST_FIRST(&ehci->qdev.child_bus);
-
- for (i = 0; i < 3; i++) {
- uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func),
- true, comp[i].name);
- qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
- qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
- qdev_init_nofail(&uhci->qdev);
- }
- return 0;
-}
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index 3b83beb140..331faf8bc3 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -94,6 +94,22 @@ static const TypeInfo ehci_type_info = {
.class_size = sizeof(SysBusEHCIClass),
};
+static void ehci_platform_class_init(ObjectClass *oc, void *data)
+{
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ sec->capsbase = 0x0;
+ sec->opregbase = 0x20;
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
+}
+
+static const TypeInfo ehci_platform_type_info = {
+ .name = TYPE_PLATFORM_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = ehci_platform_class_init,
+};
+
static void ehci_xlnx_class_init(ObjectClass *oc, void *data)
{
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
@@ -245,6 +261,7 @@ static const TypeInfo ehci_fusbh200_type_info = {
static void ehci_sysbus_register_types(void)
{
type_register_static(&ehci_type_info);
+ type_register_static(&ehci_platform_type_info);
type_register_static(&ehci_xlnx_type_info);
type_register_static(&ehci_exynos4210_type_info);
type_register_static(&ehci_tegra2_type_info);
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index e5acfc5ba5..e233681962 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1783,9 +1783,17 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
EHCIqtd qtd;
EHCIPacket *p;
int again = 1;
+ uint32_t addr;
- if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd,
- sizeof(EHCIqtd) >> 2) < 0) {
+ addr = NLPTR_GET(q->qtdaddr);
+ if (get_dwords(q->ehci, addr + 8, &qtd.token, 1) < 0) {
+ return 0;
+ }
+ barrier();
+ if (get_dwords(q->ehci, addr + 0, &qtd.next, 1) < 0 ||
+ get_dwords(q->ehci, addr + 4, &qtd.altnext, 1) < 0 ||
+ get_dwords(q->ehci, addr + 12, qtd.bufptr,
+ ARRAY_SIZE(qtd.bufptr)) < 0) {
return 0;
}
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
@@ -1815,7 +1823,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
break;
case EHCI_ASYNC_INFLIGHT:
/* Check if the guest has added new tds to the queue */
- again = ehci_fill_queue(QTAILQ_LAST(&q->packets, pkts_head));
+ again = ehci_fill_queue(QTAILQ_LAST(&q->packets));
/* Unfinished async handled packet, go horizontal */
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
break;
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
index 0bc364b286..d6601706ee 100644
--- a/hw/usb/hcd-ehci.h
+++ b/hw/usb/hcd-ehci.h
@@ -247,7 +247,7 @@ struct EHCIQueue {
uint32_t qtdaddr; /* address QTD read from */
int last_pid; /* pid of last packet executed */
USBDevice *dev;
- QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
+ QTAILQ_HEAD(, EHCIPacket) packets;
};
typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
@@ -342,6 +342,7 @@ typedef struct EHCIPCIState {
#define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb"
+#define TYPE_PLATFORM_EHCI "platform-ehci-usb"
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index 836b11f177..e694b62086 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -99,7 +99,7 @@ struct UHCIQueue {
UHCIState *uhci;
USBEndpoint *ep;
QTAILQ_ENTRY(UHCIQueue) next;
- QTAILQ_HEAD(asyncs_head, UHCIAsync) asyncs;
+ QTAILQ_HEAD(, UHCIAsync) asyncs;
int8_t valid;
};
@@ -837,7 +837,7 @@ static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
}
if (!async->done) {
UHCI_TD last_td;
- UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
+ UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs);
/*
* While we are waiting for the current td to complete, the guest
* may have added more tds to the queue. Note we re-read the td
@@ -1056,8 +1056,8 @@ static void uhci_process_frame(UHCIState *s)
link = qh.link;
} else {
/* QH with elements */
- curr_qh = link;
- link = qh.el_link;
+ curr_qh = link;
+ link = qh.el_link;
}
continue;
}
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index b6602ded4e..833250a886 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -988,7 +988,9 @@ static void usb_host_exit_notifier(struct Notifier *n, void *data)
if (s->dh) {
usb_host_release_interfaces(s);
+ libusb_reset_device(s->dh);
usb_host_attach_kernel(s);
+ libusb_close(s->dh);
}
}
diff --git a/hw/usb/tusb6010.c b/hw/usb/tusb6010.c
index a2128024c1..501706e2b2 100644
--- a/hw/usb/tusb6010.c
+++ b/hw/usb/tusb6010.c
@@ -808,10 +808,10 @@ static void tusb6010_reset(DeviceState *dev)
musb_reset(s->musb);
}
-static int tusb6010_init(SysBusDevice *sbd)
+static void tusb6010_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(sbd);
TUSBState *s = TUSB(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
@@ -822,15 +822,13 @@ static int tusb6010_init(SysBusDevice *sbd)
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
s->musb = musb_init(dev, 1);
- return 0;
}
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->realize = tusb6010_realize;
dc->reset = tusb6010_reset;
}
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index 5b2e21ed18..b20d0cfadf 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -27,7 +27,7 @@
#include "qemu/option.h"
#include "hw/sysbus.h"
#include "hw/usb.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "monitor/qdev.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
@@ -72,7 +72,7 @@ struct usbback_stub {
USBPort port;
unsigned int speed;
bool attached;
- QTAILQ_HEAD(submit_q_head, usbback_req) submit_q;
+ QTAILQ_HEAD(, usbback_req) submit_q;
};
struct usbback_req {
@@ -99,7 +99,7 @@ struct usbback_hotplug {
};
struct usbback_info {
- struct XenDevice xendev; /* must be first */
+ struct XenLegacyDevice xendev; /* must be first */
USBBus bus;
void *urb_sring;
void *conn_sring;
@@ -108,8 +108,8 @@ struct usbback_info {
int num_ports;
int usb_ver;
bool ring_error;
- QTAILQ_HEAD(req_free_q_head, usbback_req) req_free_q;
- QSIMPLEQ_HEAD(hotplug_q_head, usbback_hotplug) hotplug_q;
+ QTAILQ_HEAD(, usbback_req) req_free_q;
+ QSIMPLEQ_HEAD(, usbback_hotplug) hotplug_q;
struct usbback_stub ports[USBBACK_MAXPORTS];
struct usbback_stub *addr_table[USB_DEV_ADDR_SIZE];
QEMUBH *bh;
@@ -142,7 +142,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
unsigned int nr_segs, i, prot;
uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST];
struct usbback_info *usbif = usbback_req->usbif;
- struct XenDevice *xendev = &usbif->xendev;
+ struct XenLegacyDevice *xendev = &usbif->xendev;
struct usbif_request_segment *seg;
void *addr;
@@ -220,7 +220,7 @@ static int usbback_gnttab_map(struct usbback_req *usbback_req)
static int usbback_init_packet(struct usbback_req *usbback_req)
{
- struct XenDevice *xendev = &usbback_req->usbif->xendev;
+ struct XenLegacyDevice *xendev = &usbback_req->usbif->xendev;
USBPacket *packet = &usbback_req->packet;
USBDevice *dev = usbback_req->stub->dev;
USBEndpoint *ep;
@@ -279,7 +279,7 @@ static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
{
struct usbback_info *usbif;
struct usbif_urb_response *res;
- struct XenDevice *xendev;
+ struct XenLegacyDevice *xendev;
unsigned int notify;
usbif = usbback_req->usbif;
@@ -824,7 +824,7 @@ static void usbback_process_port(struct usbback_info *usbif, unsigned port)
g_free(busid);
}
-static void usbback_disconnect(struct XenDevice *xendev)
+static void usbback_disconnect(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
unsigned int i;
@@ -853,17 +853,21 @@ static void usbback_disconnect(struct XenDevice *xendev)
TR_BUS(xendev, "finished\n");
}
-static int usbback_connect(struct XenDevice *xendev)
+static int usbback_connect(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
struct usbif_urb_sring *urb_sring;
struct usbif_conn_sring *conn_sring;
int urb_ring_ref;
int conn_ring_ref;
- unsigned int i;
+ unsigned int i, max_grants;
TR_BUS(xendev, "start\n");
+ /* max_grants: for each request and for the rings (request and connect). */
+ max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2;
+ xen_be_set_max_grant_refs(xendev, max_grants);
+
usbif = container_of(xendev, struct usbback_info, xendev);
if (xenstore_read_fe_int(xendev, "urb-ring-ref", &urb_ring_ref)) {
@@ -909,7 +913,8 @@ static int usbback_connect(struct XenDevice *xendev)
return 0;
}
-static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
+static void usbback_backend_changed(struct XenLegacyDevice *xendev,
+ const char *node)
{
struct usbback_info *usbif;
unsigned int i;
@@ -922,7 +927,7 @@ static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
}
}
-static int usbback_init(struct XenDevice *xendev)
+static int usbback_init(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
@@ -1001,11 +1006,11 @@ static USBPortOps xen_usb_port_ops = {
static USBBusOps xen_usb_bus_ops = {
};
-static void usbback_alloc(struct XenDevice *xendev)
+static void usbback_alloc(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
USBPort *p;
- unsigned int i, max_grants;
+ unsigned int i;
usbif = container_of(xendev, struct usbback_info, xendev);
@@ -1021,13 +1026,9 @@ static void usbback_alloc(struct XenDevice *xendev)
QTAILQ_INIT(&usbif->req_free_q);
QSIMPLEQ_INIT(&usbif->hotplug_q);
usbif->bh = qemu_bh_new(usbback_bh, usbif);
-
- /* max_grants: for each request and for the rings (request and connect). */
- max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2;
- xen_be_set_max_grant_refs(xendev, max_grants);
}
-static int usbback_free(struct XenDevice *xendev)
+static int usbback_free(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
struct usbback_req *usbback_req;
@@ -1066,7 +1067,7 @@ static int usbback_free(struct XenDevice *xendev)
return 0;
}
-static void usbback_event(struct XenDevice *xendev)
+static void usbback_event(struct XenLegacyDevice *xendev)
{
struct usbback_info *usbif;
diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c
index 65de952f44..6166ccd47a 100644
--- a/hw/vfio/ap.c
+++ b/hw/vfio/ap.c
@@ -10,9 +10,9 @@
* directory.
*/
+#include "qemu/osdep.h"
#include <linux/vfio.h>
#include <sys/ioctl.h>
-#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/vfio/vfio.h"
@@ -104,6 +104,14 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp)
vapdev->vdev.name = g_strdup_printf("%s", mdevid);
vapdev->vdev.dev = dev;
+ /*
+ * vfio-ap devices operate in a way compatible with
+ * memory ballooning, as no pages are pinned in the host.
+ * This needs to be set before vfio_get_device() for vfio common to
+ * handle the balloon inhibitor.
+ */
+ vapdev->vdev.balloon_allowed = true;
+
ret = vfio_get_device(vfio_group, mdevid, &vapdev->vdev, &local_err);
if (ret) {
goto out_get_dev_err;
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 7c185e5a2e..4262b80c44 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -37,9 +37,9 @@
#include "trace.h"
#include "qapi/error.h"
-struct vfio_group_head vfio_group_list =
+VFIOGroupList vfio_group_list =
QLIST_HEAD_INITIALIZER(vfio_group_list);
-struct vfio_as_head vfio_address_spaces =
+static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
QLIST_HEAD_INITIALIZER(vfio_address_spaces);
#ifdef CONFIG_KVM
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 5c7bd96984..c0cb1ec289 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1897,15 +1897,10 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
PCI_EXP_TYPE_ENDPOINT << 4,
PCI_EXP_FLAGS_TYPE);
vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
+ QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
+ QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
}
-
- /* Mark the Link Status bits as emulated to allow virtual negotiation */
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
- pci_get_word(vdev->pdev.config + pos +
- PCI_EXP_LNKSTA),
- PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
}
/*
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
index 1b2799cfd8..ea7913d532 100644
--- a/hw/virtio/Makefile.objs
+++ b/hw/virtio/Makefile.objs
@@ -11,6 +11,21 @@ obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-p
obj-$(CONFIG_LINUX) += vhost.o vhost-backend.o vhost-user.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
+ifeq ($(CONFIG_PCI),y)
+obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock-pci.o
+obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk-pci.o
+obj-$(CONFIG_VHOST_USER_SCSI) += vhost-user-scsi-pci.o
+obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-pci.o
+obj-$(CONFIG_VIRTIO_INPUT_HOST) += virtio-input-host-pci.o
+obj-$(CONFIG_VIRTIO_INPUT) += virtio-input-pci.o
+obj-$(CONFIG_VIRTIO_RNG) += virtio-rng-pci.o
+obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon-pci.o
+obj-$(CONFIG_VIRTIO_9P) += virtio-9p-pci.o
+obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi-pci.o
+obj-$(CONFIG_VIRTIO_BLK) += virtio-blk-pci.o
+obj-$(CONFIG_VIRTIO_NET) += virtio-net-pci.o
+obj-$(CONFIG_VIRTIO_SERIAL) += virtio-serial-pci.o
+endif
endif
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO),$(CONFIG_LINUX))) += vhost-stub.o
diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c
new file mode 100644
index 0000000000..523f7cb3ce
--- /dev/null
+++ b/hw/virtio/vhost-scsi-pci.c
@@ -0,0 +1,97 @@
+/*
+ * Vhost scsi PCI bindings
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * Changes for QEMU mainline + tcm_vhost kernel upstream:
+ * Nicholas Bellinger <nab@risingtidesystems.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/osdep.h"
+
+#include "standard-headers/linux/virtio_pci.h"
+#include "hw/virtio/vhost-scsi.h"
+#include "qapi/error.h"
+#include "virtio-pci.h"
+
+typedef struct VHostSCSIPCI VHostSCSIPCI;
+
+/*
+ * vhost-scsi-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci-base"
+#define VHOST_SCSI_PCI(obj) \
+ OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI)
+
+struct VHostSCSIPCI {
+ VirtIOPCIProxy parent_obj;
+ VHostSCSI vdev;
+};
+
+static Property vhost_scsi_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = vs->conf.num_queues + 3;
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ k->realize = vhost_scsi_pci_realize;
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = vhost_scsi_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
+ pcidev_k->revision = 0x00;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vhost_scsi_pci_instance_init(Object *obj)
+{
+ VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_SCSI);
+ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
+ "bootindex", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_scsi_pci_info = {
+ .base_name = TYPE_VHOST_SCSI_PCI,
+ .generic_name = "vhost-scsi-pci",
+ .transitional_name = "vhost-scsi-pci-transitional",
+ .non_transitional_name = "vhost-scsi-pci-non-transitional",
+ .instance_size = sizeof(VHostSCSIPCI),
+ .instance_init = vhost_scsi_pci_instance_init,
+ .class_init = vhost_scsi_pci_class_init,
+};
+
+static void vhost_scsi_pci_register(void)
+{
+ virtio_pci_types_register(&vhost_scsi_pci_info);
+}
+
+type_init(vhost_scsi_pci_register)
diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c
new file mode 100644
index 0000000000..ca66c217a7
--- /dev/null
+++ b/hw/virtio/vhost-user-blk-pci.c
@@ -0,0 +1,103 @@
+/*
+ * Vhost user blk PCI Bindings
+ *
+ * Copyright(C) 2017 Intel Corporation.
+ *
+ * Authors:
+ * Changpeng Liu <changpeng.liu@intel.com>
+ *
+ * Largely based on the "vhost-user-scsi.c" and "vhost-scsi.c" implemented by:
+ * Felipe Franciosi <felipe@nutanix.com>
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ * Nicholas Bellinger <nab@risingtidesystems.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/osdep.h"
+
+#include "standard-headers/linux/virtio_pci.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost-user-blk.h"
+#include "hw/pci/pci.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "virtio-pci.h"
+
+typedef struct VHostUserBlkPCI VHostUserBlkPCI;
+
+/*
+ * vhost-user-blk-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci-base"
+#define VHOST_USER_BLK_PCI(obj) \
+ OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI)
+
+struct VHostUserBlkPCI {
+ VirtIOPCIProxy parent_obj;
+ VHostUserBlk vdev;
+};
+
+static Property vhost_user_blk_pci_properties[] = {
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = dev->vdev.num_queues + 1;
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = vhost_user_blk_pci_properties;
+ k->realize = vhost_user_blk_pci_realize;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vhost_user_blk_pci_instance_init(Object *obj)
+{
+ VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_USER_BLK);
+ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
+ "bootindex", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_user_blk_pci_info = {
+ .base_name = TYPE_VHOST_USER_BLK_PCI,
+ .generic_name = "vhost-user-blk-pci",
+ .transitional_name = "vhost-user-blk-pci-transitional",
+ .non_transitional_name = "vhost-user-blk-pci-non-transitional",
+ .instance_size = sizeof(VHostUserBlkPCI),
+ .instance_init = vhost_user_blk_pci_instance_init,
+ .class_init = vhost_user_blk_pci_class_init,
+};
+
+static void vhost_user_blk_pci_register(void)
+{
+ virtio_pci_types_register(&vhost_user_blk_pci_info);
+}
+
+type_init(vhost_user_blk_pci_register)
diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c
new file mode 100644
index 0000000000..46f7193cc7
--- /dev/null
+++ b/hw/virtio/vhost-user-scsi-pci.c
@@ -0,0 +1,103 @@
+/*
+ * Vhost user scsi PCI Bindings
+ *
+ * Copyright (c) 2016 Nutanix Inc. All rights reserved.
+ *
+ * Author:
+ * Felipe Franciosi <felipe@nutanix.com>
+ *
+ * This work is largely based on the "vhost-scsi" implementation by:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ * Nicholas Bellinger <nab@risingtidesystems.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/osdep.h"
+
+#include "standard-headers/linux/virtio_pci.h"
+#include "hw/virtio/vhost-user-scsi.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/pci/pci.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/loader.h"
+#include "sysemu/kvm.h"
+#include "virtio-pci.h"
+
+typedef struct VHostUserSCSIPCI VHostUserSCSIPCI;
+
+#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci-base"
+#define VHOST_USER_SCSI_PCI(obj) \
+ OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI)
+
+struct VHostUserSCSIPCI {
+ VirtIOPCIProxy parent_obj;
+ VHostUserSCSI vdev;
+};
+
+static Property vhost_user_scsi_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = vs->conf.num_queues + 3;
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ k->realize = vhost_user_scsi_pci_realize;
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = vhost_user_scsi_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
+ pcidev_k->revision = 0x00;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void vhost_user_scsi_pci_instance_init(Object *obj)
+{
+ VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_USER_SCSI);
+ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
+ "bootindex", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_user_scsi_pci_info = {
+ .base_name = TYPE_VHOST_USER_SCSI_PCI,
+ .generic_name = "vhost-user-scsi-pci",
+ .transitional_name = "vhost-user-scsi-pci-transitional",
+ .non_transitional_name = "vhost-user-scsi-pci-non-transitional",
+ .instance_size = sizeof(VHostUserSCSIPCI),
+ .instance_init = vhost_user_scsi_pci_instance_init,
+ .class_init = vhost_user_scsi_pci_class_init,
+};
+
+static void vhost_user_scsi_pci_register(void)
+{
+ virtio_pci_types_register(&vhost_user_scsi_pci_info);
+}
+
+type_init(vhost_user_scsi_pci_register)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index e09bed0e4a..564a31d12c 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -207,7 +207,7 @@ struct vhost_user {
static bool ioeventfd_enabled(void)
{
- return kvm_enabled() && kvm_eventfds_enabled();
+ return !kvm_enabled() || kvm_eventfds_enabled();
}
static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c
new file mode 100644
index 0000000000..6f43ca35fb
--- /dev/null
+++ b/hw/virtio/vhost-vsock-pci.c
@@ -0,0 +1,86 @@
+/*
+ * Vhost vsock PCI Bindings
+ *
+ * Copyright 2015 Red Hat, Inc.
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/virtio/vhost-vsock.h"
+
+typedef struct VHostVSockPCI VHostVSockPCI;
+
+/*
+ * vhost-vsock-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci-base"
+#define VHOST_VSOCK_PCI(obj) \
+ OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI)
+
+struct VHostVSockPCI {
+ VirtIOPCIProxy parent_obj;
+ VHostVSock vdev;
+};
+
+/* vhost-vsock-pci */
+
+static Property vhost_vsock_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ k->realize = vhost_vsock_pci_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->props = vhost_vsock_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK;
+ pcidev_k->revision = 0x00;
+ pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+}
+
+static void vhost_vsock_pci_instance_init(Object *obj)
+{
+ VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_VSOCK);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = {
+ .base_name = TYPE_VHOST_VSOCK_PCI,
+ .generic_name = "vhost-vsock-pci",
+ .transitional_name = "vhost-vsock-pci-transitional",
+ .non_transitional_name = "vhost-vsock-pci-non-transitional",
+ .instance_size = sizeof(VHostVSockPCI),
+ .instance_init = vhost_vsock_pci_instance_init,
+ .class_init = vhost_vsock_pci_class_init,
+};
+
+static void virtio_pci_vhost_register(void)
+{
+ virtio_pci_types_register(&vhost_vsock_pci_info);
+}
+
+type_init(virtio_pci_vhost_register)
diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c
new file mode 100644
index 0000000000..7bf1130966
--- /dev/null
+++ b/hw/virtio/virtio-9p-pci.c
@@ -0,0 +1,88 @@
+/*
+ * Virtio 9p PCI Bindings
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/9pfs/virtio-9p.h"
+
+/*
+ * virtio-9p-pci: This extends VirtioPCIProxy.
+ */
+
+#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci-base"
+#define VIRTIO_9P_PCI(obj) \
+ OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI)
+
+typedef struct V9fsPCIState {
+ VirtIOPCIProxy parent_obj;
+ V9fsVirtioState vdev;
+} V9fsPCIState;
+
+static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static Property virtio_9p_pci_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+
+ k->realize = virtio_9p_pci_realize;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = 0x2;
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = virtio_9p_pci_properties;
+}
+
+static void virtio_9p_pci_instance_init(Object *obj)
+{
+ V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_9P);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_9p_pci_info = {
+ .base_name = TYPE_VIRTIO_9P_PCI,
+ .generic_name = "virtio-9p-pci",
+ .transitional_name = "virtio-9p-pci-transitional",
+ .non_transitional_name = "virtio-9p-pci-non-transitional",
+ .instance_size = sizeof(V9fsPCIState),
+ .instance_init = virtio_9p_pci_instance_init,
+ .class_init = virtio_9p_pci_class_init,
+};
+
+static void virtio_9p_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_9p_pci_info);
+}
+
+type_init(virtio_9p_pci_register)
diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c
new file mode 100644
index 0000000000..2a213bbb38
--- /dev/null
+++ b/hw/virtio/virtio-balloon-pci.c
@@ -0,0 +1,95 @@
+/*
+ * Virtio balloon PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/virtio/virtio-balloon.h"
+#include "qapi/error.h"
+
+typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
+
+/*
+ * virtio-balloon-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci-base"
+#define VIRTIO_BALLOON_PCI(obj) \
+ OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
+
+struct VirtIOBalloonPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOBalloon vdev;
+};
+static Property virtio_balloon_pci_properties[] = {
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
+ vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
+ vpci_dev->class_code = PCI_CLASS_OTHERS;
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ k->realize = virtio_balloon_pci_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->props = virtio_balloon_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_balloon_pci_instance_init(Object *obj)
+{
+ VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_BALLOON);
+ object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
+ "guest-stats", &error_abort);
+ object_property_add_alias(obj, "guest-stats-polling-interval",
+ OBJECT(&dev->vdev),
+ "guest-stats-polling-interval", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_balloon_pci_info = {
+ .base_name = TYPE_VIRTIO_BALLOON_PCI,
+ .generic_name = "virtio-balloon-pci",
+ .transitional_name = "virtio-balloon-pci-transitional",
+ .non_transitional_name = "virtio-balloon-pci-non-transitional",
+ .instance_size = sizeof(VirtIOBalloonPCI),
+ .instance_init = virtio_balloon_pci_instance_init,
+ .class_init = virtio_balloon_pci_class_init,
+};
+
+static void virtio_balloon_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_balloon_pci_info);
+}
+
+type_init(virtio_balloon_pci_register)
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 1728e4f83a..a12677d4d5 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -311,7 +311,7 @@ out:
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
{
VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
- struct virtio_balloon_config config;
+ struct virtio_balloon_config config = {};
config.num_pages = cpu_to_le32(dev->num_pages);
config.actual = cpu_to_le32(dev->actual);
diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c
new file mode 100644
index 0000000000..60c9185c39
--- /dev/null
+++ b/hw/virtio/virtio-blk-pci.c
@@ -0,0 +1,100 @@
+/*
+ * Virtio blk PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-blk.h"
+#include "virtio-pci.h"
+#include "qapi/error.h"
+
+typedef struct VirtIOBlkPCI VirtIOBlkPCI;
+
+/*
+ * virtio-blk-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci-base"
+#define VIRTIO_BLK_PCI(obj) \
+ OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
+
+struct VirtIOBlkPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOBlock vdev;
+};
+
+static Property virtio_blk_pci_properties[] = {
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+ DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = dev->vdev.conf.num_queues + 1;
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = virtio_blk_pci_properties;
+ k->realize = virtio_blk_pci_realize;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void virtio_blk_pci_instance_init(Object *obj)
+{
+ VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_BLK);
+ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
+ "bootindex", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_blk_pci_info = {
+ .base_name = TYPE_VIRTIO_BLK_PCI,
+ .generic_name = "virtio-blk-pci",
+ .transitional_name = "virtio-blk-pci-transitional",
+ .non_transitional_name = "virtio-blk-pci-non-transitional",
+ .instance_size = sizeof(VirtIOBlkPCI),
+ .instance_init = virtio_blk_pci_instance_init,
+ .class_init = virtio_blk_pci_class_init,
+};
+
+static void virtio_blk_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_blk_pci_info);
+}
+
+type_init(virtio_blk_pci_register)
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index bf64996e48..90a6e0dc2e 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -19,6 +19,20 @@
#include "hw/virtio/virtio-crypto.h"
#include "qapi/error.h"
+typedef struct VirtIOCryptoPCI VirtIOCryptoPCI;
+
+/*
+ * virtio-crypto-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci"
+#define VIRTIO_CRYPTO_PCI(obj) \
+ OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI)
+
+struct VirtIOCryptoPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOCrypto vdev;
+};
+
static Property virtio_crypto_pci_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
@@ -64,9 +78,8 @@ static void virtio_crypto_initfn(Object *obj)
TYPE_VIRTIO_CRYPTO);
}
-static const TypeInfo virtio_crypto_pci_info = {
- .name = TYPE_VIRTIO_CRYPTO_PCI,
- .parent = TYPE_VIRTIO_PCI,
+static const VirtioPCIDeviceTypeInfo virtio_crypto_pci_info = {
+ .generic_name = TYPE_VIRTIO_CRYPTO_PCI,
.instance_size = sizeof(VirtIOCryptoPCI),
.instance_init = virtio_crypto_initfn,
.class_init = virtio_crypto_pci_class_init,
@@ -74,6 +87,6 @@ static const TypeInfo virtio_crypto_pci_info = {
static void virtio_crypto_pci_register_types(void)
{
- type_register_static(&virtio_crypto_pci_info);
+ virtio_pci_types_register(&virtio_crypto_pci_info);
}
type_init(virtio_crypto_pci_register_types)
diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c
new file mode 100644
index 0000000000..725a51ad30
--- /dev/null
+++ b/hw/virtio/virtio-input-host-pci.c
@@ -0,0 +1,48 @@
+/*
+ * Virtio input host PCI Bindings
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/virtio/virtio-input.h"
+
+typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
+
+#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci-base"
+#define VIRTIO_INPUT_HOST_PCI(obj) \
+ OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
+
+struct VirtIOInputHostPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOInputHost vdev;
+};
+
+static void virtio_host_initfn(Object *obj)
+{
+ VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_INPUT_HOST);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_input_host_pci_info = {
+ .base_name = TYPE_VIRTIO_INPUT_HOST_PCI,
+ .generic_name = "virtio-input-host-pci",
+ .transitional_name = "virtio-input-host-pci-transitional",
+ .non_transitional_name = "virtio-input-host-pci-non-transitional",
+ .parent = TYPE_VIRTIO_INPUT_PCI,
+ .instance_size = sizeof(VirtIOInputHostPCI),
+ .instance_init = virtio_host_initfn,
+};
+
+static void virtio_input_host_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_input_host_pci_info);
+}
+
+type_init(virtio_input_host_pci_register)
diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c
new file mode 100644
index 0000000000..2c1397842b
--- /dev/null
+++ b/hw/virtio/virtio-input-pci.c
@@ -0,0 +1,157 @@
+/*
+ * Virtio input PCI Bindings
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/virtio/virtio-input.h"
+
+typedef struct VirtIOInputPCI VirtIOInputPCI;
+typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
+
+/*
+ * virtio-input-pci: This extends VirtioPCIProxy.
+ */
+#define VIRTIO_INPUT_PCI(obj) \
+ OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
+
+struct VirtIOInputPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOInput vdev;
+};
+
+#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
+#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
+#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci"
+#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
+#define VIRTIO_INPUT_HID_PCI(obj) \
+ OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
+
+struct VirtIOInputHIDPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOInputHID vdev;
+};
+
+static Property virtio_input_pci_properties[] = {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&vinput->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ virtio_pci_force_virtio_1(vpci_dev);
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ dc->props = virtio_input_pci_properties;
+ k->realize = virtio_input_pci_realize;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+
+ pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
+}
+
+static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
+}
+
+static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
+ void *data)
+{
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
+}
+
+static void virtio_keyboard_initfn(Object *obj)
+{
+ VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_KEYBOARD);
+}
+
+static void virtio_mouse_initfn(Object *obj)
+{
+ VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_MOUSE);
+}
+
+static void virtio_tablet_initfn(Object *obj)
+{
+ VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_TABLET);
+}
+
+static const TypeInfo virtio_input_pci_info = {
+ .name = TYPE_VIRTIO_INPUT_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIOInputPCI),
+ .class_init = virtio_input_pci_class_init,
+ .abstract = true,
+};
+
+static const TypeInfo virtio_input_hid_pci_info = {
+ .name = TYPE_VIRTIO_INPUT_HID_PCI,
+ .parent = TYPE_VIRTIO_INPUT_PCI,
+ .instance_size = sizeof(VirtIOInputHIDPCI),
+ .abstract = true,
+};
+
+static const VirtioPCIDeviceTypeInfo virtio_keyboard_pci_info = {
+ .generic_name = TYPE_VIRTIO_KEYBOARD_PCI,
+ .parent = TYPE_VIRTIO_INPUT_HID_PCI,
+ .class_init = virtio_input_hid_kbd_pci_class_init,
+ .instance_size = sizeof(VirtIOInputHIDPCI),
+ .instance_init = virtio_keyboard_initfn,
+};
+
+static const VirtioPCIDeviceTypeInfo virtio_mouse_pci_info = {
+ .generic_name = TYPE_VIRTIO_MOUSE_PCI,
+ .parent = TYPE_VIRTIO_INPUT_HID_PCI,
+ .class_init = virtio_input_hid_mouse_pci_class_init,
+ .instance_size = sizeof(VirtIOInputHIDPCI),
+ .instance_init = virtio_mouse_initfn,
+};
+
+static const VirtioPCIDeviceTypeInfo virtio_tablet_pci_info = {
+ .generic_name = TYPE_VIRTIO_TABLET_PCI,
+ .parent = TYPE_VIRTIO_INPUT_HID_PCI,
+ .instance_size = sizeof(VirtIOInputHIDPCI),
+ .instance_init = virtio_tablet_initfn,
+};
+
+static void virtio_pci_input_register(void)
+{
+ /* Base types: */
+ type_register_static(&virtio_input_pci_info);
+ type_register_static(&virtio_input_hid_pci_info);
+
+ /* Implementations: */
+ virtio_pci_types_register(&virtio_keyboard_pci_info);
+ virtio_pci_types_register(&virtio_mouse_pci_info);
+ virtio_pci_types_register(&virtio_tablet_pci_info);
+}
+
+type_init(virtio_pci_input_register)
diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c
new file mode 100644
index 0000000000..db07ab9e21
--- /dev/null
+++ b/hw/virtio/virtio-net-pci.c
@@ -0,0 +1,98 @@
+/*
+ * Virtio net PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-net.h"
+#include "virtio-pci.h"
+#include "qapi/error.h"
+
+typedef struct VirtIONetPCI VirtIONetPCI;
+
+/*
+ * virtio-net-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_NET_PCI "virtio-net-pci-base"
+#define VIRTIO_NET_PCI(obj) \
+ OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI)
+
+struct VirtIONetPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIONet vdev;
+};
+
+static Property virtio_net_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ DeviceState *qdev = DEVICE(vpci_dev);
+ VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ virtio_net_set_netclient_name(&dev->vdev, qdev->id,
+ object_get_typename(OBJECT(qdev)));
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
+
+ k->romfile = "efi-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;
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+ dc->props = virtio_net_properties;
+ vpciklass->realize = virtio_net_pci_realize;
+}
+
+static void virtio_net_pci_instance_init(Object *obj)
+{
+ VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_NET);
+ object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
+ "bootindex", &error_abort);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_net_pci_info = {
+ .base_name = TYPE_VIRTIO_NET_PCI,
+ .generic_name = "virtio-net-pci",
+ .transitional_name = "virtio-net-pci-transitional",
+ .non_transitional_name = "virtio-net-pci-non-transitional",
+ .instance_size = sizeof(VirtIONetPCI),
+ .instance_init = virtio_net_pci_instance_init,
+ .class_init = virtio_net_pci_class_init,
+};
+
+static void virtio_net_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_net_pci_info);
+}
+
+type_init(virtio_net_pci_register)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index a954799267..b282109343 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -19,12 +19,6 @@
#include "standard-headers/linux/virtio_pci.h"
#include "hw/virtio/virtio.h"
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-balloon.h"
-#include "hw/virtio/virtio-input.h"
#include "hw/pci/pci.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -1079,55 +1073,6 @@ static void virtio_pci_vmstate_change(DeviceState *d, bool running)
}
}
-#ifdef CONFIG_VIRTFS
-static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static Property virtio_9p_pci_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
-
- k->realize = virtio_9p_pci_realize;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = 0x2;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_9p_pci_properties;
-}
-
-static void virtio_9p_pci_instance_init(Object *obj)
-{
- V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_9P);
-}
-
-static const TypeInfo virtio_9p_pci_info = {
- .name = TYPE_VIRTIO_9P_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(V9fsPCIState),
- .instance_init = virtio_9p_pci_instance_init,
- .class_init = virtio_9p_pci_class_init,
-};
-#endif /* CONFIG_VIRTFS */
-
/*
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
*/
@@ -1877,9 +1822,6 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
- DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
- ON_OFF_AUTO_AUTO),
- DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
@@ -1939,712 +1881,123 @@ static const TypeInfo virtio_pci_info = {
.class_init = virtio_pci_class_init,
.class_size = sizeof(VirtioPCIClass),
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- { }
- },
-};
-
-/* virtio-blk-pci */
-
-static Property virtio_blk_pci_properties[] = {
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = dev->vdev.conf.num_queues + 1;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_blk_pci_properties;
- k->realize = virtio_blk_pci_realize;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_blk_pci_instance_init(Object *obj)
-{
- VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BLK);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo virtio_blk_pci_info = {
- .name = TYPE_VIRTIO_BLK_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOBlkPCI),
- .instance_init = virtio_blk_pci_instance_init,
- .class_init = virtio_blk_pci_class_init,
-};
-
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
-/* vhost-user-blk */
-
-static Property vhost_user_blk_pci_properties[] = {
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = dev->vdev.num_queues + 1;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = vhost_user_blk_pci_properties;
- k->realize = vhost_user_blk_pci_realize;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void vhost_user_blk_pci_instance_init(Object *obj)
-{
- VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_USER_BLK);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo vhost_user_blk_pci_info = {
- .name = TYPE_VHOST_USER_BLK_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VHostUserBlkPCI),
- .instance_init = vhost_user_blk_pci_instance_init,
- .class_init = vhost_user_blk_pci_class_init,
-};
-#endif
-
-/* virtio-scsi-pci */
-
-static Property virtio_scsi_pci_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_END_OF_LIST(),
-};
-
-static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
- DeviceState *proxy = DEVICE(vpci_dev);
- char *bus_name;
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues + 3;
- }
-
- /*
- * For command line compatibility, this sets the virtio-scsi-device bus
- * name as before.
- */
- if (proxy->id) {
- bus_name = g_strdup_printf("%s.0", proxy->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->realize = virtio_scsi_pci_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = virtio_scsi_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_scsi_pci_instance_init(Object *obj)
-{
- VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SCSI);
-}
-
-static const TypeInfo virtio_scsi_pci_info = {
- .name = TYPE_VIRTIO_SCSI_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOSCSIPCI),
- .instance_init = virtio_scsi_pci_instance_init,
- .class_init = virtio_scsi_pci_class_init,
-};
-
-/* vhost-scsi-pci */
-
-#ifdef CONFIG_VHOST_SCSI
-static Property vhost_scsi_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues + 3;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = vhost_scsi_pci_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = vhost_scsi_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void vhost_scsi_pci_instance_init(Object *obj)
-{
- VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_SCSI);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo vhost_scsi_pci_info = {
- .name = TYPE_VHOST_SCSI_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VHostSCSIPCI),
- .instance_init = vhost_scsi_pci_instance_init,
- .class_init = vhost_scsi_pci_class_init,
-};
-#endif
-
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
-/* vhost-user-scsi-pci */
-static Property vhost_user_scsi_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = vs->conf.num_queues + 3;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = vhost_user_scsi_pci_realize;
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
- dc->props = vhost_user_scsi_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void vhost_user_scsi_pci_instance_init(Object *obj)
-{
- VHostUserSCSIPCI *dev = VHOST_USER_SCSI_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_USER_SCSI);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
-}
-
-static const TypeInfo vhost_user_scsi_pci_info = {
- .name = TYPE_VHOST_USER_SCSI_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VHostUserSCSIPCI),
- .instance_init = vhost_user_scsi_pci_instance_init,
- .class_init = vhost_user_scsi_pci_class_init,
-};
-#endif
-
-/* vhost-vsock-pci */
-
-#ifdef CONFIG_VHOST_VSOCK
-static Property vhost_vsock_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_PROP_END_OF_LIST(),
};
-static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = vhost_vsock_pci_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = vhost_vsock_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_VSOCK;
- pcidev_k->revision = 0x00;
- pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-}
-
-static void vhost_vsock_pci_instance_init(Object *obj)
-{
- VHostVSockPCI *dev = VHOST_VSOCK_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_VSOCK);
-}
-
-static const TypeInfo vhost_vsock_pci_info = {
- .name = TYPE_VHOST_VSOCK_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VHostVSockPCI),
- .instance_init = vhost_vsock_pci_instance_init,
- .class_init = vhost_vsock_pci_class_init,
-};
-#endif
-
-/* virtio-balloon-pci */
-
-static Property virtio_balloon_pci_properties[] = {
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+static Property virtio_pci_generic_properties[] = {
+ DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
+ ON_OFF_AUTO_AUTO),
+ DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
DEFINE_PROP_END_OF_LIST(),
};
-static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
- vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
- vpci_dev->class_code = PCI_CLASS_OTHERS;
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = virtio_balloon_pci_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->props = virtio_balloon_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_balloon_pci_instance_init(Object *obj)
-{
- VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_BALLOON);
- object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
- "guest-stats", &error_abort);
- object_property_add_alias(obj, "guest-stats-polling-interval",
- OBJECT(&dev->vdev),
- "guest-stats-polling-interval", &error_abort);
-}
-
-static const TypeInfo virtio_balloon_pci_info = {
- .name = TYPE_VIRTIO_BALLOON_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOBalloonPCI),
- .instance_init = virtio_balloon_pci_instance_init,
- .class_init = virtio_balloon_pci_class_init,
-};
-
-/* virtio-serial-pci */
-
-static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+static void virtio_pci_base_class_init(ObjectClass *klass, void *data)
{
- VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
- DeviceState *proxy = DEVICE(vpci_dev);
- char *bus_name;
-
- if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
- vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
- vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */
- vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
- }
-
- /* backwards-compatibility with machines that were created with
- DEV_NVECTORS_UNSPECIFIED */
- if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
- vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
+ const VirtioPCIDeviceTypeInfo *t = data;
+ if (t->class_init) {
+ t->class_init(klass, NULL);
}
-
- /*
- * For command line compatibility, this sets the virtio-serial-device bus
- * name as before.
- */
- if (proxy->id) {
- bus_name = g_strdup_printf("%s.0", proxy->id);
- virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
- g_free(bus_name);
- }
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
}
-static Property virtio_serial_pci_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_pci_generic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
- k->realize = virtio_serial_pci_realize;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
- dc->props = virtio_serial_pci_properties;
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-}
-static void virtio_serial_pci_instance_init(Object *obj)
-{
- VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_SERIAL);
+ dc->props = virtio_pci_generic_properties;
}
-static const TypeInfo virtio_serial_pci_info = {
- .name = TYPE_VIRTIO_SERIAL_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOSerialPCI),
- .instance_init = virtio_serial_pci_instance_init,
- .class_init = virtio_serial_pci_class_init,
-};
-
-/* virtio-net-pci */
-
-static Property virtio_net_properties[] = {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+/* Used when the generic type and the base type is the same */
+static void virtio_pci_generic_base_class_init(ObjectClass *klass, void *data)
{
- DeviceState *qdev = DEVICE(vpci_dev);
- VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- virtio_net_set_netclient_name(&dev->vdev, qdev->id,
- object_get_typename(OBJECT(qdev)));
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+ virtio_pci_base_class_init(klass, data);
+ virtio_pci_generic_class_init(klass, NULL);
}
-static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
+static void virtio_pci_transitional_instance_init(Object *obj)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(obj);
- k->romfile = "efi-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;
- set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
- dc->props = virtio_net_properties;
- vpciklass->realize = virtio_net_pci_realize;
+ proxy->disable_legacy = ON_OFF_AUTO_OFF;
+ proxy->disable_modern = false;
}
-static void virtio_net_pci_instance_init(Object *obj)
+static void virtio_pci_non_transitional_instance_init(Object *obj)
{
- VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(obj);
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_NET);
- object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
- "bootindex", &error_abort);
+ proxy->disable_legacy = ON_OFF_AUTO_ON;
+ proxy->disable_modern = false;
}
-static const TypeInfo virtio_net_pci_info = {
- .name = TYPE_VIRTIO_NET_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIONetPCI),
- .instance_init = virtio_net_pci_instance_init,
- .class_init = virtio_net_pci_class_init,
-};
-
-/* virtio-rng-pci */
-
-static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t)
{
- VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&vrng->vdev);
- Error *err = NULL;
+ TypeInfo base_type_info = {
+ .name = t->base_name,
+ .parent = t->parent ? t->parent : TYPE_VIRTIO_PCI,
+ .instance_size = t->instance_size,
+ .instance_init = t->instance_init,
+ .class_init = virtio_pci_base_class_init,
+ .class_data = (void *)t,
+ .abstract = true,
+ };
+ TypeInfo generic_type_info = {
+ .name = t->generic_name,
+ .parent = base_type_info.name,
+ .class_init = virtio_pci_generic_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { }
+ },
+ };
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- object_property_set_bool(OBJECT(vdev), true, "realized", &err);
- if (err) {
- error_propagate(errp, err);
- return;
+ if (!base_type_info.name) {
+ /* No base type -> register a single generic device type */
+ base_type_info.name = t->generic_name;
+ base_type_info.class_init = virtio_pci_generic_base_class_init;
+ base_type_info.interfaces = generic_type_info.interfaces;
+ base_type_info.abstract = false;
+ generic_type_info.name = NULL;
+ assert(!t->non_transitional_name);
+ assert(!t->transitional_name);
+ }
+
+ type_register(&base_type_info);
+ if (generic_type_info.name) {
+ type_register(&generic_type_info);
+ }
+
+ if (t->non_transitional_name) {
+ const TypeInfo non_transitional_type_info = {
+ .name = t->non_transitional_name,
+ .parent = base_type_info.name,
+ .instance_init = virtio_pci_non_transitional_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { }
+ },
+ };
+ type_register(&non_transitional_type_info);
+ }
+
+ if (t->transitional_name) {
+ const TypeInfo transitional_type_info = {
+ .name = t->transitional_name,
+ .parent = base_type_info.name,
+ .instance_init = virtio_pci_transitional_instance_init,
+ .interfaces = (InterfaceInfo[]) {
+ /*
+ * Transitional virtio devices work only as Conventional PCI
+ * devices because they require PIO ports.
+ */
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { }
+ },
+ };
+ type_register(&transitional_type_info);
}
-
- object_property_set_link(OBJECT(vrng),
- OBJECT(vrng->vdev.conf.rng), "rng",
- NULL);
}
-static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- k->realize = virtio_rng_pci_realize;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-
- pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
- pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
- pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
- pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_rng_initfn(Object *obj)
-{
- VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_RNG);
-}
-
-static const TypeInfo virtio_rng_pci_info = {
- .name = TYPE_VIRTIO_RNG_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIORngPCI),
- .instance_init = virtio_rng_initfn,
- .class_init = virtio_rng_pci_class_init,
-};
-
-/* virtio-input-pci */
-
-static Property virtio_input_pci_properties[] = {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
-{
- VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
- DeviceState *vdev = DEVICE(&vinput->vdev);
-
- qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
- virtio_pci_force_virtio_1(vpci_dev);
- object_property_set_bool(OBJECT(vdev), true, "realized", errp);
-}
-
-static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- dc->props = virtio_input_pci_properties;
- k->realize = virtio_input_pci_realize;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
-}
-
-static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
-{
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
-}
-
-static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
- void *data)
-{
- PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
- pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
-}
-
-static void virtio_keyboard_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_KEYBOARD);
-}
-
-static void virtio_mouse_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_MOUSE);
-}
-
-static void virtio_tablet_initfn(Object *obj)
-{
- VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_TABLET);
-}
-
-static const TypeInfo virtio_input_pci_info = {
- .name = TYPE_VIRTIO_INPUT_PCI,
- .parent = TYPE_VIRTIO_PCI,
- .instance_size = sizeof(VirtIOInputPCI),
- .class_init = virtio_input_pci_class_init,
- .abstract = true,
-};
-
-static const TypeInfo virtio_input_hid_pci_info = {
- .name = TYPE_VIRTIO_INPUT_HID_PCI,
- .parent = TYPE_VIRTIO_INPUT_PCI,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .abstract = true,
-};
-
-static const TypeInfo virtio_keyboard_pci_info = {
- .name = TYPE_VIRTIO_KEYBOARD_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .class_init = virtio_input_hid_kbd_pci_class_init,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_keyboard_initfn,
-};
-
-static const TypeInfo virtio_mouse_pci_info = {
- .name = TYPE_VIRTIO_MOUSE_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .class_init = virtio_input_hid_mouse_pci_class_init,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_mouse_initfn,
-};
-
-static const TypeInfo virtio_tablet_pci_info = {
- .name = TYPE_VIRTIO_TABLET_PCI,
- .parent = TYPE_VIRTIO_INPUT_HID_PCI,
- .instance_size = sizeof(VirtIOInputHIDPCI),
- .instance_init = virtio_tablet_initfn,
-};
-
-#ifdef CONFIG_LINUX
-static void virtio_host_initfn(Object *obj)
-{
- VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VIRTIO_INPUT_HOST);
-}
-
-static const TypeInfo virtio_host_pci_info = {
- .name = TYPE_VIRTIO_INPUT_HOST_PCI,
- .parent = TYPE_VIRTIO_INPUT_PCI,
- .instance_size = sizeof(VirtIOInputHostPCI),
- .instance_init = virtio_host_initfn,
-};
-#endif
-
/* virtio-pci-bus */
static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
@@ -2692,37 +2045,10 @@ static const TypeInfo virtio_pci_bus_info = {
static void virtio_pci_register_types(void)
{
- type_register_static(&virtio_rng_pci_info);
- type_register_static(&virtio_input_pci_info);
- type_register_static(&virtio_input_hid_pci_info);
- type_register_static(&virtio_keyboard_pci_info);
- type_register_static(&virtio_mouse_pci_info);
- type_register_static(&virtio_tablet_pci_info);
-#ifdef CONFIG_LINUX
- type_register_static(&virtio_host_pci_info);
-#endif
+ /* Base types: */
type_register_static(&virtio_pci_bus_info);
type_register_static(&virtio_pci_info);
-#ifdef CONFIG_VIRTFS
- type_register_static(&virtio_9p_pci_info);
-#endif
- type_register_static(&virtio_blk_pci_info);
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
- type_register_static(&vhost_user_blk_pci_info);
-#endif
- type_register_static(&virtio_scsi_pci_info);
- type_register_static(&virtio_balloon_pci_info);
- type_register_static(&virtio_serial_pci_info);
- type_register_static(&virtio_net_pci_info);
-#ifdef CONFIG_VHOST_SCSI
- type_register_static(&vhost_scsi_pci_info);
-#endif
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
- type_register_static(&vhost_user_scsi_pci_info);
-#endif
-#ifdef CONFIG_VHOST_VSOCK
- type_register_static(&vhost_vsock_pci_info);
-#endif
}
type_init(virtio_pci_register_types)
+
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 813082b0d7..bd223a6e3b 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -16,47 +16,9 @@
#define QEMU_VIRTIO_PCI_H
#include "hw/pci/msi.h"
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-rng.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
-#include "hw/virtio/virtio-balloon.h"
#include "hw/virtio/virtio-bus.h"
-#include "hw/virtio/virtio-input.h"
-#include "hw/virtio/virtio-gpu.h"
-#include "hw/virtio/virtio-crypto.h"
-#include "hw/virtio/vhost-user-scsi.h"
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
-#include "hw/virtio/vhost-user-blk.h"
-#endif
-
-#ifdef CONFIG_VIRTFS
-#include "hw/9pfs/virtio-9p.h"
-#endif
-#ifdef CONFIG_VHOST_SCSI
-#include "hw/virtio/vhost-scsi.h"
-#endif
-#ifdef CONFIG_VHOST_VSOCK
-#include "hw/virtio/vhost-vsock.h"
-#endif
typedef struct VirtIOPCIProxy VirtIOPCIProxy;
-typedef struct VirtIOBlkPCI VirtIOBlkPCI;
-typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
-typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
-typedef struct VirtIOSerialPCI VirtIOSerialPCI;
-typedef struct VirtIONetPCI VirtIONetPCI;
-typedef struct VHostSCSIPCI VHostSCSIPCI;
-typedef struct VHostUserSCSIPCI VHostUserSCSIPCI;
-typedef struct VHostUserBlkPCI VHostUserBlkPCI;
-typedef struct VirtIORngPCI VirtIORngPCI;
-typedef struct VirtIOInputPCI VirtIOInputPCI;
-typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
-typedef struct VirtIOInputHostPCI VirtIOInputHostPCI;
-typedef struct VirtIOGPUPCI VirtIOGPUPCI;
-typedef struct VHostVSockPCI VHostVSockPCI;
-typedef struct VirtIOCryptoPCI VirtIOCryptoPCI;
/* virtio-pci-bus */
@@ -214,207 +176,65 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
}
/*
- * virtio-scsi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci"
-#define VIRTIO_SCSI_PCI(obj) \
- OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
-
-struct VirtIOSCSIPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOSCSI vdev;
-};
-
-#ifdef CONFIG_VHOST_SCSI
-/*
- * vhost-scsi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VHOST_SCSI_PCI "vhost-scsi-pci"
-#define VHOST_SCSI_PCI(obj) \
- OBJECT_CHECK(VHostSCSIPCI, (obj), TYPE_VHOST_SCSI_PCI)
-
-struct VHostSCSIPCI {
- VirtIOPCIProxy parent_obj;
- VHostSCSI vdev;
-};
-#endif
-
-#define TYPE_VHOST_USER_SCSI_PCI "vhost-user-scsi-pci"
-#define VHOST_USER_SCSI_PCI(obj) \
- OBJECT_CHECK(VHostUserSCSIPCI, (obj), TYPE_VHOST_USER_SCSI_PCI)
-
-struct VHostUserSCSIPCI {
- VirtIOPCIProxy parent_obj;
- VHostUserSCSI vdev;
-};
-
-#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
-/*
- * vhost-user-blk-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VHOST_USER_BLK_PCI "vhost-user-blk-pci"
-#define VHOST_USER_BLK_PCI(obj) \
- OBJECT_CHECK(VHostUserBlkPCI, (obj), TYPE_VHOST_USER_BLK_PCI)
-
-struct VHostUserBlkPCI {
- VirtIOPCIProxy parent_obj;
- VHostUserBlk vdev;
-};
-#endif
-
-/*
- * virtio-blk-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci"
-#define VIRTIO_BLK_PCI(obj) \
- OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
-
-struct VirtIOBlkPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOBlock vdev;
-};
-
-/*
- * virtio-balloon-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci"
-#define VIRTIO_BALLOON_PCI(obj) \
- OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
-
-struct VirtIOBalloonPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOBalloon vdev;
-};
-
-/*
- * virtio-serial-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci"
-#define VIRTIO_SERIAL_PCI(obj) \
- OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI)
-
-struct VirtIOSerialPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOSerial vdev;
-};
-
-/*
- * virtio-net-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_NET_PCI "virtio-net-pci"
-#define VIRTIO_NET_PCI(obj) \
- OBJECT_CHECK(VirtIONetPCI, (obj), TYPE_VIRTIO_NET_PCI)
-
-struct VirtIONetPCI {
- VirtIOPCIProxy parent_obj;
- VirtIONet vdev;
-};
-
-/*
- * virtio-9p-pci: This extends VirtioPCIProxy.
- */
-
-#ifdef CONFIG_VIRTFS
-
-#define TYPE_VIRTIO_9P_PCI "virtio-9p-pci"
-#define VIRTIO_9P_PCI(obj) \
- OBJECT_CHECK(V9fsPCIState, (obj), TYPE_VIRTIO_9P_PCI)
-
-typedef struct V9fsPCIState {
- VirtIOPCIProxy parent_obj;
- V9fsVirtioState vdev;
-} V9fsPCIState;
-
-#endif
-
-/*
- * virtio-rng-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci"
-#define VIRTIO_RNG_PCI(obj) \
- OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
-
-struct VirtIORngPCI {
- VirtIOPCIProxy parent_obj;
- VirtIORNG vdev;
-};
-
-/*
* virtio-input-pci: This extends VirtioPCIProxy.
*/
#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
-#define VIRTIO_INPUT_PCI(obj) \
- OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
-
-struct VirtIOInputPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInput vdev;
-};
-
-#define TYPE_VIRTIO_INPUT_HID_PCI "virtio-input-hid-pci"
-#define TYPE_VIRTIO_KEYBOARD_PCI "virtio-keyboard-pci"
-#define TYPE_VIRTIO_MOUSE_PCI "virtio-mouse-pci"
-#define TYPE_VIRTIO_TABLET_PCI "virtio-tablet-pci"
-#define VIRTIO_INPUT_HID_PCI(obj) \
- OBJECT_CHECK(VirtIOInputHIDPCI, (obj), TYPE_VIRTIO_INPUT_HID_PCI)
-
-struct VirtIOInputHIDPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInputHID vdev;
-};
-
-#ifdef CONFIG_LINUX
-
-#define TYPE_VIRTIO_INPUT_HOST_PCI "virtio-input-host-pci"
-#define VIRTIO_INPUT_HOST_PCI(obj) \
- OBJECT_CHECK(VirtIOInputHostPCI, (obj), TYPE_VIRTIO_INPUT_HOST_PCI)
-
-struct VirtIOInputHostPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOInputHost vdev;
-};
-
-#endif
-
-/*
- * virtio-gpu-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
-#define VIRTIO_GPU_PCI(obj) \
- OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
-
-struct VirtIOGPUPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOGPU vdev;
-};
-
-#ifdef CONFIG_VHOST_VSOCK
-/*
- * vhost-vsock-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VHOST_VSOCK_PCI "vhost-vsock-pci"
-#define VHOST_VSOCK_PCI(obj) \
- OBJECT_CHECK(VHostVSockPCI, (obj), TYPE_VHOST_VSOCK_PCI)
-
-struct VHostVSockPCI {
- VirtIOPCIProxy parent_obj;
- VHostVSock vdev;
-};
-#endif
-
-/*
- * virtio-crypto-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_CRYPTO_PCI "virtio-crypto-pci"
-#define VIRTIO_CRYPTO_PCI(obj) \
- OBJECT_CHECK(VirtIOCryptoPCI, (obj), TYPE_VIRTIO_CRYPTO_PCI)
-
-struct VirtIOCryptoPCI {
- VirtIOPCIProxy parent_obj;
- VirtIOCrypto vdev;
-};
/* Virtio ABI version, if we increment this, we break the guest driver. */
#define VIRTIO_PCI_ABI_VERSION 0
+/* Input for virtio_pci_types_register() */
+typedef struct VirtioPCIDeviceTypeInfo {
+ /*
+ * Common base class for the subclasses below.
+ *
+ * Required only if transitional_name or non_transitional_name is set.
+ *
+ * We need a separate base type instead of making all types
+ * inherit from generic_name for two reasons:
+ * 1) generic_name implements INTERFACE_PCIE_DEVICE, but
+ * transitional_name does not.
+ * 2) generic_name has the "disable-legacy" and "disable-modern"
+ * properties, transitional_name and non_transitional name don't.
+ */
+ const char *base_name;
+ /*
+ * Generic device type. Optional.
+ *
+ * Supports both transitional and non-transitional modes,
+ * using the disable-legacy and disable-modern properties.
+ * If disable-legacy=auto, (non-)transitional mode is selected
+ * depending on the bus where the device is plugged.
+ *
+ * Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE,
+ * but PCI Express is supported only in non-transitional mode.
+ *
+ * The only type implemented by QEMU 3.1 and older.
+ */
+ const char *generic_name;
+ /*
+ * The transitional device type. Optional.
+ *
+ * Implements both INTERFACE_PCIE_DEVICE and INTERFACE_CONVENTIONAL_PCI_DEVICE.
+ */
+ const char *transitional_name;
+ /*
+ * The non-transitional device type. Optional.
+ *
+ * Implements INTERFACE_CONVENTIONAL_PCI_DEVICE only.
+ */
+ const char *non_transitional_name;
+
+ /* Parent type. If NULL, TYPE_VIRTIO_PCI is used */
+ const char *parent;
+
+ /* Same as TypeInfo fields: */
+ size_t instance_size;
+ void (*instance_init)(Object *obj);
+ void (*class_init)(ObjectClass *klass, void *data);
+} VirtioPCIDeviceTypeInfo;
+
+/* Register virtio-pci type(s). @t must be static. */
+void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t);
+
#endif
diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c
new file mode 100644
index 0000000000..6cc6374289
--- /dev/null
+++ b/hw/virtio/virtio-rng-pci.c
@@ -0,0 +1,88 @@
+/*
+ * Virtio rng PCI Bindings
+ *
+ * Copyright 2012 Red Hat, Inc.
+ * Copyright 2012 Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "virtio-pci.h"
+#include "hw/virtio/virtio-rng.h"
+#include "qapi/error.h"
+
+typedef struct VirtIORngPCI VirtIORngPCI;
+
+/*
+ * virtio-rng-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci-base"
+#define VIRTIO_RNG_PCI(obj) \
+ OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
+
+struct VirtIORngPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIORNG vdev;
+};
+
+static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&vrng->vdev);
+ Error *err = NULL;
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ object_property_set_link(OBJECT(vrng),
+ OBJECT(vrng->vdev.conf.rng), "rng",
+ NULL);
+}
+
+static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = virtio_rng_pci_realize;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_rng_initfn(Object *obj)
+{
+ VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_RNG);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_rng_pci_info = {
+ .base_name = TYPE_VIRTIO_RNG_PCI,
+ .generic_name = "virtio-rng-pci",
+ .transitional_name = "virtio-rng-pci-transitional",
+ .non_transitional_name = "virtio-rng-pci-non-transitional",
+ .instance_size = sizeof(VirtIORngPCI),
+ .instance_init = virtio_rng_initfn,
+ .class_init = virtio_rng_pci_class_init,
+};
+
+static void virtio_rng_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_rng_pci_info);
+}
+
+type_init(virtio_rng_pci_register)
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 855f1b41d1..30493a2586 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -191,7 +191,7 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
if (vrng->conf.rng == NULL) {
vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
- user_creatable_complete(OBJECT(vrng->conf.default_backend),
+ user_creatable_complete(USER_CREATABLE(vrng->conf.default_backend),
&local_err);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c
new file mode 100644
index 0000000000..2830849729
--- /dev/null
+++ b/hw/virtio/virtio-scsi-pci.c
@@ -0,0 +1,107 @@
+/*
+ * Virtio scsi PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-scsi.h"
+#include "virtio-pci.h"
+
+typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
+
+/*
+ * virtio-scsi-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci-base"
+#define VIRTIO_SCSI_PCI(obj) \
+ OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
+
+struct VirtIOSCSIPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOSCSI vdev;
+};
+
+static Property virtio_scsi_pci_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_END_OF_LIST(),
+};
+
+static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+ DeviceState *proxy = DEVICE(vpci_dev);
+ char *bus_name;
+
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = vs->conf.num_queues + 3;
+ }
+
+ /*
+ * For command line compatibility, this sets the virtio-scsi-device bus
+ * name as before.
+ */
+ if (proxy->id) {
+ bus_name = g_strdup_printf("%s.0", proxy->id);
+ virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
+ g_free(bus_name);
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = virtio_scsi_pci_realize;
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+ dc->props = virtio_scsi_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
+ pcidev_k->revision = 0x00;
+ pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void virtio_scsi_pci_instance_init(Object *obj)
+{
+ VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_SCSI);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_scsi_pci_info = {
+ .base_name = TYPE_VIRTIO_SCSI_PCI,
+ .generic_name = "virtio-scsi-pci",
+ .transitional_name = "virtio-scsi-pci-transitional",
+ .non_transitional_name = "virtio-scsi-pci-non-transitional",
+ .instance_size = sizeof(VirtIOSCSIPCI),
+ .instance_init = virtio_scsi_pci_instance_init,
+ .class_init = virtio_scsi_pci_class_init,
+};
+
+static void virtio_scsi_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_scsi_pci_info);
+}
+
+type_init(virtio_scsi_pci_register)
diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c
new file mode 100644
index 0000000000..971b2eb8d8
--- /dev/null
+++ b/hw/virtio/virtio-serial-pci.c
@@ -0,0 +1,115 @@
+/*
+ * Virtio serial PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-serial.h"
+#include "virtio-pci.h"
+
+typedef struct VirtIOSerialPCI VirtIOSerialPCI;
+
+/*
+ * virtio-serial-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SERIAL_PCI "virtio-serial-pci-base"
+#define VIRTIO_SERIAL_PCI(obj) \
+ OBJECT_CHECK(VirtIOSerialPCI, (obj), TYPE_VIRTIO_SERIAL_PCI)
+
+struct VirtIOSerialPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIOSerial vdev;
+};
+
+static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+ VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+ DeviceState *proxy = DEVICE(vpci_dev);
+ char *bus_name;
+
+ if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
+ vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
+ vpci_dev->class_code != PCI_CLASS_OTHERS) { /* qemu-kvm */
+ vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
+ }
+
+ /* backwards-compatibility with machines that were created with
+ DEV_NVECTORS_UNSPECIFIED */
+ if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+ vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
+ }
+
+ /*
+ * For command line compatibility, this sets the virtio-serial-device bus
+ * name as before.
+ */
+ if (proxy->id) {
+ bus_name = g_strdup_printf("%s.0", proxy->id);
+ virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
+ g_free(bus_name);
+ }
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+static Property virtio_serial_pci_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+ k->realize = virtio_serial_pci_realize;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+ dc->props = virtio_serial_pci_properties;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+}
+
+static void virtio_serial_pci_instance_init(Object *obj)
+{
+ VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_SERIAL);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_serial_pci_info = {
+ .base_name = TYPE_VIRTIO_SERIAL_PCI,
+ .generic_name = "virtio-serial-pci",
+ .transitional_name = "virtio-serial-pci-transitional",
+ .non_transitional_name = "virtio-serial-pci-non-transitional",
+ .instance_size = sizeof(VirtIOSerialPCI),
+ .instance_init = virtio_serial_pci_instance_init,
+ .class_init = virtio_serial_pci_class_init,
+};
+
+static void virtio_serial_pci_register(void)
+{
+ virtio_pci_types_register(&virtio_serial_pci_info);
+}
+
+type_init(virtio_serial_pci_register)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 5828ed14df..22bd1ac34e 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -796,13 +796,13 @@ static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num,
}
static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg,
- hwaddr *addr, unsigned int *num_sg,
+ hwaddr *addr, unsigned int num_sg,
int is_write)
{
unsigned int i;
hwaddr len;
- for (i = 0; i < *num_sg; i++) {
+ for (i = 0; i < num_sg; i++) {
len = sg[i].iov_len;
sg[i].iov_base = dma_memory_map(vdev->dma_as,
addr[i], &len, is_write ?
@@ -821,8 +821,8 @@ static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg,
void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem)
{
- virtqueue_map_iovec(vdev, elem->in_sg, elem->in_addr, &elem->in_num, 1);
- virtqueue_map_iovec(vdev, elem->out_sg, elem->out_addr, &elem->out_num, 0);
+ virtqueue_map_iovec(vdev, elem->in_sg, elem->in_addr, elem->in_num, 1);
+ virtqueue_map_iovec(vdev, elem->out_sg, elem->out_addr, elem->out_num, 0);
}
static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index 33e6c20184..dce7c1db14 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -32,7 +32,7 @@
#include "qemu/help_option.h"
static WatchdogAction watchdog_action = WATCHDOG_ACTION_RESET;
-static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
+static QLIST_HEAD(, WatchdogTimerModel) watchdog_list;
void watchdog_add_model(WatchdogTimerModel *model)
{
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index 7b59469888..1c6eddf86a 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -449,7 +449,6 @@ static void i6300esb_realize(PCIDevice *dev, Error **errp)
memory_region_init_io(&d->io_mem, OBJECT(d), &i6300esb_ops, d,
"i6300esb", 0x10);
pci_register_bar(&d->dev, 0, 0, &d->io_mem);
- /* qemu_register_coalesced_mmio (addr, 0x10); ? */
}
static void i6300esb_exit(PCIDevice *dev)
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
index 9ea5c73423..84df60a928 100644
--- a/hw/xen/Makefile.objs
+++ b/hw/xen/Makefile.objs
@@ -1,5 +1,5 @@
# xen backend driver support
-common-obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o xen_pvdev.o xen-common.o
+common-obj-$(CONFIG_XEN) += xen-legacy-backend.o xen_devconfig.o xen_pvdev.o xen-common.o xen-bus.o xen-bus-helper.o xen-backend.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index c7e7a3b523..f6944624b2 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -12,3 +12,29 @@ xen_unmap_portio_range(uint32_t id, uint64_t start_addr, uint64_t end_addr) "id:
xen_map_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
xen_unmap_pcidev(uint32_t id, uint8_t bus, uint8_t dev, uint8_t func) "id: %u bdf: %02x.%02x.%02x"
xen_domid_restrict(int err) "err: %u"
+
+# include/hw/xen/xen-bus.c
+xen_bus_realize(void) ""
+xen_bus_unrealize(void) ""
+xen_bus_enumerate(void) ""
+xen_bus_type_enumerate(const char *type) "type: %s"
+xen_bus_backend_create(const char *type, const char *path) "type: %s path: %s"
+xen_bus_add_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
+xen_bus_remove_watch(const char *node, const char *key, char *token) "node: %s key: %s token: %s"
+xen_bus_watch(const char *token) "token: %s"
+xen_device_realize(const char *type, char *name) "type: %s name: %s"
+xen_device_unrealize(const char *type, char *name) "type: %s name: %s"
+xen_device_backend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
+xen_device_backend_online(const char *type, char *name, bool online) "type: %s name: %s -> %u"
+xen_device_backend_changed(const char *type, char *name) "type: %s name: %s"
+xen_device_frontend_state(const char *type, char *name, const char *state) "type: %s name: %s -> %s"
+xen_device_frontend_changed(const char *type, char *name) "type: %s name: %s"
+xen_device_unplug(const char *type, char *name) "type: %s name: %s"
+
+# include/hw/xen/xen-bus-helper.c
+xs_node_create(const char *node) "%s"
+xs_node_destroy(const char *node) "%s"
+xs_node_vprintf(char *path, char *value) "%s %s"
+xs_node_vscanf(char *path, char *value) "%s %s"
+xs_node_watch(char *path) "%s"
+xs_node_unwatch(char *path) "%s"
diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c
new file mode 100644
index 0000000000..da065f81b7
--- /dev/null
+++ b/hw/xen/xen-backend.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/xen/xen-backend.h"
+#include "hw/xen/xen-bus.h"
+
+typedef struct XenBackendImpl {
+ const char *type;
+ XenBackendDeviceCreate create;
+ XenBackendDeviceDestroy destroy;
+} XenBackendImpl;
+
+struct XenBackendInstance {
+ QLIST_ENTRY(XenBackendInstance) entry;
+ const XenBackendImpl *impl;
+ XenBus *xenbus;
+ char *name;
+ XenDevice *xendev;
+};
+
+static GHashTable *xen_backend_table_get(void)
+{
+ static GHashTable *table;
+
+ if (table == NULL) {
+ table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ return table;
+}
+
+static void xen_backend_table_add(XenBackendImpl *impl)
+{
+ g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl);
+}
+
+static const XenBackendImpl *xen_backend_table_lookup(const char *type)
+{
+ return g_hash_table_lookup(xen_backend_table_get(), type);
+}
+
+void xen_backend_register(const XenBackendInfo *info)
+{
+ XenBackendImpl *impl = g_new0(XenBackendImpl, 1);
+
+ g_assert(info->type);
+
+ if (xen_backend_table_lookup(info->type)) {
+ error_report("attempt to register duplicate Xen backend type '%s'",
+ info->type);
+ abort();
+ }
+
+ if (!info->create) {
+ error_report("backend type '%s' has no creator", info->type);
+ abort();
+ }
+
+ impl->type = info->type;
+ impl->create = info->create;
+ impl->destroy = info->destroy;
+
+ xen_backend_table_add(impl);
+}
+
+static QLIST_HEAD(, XenBackendInstance) backend_list;
+
+static void xen_backend_list_add(XenBackendInstance *backend)
+{
+ QLIST_INSERT_HEAD(&backend_list, backend, entry);
+}
+
+static XenBackendInstance *xen_backend_list_find(XenDevice *xendev)
+{
+ XenBackendInstance *backend;
+
+ QLIST_FOREACH(backend, &backend_list, entry) {
+ if (backend->xendev == xendev) {
+ return backend;
+ }
+ }
+
+ return NULL;
+}
+
+static void xen_backend_list_remove(XenBackendInstance *backend)
+{
+ QLIST_REMOVE(backend, entry);
+}
+
+void xen_backend_device_create(XenBus *xenbus, const char *type,
+ const char *name, QDict *opts, Error **errp)
+{
+ const XenBackendImpl *impl = xen_backend_table_lookup(type);
+ XenBackendInstance *backend;
+ Error *local_error = NULL;
+
+ if (!impl) {
+ return;
+ }
+
+ backend = g_new0(XenBackendInstance, 1);
+ backend->xenbus = xenbus;
+ backend->name = g_strdup(name);
+
+ impl->create(backend, opts, &local_error);
+ if (local_error) {
+ error_propagate(errp, local_error);
+ g_free(backend->name);
+ g_free(backend);
+ return;
+ }
+
+ backend->impl = impl;
+ xen_backend_list_add(backend);
+}
+
+XenBus *xen_backend_get_bus(XenBackendInstance *backend)
+{
+ return backend->xenbus;
+}
+
+const char *xen_backend_get_name(XenBackendInstance *backend)
+{
+ return backend->name;
+}
+
+void xen_backend_set_device(XenBackendInstance *backend,
+ XenDevice *xendev)
+{
+ g_assert(!backend->xendev);
+ backend->xendev = xendev;
+}
+
+XenDevice *xen_backend_get_device(XenBackendInstance *backend)
+{
+ return backend->xendev;
+}
+
+
+bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp)
+{
+ XenBackendInstance *backend = xen_backend_list_find(xendev);
+ const XenBackendImpl *impl;
+
+ if (!backend) {
+ return false;
+ }
+
+ impl = backend->impl;
+ impl->destroy(backend, errp);
+
+ xen_backend_list_remove(backend);
+ g_free(backend->name);
+ g_free(backend);
+
+ return true;
+}
diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c
new file mode 100644
index 0000000000..5f7a4b2612
--- /dev/null
+++ b/hw/xen/xen-bus-helper.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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/osdep.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/xen/xen.h"
+#include "hw/xen/xen-bus.h"
+#include "hw/xen/xen-bus-helper.h"
+#include "qapi/error.h"
+
+#include <glib/gprintf.h>
+
+struct xs_state {
+ enum xenbus_state statenum;
+ const char *statestr;
+};
+#define XS_STATE(state) { state, #state }
+
+static struct xs_state xs_state[] = {
+ XS_STATE(XenbusStateUnknown),
+ XS_STATE(XenbusStateInitialising),
+ XS_STATE(XenbusStateInitWait),
+ XS_STATE(XenbusStateInitialised),
+ XS_STATE(XenbusStateConnected),
+ XS_STATE(XenbusStateClosing),
+ XS_STATE(XenbusStateClosed),
+ XS_STATE(XenbusStateReconfiguring),
+ XS_STATE(XenbusStateReconfigured),
+};
+
+#undef XS_STATE
+
+const char *xs_strstate(enum xenbus_state state)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(xs_state); i++) {
+ if (xs_state[i].statenum == state) {
+ return xs_state[i].statestr;
+ }
+ }
+
+ return "INVALID";
+}
+
+void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, struct xs_permissions perms[],
+ unsigned int nr_perms, Error **errp)
+{
+ trace_xs_node_create(node);
+
+ if (!xs_write(xsh, tid, node, "", 0)) {
+ error_setg_errno(errp, errno, "failed to create node '%s'", node);
+ return;
+ }
+
+ if (!xs_set_permissions(xsh, tid, node, perms, nr_perms)) {
+ error_setg_errno(errp, errno, "failed to set node '%s' permissions",
+ node);
+ }
+}
+
+void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, Error **errp)
+{
+ trace_xs_node_destroy(node);
+
+ if (!xs_rm(xsh, tid, node)) {
+ error_setg_errno(errp, errno, "failed to destroy node '%s'", node);
+ }
+}
+
+void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, va_list ap)
+{
+ char *path, *value;
+ int len;
+
+ path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
+ g_strdup(key);
+ len = g_vasprintf(&value, fmt, ap);
+
+ trace_xs_node_vprintf(path, value);
+
+ if (!xs_write(xsh, tid, path, value, len)) {
+ error_setg_errno(errp, errno, "failed to write '%s' to '%s'",
+ value, path);
+ }
+
+ g_free(value);
+ g_free(path);
+}
+
+void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xs_node_vprintf(xsh, tid, node, key, errp, fmt, ap);
+ va_end(ap);
+}
+
+int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, va_list ap)
+{
+ char *path, *value;
+ int rc;
+
+ path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
+ g_strdup(key);
+ value = xs_read(xsh, tid, path, NULL);
+
+ trace_xs_node_vscanf(path, value);
+
+ if (value) {
+ rc = vsscanf(value, fmt, ap);
+ } else {
+ error_setg_errno(errp, errno, "failed to read from '%s'",
+ path);
+ rc = EOF;
+ }
+
+ free(value);
+ g_free(path);
+
+ return rc;
+}
+
+int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, fmt);
+ rc = xs_node_vscanf(xsh, tid, node, key, errp, fmt, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
+ char *token, Error **errp)
+{
+ char *path;
+
+ path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
+ g_strdup(key);
+
+ trace_xs_node_watch(path);
+
+ if (!xs_watch(xsh, path, token)) {
+ error_setg_errno(errp, errno, "failed to watch node '%s'", path);
+ }
+
+ g_free(path);
+}
+
+void xs_node_unwatch(struct xs_handle *xsh, const char *node,
+ const char *key, const char *token, Error **errp)
+{
+ char *path;
+
+ path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
+ g_strdup(key);
+
+ trace_xs_node_unwatch(path);
+
+ if (!xs_unwatch(xsh, path, token)) {
+ error_setg_errno(errp, errno, "failed to unwatch node '%s'", path);
+ }
+
+ g_free(path);
+}
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
new file mode 100644
index 0000000000..3aeccec69c
--- /dev/null
+++ b/hw/xen/xen-bus.c
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/uuid.h"
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/xen/xen.h"
+#include "hw/xen/xen-backend.h"
+#include "hw/xen/xen-bus.h"
+#include "hw/xen/xen-bus-helper.h"
+#include "monitor/monitor.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+static char *xen_device_get_backend_path(XenDevice *xendev)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(xendev));
+ const char *backend = xendev_class->backend;
+
+ if (!backend) {
+ backend = type;
+ }
+
+ return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
+ xenbus->backend_id, backend, xendev->frontend_id,
+ xendev->name);
+}
+
+static char *xen_device_get_frontend_path(XenDevice *xendev)
+{
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(xendev));
+ const char *device = xendev_class->device;
+
+ if (!device) {
+ device = type;
+ }
+
+ return g_strdup_printf("/local/domain/%u/device/%s/%s",
+ xendev->frontend_id, device, xendev->name);
+}
+
+static void xen_device_unplug(XenDevice *xendev, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ const char *type = object_get_typename(OBJECT(xendev));
+ Error *local_err = NULL;
+ xs_transaction_t tid;
+
+ trace_xen_device_unplug(type, xendev->name);
+
+ /* Mimic the way the Xen toolstack does an unplug */
+again:
+ tid = xs_transaction_start(xenbus->xsh);
+ if (tid == XBT_NULL) {
+ error_setg_errno(errp, errno, "failed xs_transaction_start");
+ return;
+ }
+
+ xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
+ &local_err, "%u", 0);
+ if (local_err) {
+ goto abort;
+ }
+
+ xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
+ &local_err, "%u", XenbusStateClosing);
+ if (local_err) {
+ goto abort;
+ }
+
+ if (!xs_transaction_end(xenbus->xsh, tid, false)) {
+ if (errno == EAGAIN) {
+ goto again;
+ }
+
+ error_setg_errno(errp, errno, "failed xs_transaction_end");
+ }
+
+ return;
+
+abort:
+ /*
+ * We only abort if there is already a failure so ignore any error
+ * from ending the transaction.
+ */
+ xs_transaction_end(xenbus->xsh, tid, true);
+ error_propagate(errp, local_err);
+}
+
+static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
+{
+ XenDevice *xendev = XEN_DEVICE(dev);
+
+ monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
+ indent, "", xendev->name, xendev->frontend_id);
+}
+
+static char *xen_bus_get_dev_path(DeviceState *dev)
+{
+ return xen_device_get_backend_path(XEN_DEVICE(dev));
+}
+
+struct XenWatch {
+ char *node, *key;
+ char *token;
+ XenWatchHandler handler;
+ void *opaque;
+ Notifier notifier;
+};
+
+static void watch_notify(Notifier *n, void *data)
+{
+ XenWatch *watch = container_of(n, XenWatch, notifier);
+ const char *token = data;
+
+ if (!strcmp(watch->token, token)) {
+ watch->handler(watch->opaque);
+ }
+}
+
+static XenWatch *new_watch(const char *node, const char *key,
+ XenWatchHandler handler, void *opaque)
+{
+ XenWatch *watch = g_new0(XenWatch, 1);
+ QemuUUID uuid;
+
+ qemu_uuid_generate(&uuid);
+
+ watch->token = qemu_uuid_unparse_strdup(&uuid);
+ watch->node = g_strdup(node);
+ watch->key = g_strdup(key);
+ watch->handler = handler;
+ watch->opaque = opaque;
+ watch->notifier.notify = watch_notify;
+
+ return watch;
+}
+
+static void free_watch(XenWatch *watch)
+{
+ g_free(watch->token);
+ g_free(watch->key);
+ g_free(watch->node);
+
+ g_free(watch);
+}
+
+static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
+ const char *key, XenWatchHandler handler,
+ void *opaque, Error **errp)
+{
+ XenWatch *watch = new_watch(node, key, handler, opaque);
+ Error *local_err = NULL;
+
+ trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
+
+ notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
+
+ xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+
+ notifier_remove(&watch->notifier);
+ free_watch(watch);
+
+ return NULL;
+ }
+
+ return watch;
+}
+
+static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
+ Error **errp)
+{
+ trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
+
+ xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
+ errp);
+
+ notifier_remove(&watch->notifier);
+ free_watch(watch);
+}
+
+static void xen_bus_backend_create(XenBus *xenbus, const char *type,
+ const char *name, char *path,
+ Error **errp)
+{
+ xs_transaction_t tid;
+ char **key;
+ QDict *opts;
+ unsigned int i, n;
+ Error *local_err = NULL;
+
+ trace_xen_bus_backend_create(type, path);
+
+again:
+ tid = xs_transaction_start(xenbus->xsh);
+ if (tid == XBT_NULL) {
+ error_setg(errp, "failed xs_transaction_start");
+ return;
+ }
+
+ key = xs_directory(xenbus->xsh, tid, path, &n);
+ if (!key) {
+ if (!xs_transaction_end(xenbus->xsh, tid, true)) {
+ error_setg_errno(errp, errno, "failed xs_transaction_end");
+ }
+ return;
+ }
+
+ opts = qdict_new();
+ for (i = 0; i < n; i++) {
+ char *val;
+
+ /*
+ * Assume anything found in the xenstore backend area, other than
+ * the keys created for a generic XenDevice, are parameters
+ * to be used to configure the backend.
+ */
+ if (!strcmp(key[i], "state") ||
+ !strcmp(key[i], "online") ||
+ !strcmp(key[i], "frontend") ||
+ !strcmp(key[i], "frontend-id") ||
+ !strcmp(key[i], "hotplug-status"))
+ continue;
+
+ if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
+ &val) == 1) {
+ qdict_put_str(opts, key[i], val);
+ free(val);
+ }
+ }
+
+ free(key);
+
+ if (!xs_transaction_end(xenbus->xsh, tid, false)) {
+ qobject_unref(opts);
+
+ if (errno == EAGAIN) {
+ goto again;
+ }
+
+ error_setg_errno(errp, errno, "failed xs_transaction_end");
+ return;
+ }
+
+ xen_backend_device_create(xenbus, type, name, opts, &local_err);
+ qobject_unref(opts);
+
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to create '%s' device '%s': ",
+ type, name);
+ }
+}
+
+static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
+{
+ char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid);
+ char **backend;
+ unsigned int i, n;
+
+ trace_xen_bus_type_enumerate(type);
+
+ backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n);
+ if (!backend) {
+ goto out;
+ }
+
+ for (i = 0; i < n; i++) {
+ char *backend_path = g_strdup_printf("%s/%s", domain_path,
+ backend[i]);
+ enum xenbus_state backend_state;
+
+ if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state",
+ NULL, "%u", &backend_state) != 1)
+ backend_state = XenbusStateUnknown;
+
+ if (backend_state == XenbusStateInitialising) {
+ Error *local_err = NULL;
+
+ xen_bus_backend_create(xenbus, type, backend[i], backend_path,
+ &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+
+ g_free(backend_path);
+ }
+
+ free(backend);
+
+out:
+ g_free(domain_path);
+}
+
+static void xen_bus_enumerate(void *opaque)
+{
+ XenBus *xenbus = opaque;
+ char **type;
+ unsigned int i, n;
+
+ trace_xen_bus_enumerate();
+
+ type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n);
+ if (!type) {
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ xen_bus_type_enumerate(xenbus, type[i]);
+ }
+
+ free(type);
+}
+
+static void xen_bus_unrealize(BusState *bus, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(bus);
+
+ trace_xen_bus_unrealize();
+
+ if (xenbus->backend_watch) {
+ xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL);
+ xenbus->backend_watch = NULL;
+ }
+
+ if (!xenbus->xsh) {
+ return;
+ }
+
+ qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
+
+ xs_close(xenbus->xsh);
+}
+
+static void xen_bus_watch(void *opaque)
+{
+ XenBus *xenbus = opaque;
+ char **v;
+ const char *token;
+
+ g_assert(xenbus->xsh);
+
+ v = xs_check_watch(xenbus->xsh);
+ if (!v) {
+ return;
+ }
+
+ token = v[XS_WATCH_TOKEN];
+
+ trace_xen_bus_watch(token);
+
+ notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
+
+ free(v);
+}
+
+static void xen_bus_realize(BusState *bus, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(bus);
+ unsigned int domid;
+ Error *local_err = NULL;
+
+ trace_xen_bus_realize();
+
+ xenbus->xsh = xs_open(0);
+ if (!xenbus->xsh) {
+ error_setg_errno(errp, errno, "failed xs_open");
+ goto fail;
+ }
+
+ if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
+ "domid", NULL, "%u", &domid) == 1) {
+ xenbus->backend_id = domid;
+ } else {
+ xenbus->backend_id = 0; /* Assume lack of node means dom0 */
+ }
+
+ notifier_list_init(&xenbus->watch_notifiers);
+ qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
+ xenbus);
+
+ module_call_init(MODULE_INIT_XEN_BACKEND);
+
+ xenbus->backend_watch =
+ xen_bus_add_watch(xenbus, "", /* domain root node */
+ "backend", xen_bus_enumerate, xenbus, &local_err);
+ if (local_err) {
+ /* This need not be treated as a hard error so don't propagate */
+ error_reportf_err(local_err,
+ "failed to set up enumeration watch: ");
+ }
+
+ return;
+
+fail:
+ xen_bus_unrealize(bus, &error_abort);
+}
+
+static void xen_bus_unplug_request(HotplugHandler *hotplug,
+ DeviceState *dev,
+ Error **errp)
+{
+ XenDevice *xendev = XEN_DEVICE(dev);
+
+ xen_device_unplug(xendev, errp);
+}
+
+static void xen_bus_class_init(ObjectClass *class, void *data)
+{
+ BusClass *bus_class = BUS_CLASS(class);
+ HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
+
+ bus_class->print_dev = xen_bus_print_dev;
+ bus_class->get_dev_path = xen_bus_get_dev_path;
+ bus_class->realize = xen_bus_realize;
+ bus_class->unrealize = xen_bus_unrealize;
+
+ hotplug_class->unplug_request = xen_bus_unplug_request;
+}
+
+static const TypeInfo xen_bus_type_info = {
+ .name = TYPE_XEN_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(XenBus),
+ .class_size = sizeof(XenBusClass),
+ .class_init = xen_bus_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_HOTPLUG_HANDLER },
+ { }
+ },
+};
+
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ Error *local_err = NULL;
+ va_list ap;
+
+ g_assert(xenbus->xsh);
+
+ va_start(ap, fmt);
+ xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
+ &local_err, fmt, ap);
+ va_end(ap);
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+}
+
+static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ va_list ap;
+ int rc;
+
+ g_assert(xenbus->xsh);
+
+ va_start(ap, fmt);
+ rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
+ NULL, fmt, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+void xen_device_backend_set_state(XenDevice *xendev,
+ enum xenbus_state state)
+{
+ const char *type = object_get_typename(OBJECT(xendev));
+
+ if (xendev->backend_state == state) {
+ return;
+ }
+
+ trace_xen_device_backend_state(type, xendev->name,
+ xs_strstate(state));
+
+ xendev->backend_state = state;
+ xen_device_backend_printf(xendev, "state", "%u", state);
+}
+
+enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
+{
+ return xendev->backend_state;
+}
+
+static void xen_device_backend_set_online(XenDevice *xendev, bool online)
+{
+ const char *type = object_get_typename(OBJECT(xendev));
+
+ if (xendev->backend_online == online) {
+ return;
+ }
+
+ trace_xen_device_backend_online(type, xendev->name, online);
+
+ xendev->backend_online = online;
+ xen_device_backend_printf(xendev, "online", "%u", online);
+}
+
+static void xen_device_backend_changed(void *opaque)
+{
+ XenDevice *xendev = opaque;
+ const char *type = object_get_typename(OBJECT(xendev));
+ enum xenbus_state state;
+ unsigned int online;
+
+ trace_xen_device_backend_changed(type, xendev->name);
+
+ if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
+ state = XenbusStateUnknown;
+ }
+
+ xen_device_backend_set_state(xendev, state);
+
+ if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
+ online = 0;
+ }
+
+ xen_device_backend_set_online(xendev, !!online);
+
+ /*
+ * If the toolstack (or unplug request callback) has set the backend
+ * state to Closing, but there is no active frontend (i.e. the
+ * state is not Connected) then set the backend state to Closed.
+ */
+ if (xendev->backend_state == XenbusStateClosing &&
+ xendev->frontend_state != XenbusStateConnected) {
+ xen_device_backend_set_state(xendev, XenbusStateClosed);
+ }
+
+ /*
+ * If a backend is still 'online' then its state should be cycled
+ * back round to InitWait in order for a new frontend instance to
+ * connect. This may happen when, for example, a frontend driver is
+ * re-installed or updated.
+ * If a backend is not 'online' then the device should be destroyed.
+ */
+ if (xendev->backend_online &&
+ xendev->backend_state == XenbusStateClosed) {
+ xen_device_backend_set_state(xendev, XenbusStateInitWait);
+ } else if (!xendev->backend_online &&
+ (xendev->backend_state == XenbusStateClosed ||
+ xendev->backend_state == XenbusStateInitialising ||
+ xendev->backend_state == XenbusStateInitWait ||
+ xendev->backend_state == XenbusStateUnknown)) {
+ Error *local_err = NULL;
+
+ if (!xen_backend_try_device_destroy(xendev, &local_err)) {
+ object_unparent(OBJECT(xendev));
+ }
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ }
+}
+
+static void xen_device_backend_create(XenDevice *xendev, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ struct xs_permissions perms[2];
+ Error *local_err = NULL;
+
+ xendev->backend_path = xen_device_get_backend_path(xendev);
+
+ perms[0].id = xenbus->backend_id;
+ perms[0].perms = XS_PERM_NONE;
+ perms[1].id = xendev->frontend_id;
+ perms[1].perms = XS_PERM_READ;
+
+ g_assert(xenbus->xsh);
+
+ xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
+ ARRAY_SIZE(perms), &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to create backend: ");
+ return;
+ }
+
+ xendev->backend_state_watch =
+ xen_bus_add_watch(xenbus, xendev->backend_path,
+ "state", xen_device_backend_changed,
+ xendev, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to watch backend state: ");
+ return;
+ }
+
+ xendev->backend_online_watch =
+ xen_bus_add_watch(xenbus, xendev->backend_path,
+ "online", xen_device_backend_changed,
+ xendev, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to watch backend online: ");
+ return;
+ }
+}
+
+static void xen_device_backend_destroy(XenDevice *xendev)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ Error *local_err = NULL;
+
+ if (xendev->backend_online_watch) {
+ xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
+ xendev->backend_online_watch = NULL;
+ }
+
+ if (xendev->backend_state_watch) {
+ xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
+ xendev->backend_state_watch = NULL;
+ }
+
+ if (!xendev->backend_path) {
+ return;
+ }
+
+ g_assert(xenbus->xsh);
+
+ xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
+ &local_err);
+ g_free(xendev->backend_path);
+ xendev->backend_path = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+}
+
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ Error *local_err = NULL;
+ va_list ap;
+
+ g_assert(xenbus->xsh);
+
+ va_start(ap, fmt);
+ xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
+ &local_err, fmt, ap);
+ va_end(ap);
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+}
+
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ va_list ap;
+ int rc;
+
+ g_assert(xenbus->xsh);
+
+ va_start(ap, fmt);
+ rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
+ NULL, fmt, ap);
+ va_end(ap);
+
+ return rc;
+}
+
+static void xen_device_frontend_set_state(XenDevice *xendev,
+ enum xenbus_state state)
+{
+ const char *type = object_get_typename(OBJECT(xendev));
+
+ if (xendev->frontend_state == state) {
+ return;
+ }
+
+ trace_xen_device_frontend_state(type, xendev->name,
+ xs_strstate(state));
+
+ xendev->frontend_state = state;
+ xen_device_frontend_printf(xendev, "state", "%u", state);
+}
+
+static void xen_device_frontend_changed(void *opaque)
+{
+ XenDevice *xendev = opaque;
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(xendev));
+ enum xenbus_state state;
+
+ trace_xen_device_frontend_changed(type, xendev->name);
+
+ if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
+ state = XenbusStateUnknown;
+ }
+
+ xen_device_frontend_set_state(xendev, state);
+
+ if (xendev_class->frontend_changed) {
+ Error *local_err = NULL;
+
+ xendev_class->frontend_changed(xendev, state, &local_err);
+
+ if (local_err) {
+ error_reportf_err(local_err, "frontend change error: ");
+ }
+ }
+}
+
+static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ struct xs_permissions perms[2];
+ Error *local_err = NULL;
+
+ xendev->frontend_path = xen_device_get_frontend_path(xendev);
+
+ perms[0].id = xendev->frontend_id;
+ perms[0].perms = XS_PERM_NONE;
+ perms[1].id = xenbus->backend_id;
+ perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
+
+ g_assert(xenbus->xsh);
+
+ xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
+ ARRAY_SIZE(perms), &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to create frontend: ");
+ return;
+ }
+
+ xendev->frontend_state_watch =
+ xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
+ xen_device_frontend_changed, xendev, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to watch frontend state: ");
+ }
+}
+
+static void xen_device_frontend_destroy(XenDevice *xendev)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ Error *local_err = NULL;
+
+ if (xendev->frontend_state_watch) {
+ xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
+ xendev->frontend_state_watch = NULL;
+ }
+
+ if (!xendev->frontend_path) {
+ return;
+ }
+
+ g_assert(xenbus->xsh);
+
+ xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
+ &local_err);
+ g_free(xendev->frontend_path);
+ xendev->frontend_path = NULL;
+
+ if (local_err) {
+ error_report_err(local_err);
+ }
+}
+
+void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
+ Error **errp)
+{
+ if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
+ error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
+ }
+}
+
+void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
+ unsigned int nr_refs, int prot,
+ Error **errp)
+{
+ void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
+ xendev->frontend_id, refs,
+ prot);
+
+ if (!map) {
+ error_setg_errno(errp, errno,
+ "xengnttab_map_domain_grant_refs failed");
+ }
+
+ return map;
+}
+
+void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
+ unsigned int nr_refs, Error **errp)
+{
+ if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
+ error_setg_errno(errp, errno, "xengnttab_unmap failed");
+ }
+}
+
+static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
+ XenDeviceGrantCopySegment segs[],
+ unsigned int nr_segs, Error **errp)
+{
+ uint32_t *refs = g_new(uint32_t, nr_segs);
+ int prot = to_domain ? PROT_WRITE : PROT_READ;
+ void *map;
+ unsigned int i;
+
+ for (i = 0; i < nr_segs; i++) {
+ XenDeviceGrantCopySegment *seg = &segs[i];
+
+ refs[i] = to_domain ? seg->dest.foreign.ref :
+ seg->source.foreign.ref;
+ }
+
+ map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
+ xendev->frontend_id, refs,
+ prot);
+ if (!map) {
+ error_setg_errno(errp, errno,
+ "xengnttab_map_domain_grant_refs failed");
+ goto done;
+ }
+
+ for (i = 0; i < nr_segs; i++) {
+ XenDeviceGrantCopySegment *seg = &segs[i];
+ void *page = map + (i * XC_PAGE_SIZE);
+
+ if (to_domain) {
+ memcpy(page + seg->dest.foreign.offset, seg->source.virt,
+ seg->len);
+ } else {
+ memcpy(seg->dest.virt, page + seg->source.foreign.offset,
+ seg->len);
+ }
+ }
+
+ if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
+ error_setg_errno(errp, errno, "xengnttab_unmap failed");
+ }
+
+done:
+ g_free(refs);
+}
+
+void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
+ XenDeviceGrantCopySegment segs[],
+ unsigned int nr_segs, Error **errp)
+{
+ xengnttab_grant_copy_segment_t *xengnttab_segs;
+ unsigned int i;
+
+ if (!xendev->feature_grant_copy) {
+ compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
+ return;
+ }
+
+ xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
+
+ for (i = 0; i < nr_segs; i++) {
+ XenDeviceGrantCopySegment *seg = &segs[i];
+ xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
+
+ if (to_domain) {
+ xengnttab_seg->flags = GNTCOPY_dest_gref;
+ xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
+ xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
+ xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
+ xengnttab_seg->source.virt = seg->source.virt;
+ } else {
+ xengnttab_seg->flags = GNTCOPY_source_gref;
+ xengnttab_seg->source.foreign.domid = xendev->frontend_id;
+ xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
+ xengnttab_seg->source.foreign.offset =
+ seg->source.foreign.offset;
+ xengnttab_seg->dest.virt = seg->dest.virt;
+ }
+
+ xengnttab_seg->len = seg->len;
+ }
+
+ if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
+ error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
+ goto done;
+ }
+
+ for (i = 0; i < nr_segs; i++) {
+ xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
+
+ if (xengnttab_seg->status != GNTST_okay) {
+ error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
+ break;
+ }
+ }
+
+done:
+ g_free(xengnttab_segs);
+}
+
+struct XenEventChannel {
+ evtchn_port_t local_port;
+ XenEventHandler handler;
+ void *opaque;
+ Notifier notifier;
+};
+
+static void event_notify(Notifier *n, void *data)
+{
+ XenEventChannel *channel = container_of(n, XenEventChannel, notifier);
+ unsigned long port = (unsigned long)data;
+
+ if (port == channel->local_port) {
+ channel->handler(channel->opaque);
+ }
+}
+
+XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
+ unsigned int port,
+ XenEventHandler handler,
+ void *opaque, Error **errp)
+{
+ XenEventChannel *channel = g_new0(XenEventChannel, 1);
+ xenevtchn_port_or_error_t local_port;
+
+ local_port = xenevtchn_bind_interdomain(xendev->xeh,
+ xendev->frontend_id,
+ port);
+ if (local_port < 0) {
+ error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
+
+ g_free(channel);
+ return NULL;
+ }
+
+ channel->local_port = local_port;
+ channel->handler = handler;
+ channel->opaque = opaque;
+ channel->notifier.notify = event_notify;
+
+ notifier_list_add(&xendev->event_notifiers, &channel->notifier);
+
+ return channel;
+}
+
+void xen_device_notify_event_channel(XenDevice *xendev,
+ XenEventChannel *channel,
+ Error **errp)
+{
+ if (!channel) {
+ error_setg(errp, "bad channel");
+ return;
+ }
+
+ if (xenevtchn_notify(xendev->xeh, channel->local_port) < 0) {
+ error_setg_errno(errp, errno, "xenevtchn_notify failed");
+ }
+}
+
+void xen_device_unbind_event_channel(XenDevice *xendev,
+ XenEventChannel *channel,
+ Error **errp)
+{
+ if (!channel) {
+ error_setg(errp, "bad channel");
+ return;
+ }
+
+ notifier_remove(&channel->notifier);
+
+ if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
+ error_setg_errno(errp, errno, "xenevtchn_unbind failed");
+ }
+
+ g_free(channel);
+}
+
+static void xen_device_unrealize(DeviceState *dev, Error **errp)
+{
+ XenDevice *xendev = XEN_DEVICE(dev);
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
+ const char *type = object_get_typename(OBJECT(xendev));
+
+ if (!xendev->name) {
+ return;
+ }
+
+ trace_xen_device_unrealize(type, xendev->name);
+
+ if (xendev->exit.notify) {
+ qemu_remove_exit_notifier(&xendev->exit);
+ xendev->exit.notify = NULL;
+ }
+
+ if (xendev_class->unrealize) {
+ xendev_class->unrealize(xendev, errp);
+ }
+
+ xen_device_frontend_destroy(xendev);
+ xen_device_backend_destroy(xendev);
+
+ if (xendev->xeh) {
+ qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), NULL, NULL, NULL);
+ xenevtchn_close(xendev->xeh);
+ xendev->xeh = NULL;
+ }
+
+ if (xendev->xgth) {
+ xengnttab_close(xendev->xgth);
+ xendev->xgth = NULL;
+ }
+
+ g_free(xendev->name);
+ xendev->name = NULL;
+}
+
+static void xen_device_exit(Notifier *n, void *data)
+{
+ XenDevice *xendev = container_of(n, XenDevice, exit);
+
+ xen_device_unrealize(DEVICE(xendev), &error_abort);
+}
+
+static void xen_device_event(void *opaque)
+{
+ XenDevice *xendev = opaque;
+ unsigned long port = xenevtchn_pending(xendev->xeh);
+
+ notifier_list_notify(&xendev->event_notifiers, (void *)port);
+
+ xenevtchn_unmask(xendev->xeh, port);
+}
+
+static void xen_device_realize(DeviceState *dev, Error **errp)
+{
+ XenDevice *xendev = XEN_DEVICE(dev);
+ XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+ const char *type = object_get_typename(OBJECT(xendev));
+ Error *local_err = NULL;
+
+ if (xendev->frontend_id == DOMID_INVALID) {
+ xendev->frontend_id = xen_domid;
+ }
+
+ if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
+ error_setg(errp, "invalid frontend-id");
+ goto unrealize;
+ }
+
+ if (!xendev_class->get_name) {
+ error_setg(errp, "get_name method not implemented");
+ goto unrealize;
+ }
+
+ xendev->name = xendev_class->get_name(xendev, &local_err);
+ if (local_err) {
+ error_propagate_prepend(errp, local_err,
+ "failed to get device name: ");
+ goto unrealize;
+ }
+
+ trace_xen_device_realize(type, xendev->name);
+
+ xendev->xgth = xengnttab_open(NULL, 0);
+ if (!xendev->xgth) {
+ error_setg_errno(errp, errno, "failed xengnttab_open");
+ goto unrealize;
+ }
+
+ xendev->feature_grant_copy =
+ (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
+
+ xendev->xeh = xenevtchn_open(NULL, 0);
+ if (!xendev->xeh) {
+ error_setg_errno(errp, errno, "failed xenevtchn_open");
+ goto unrealize;
+ }
+
+ notifier_list_init(&xendev->event_notifiers);
+ qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), xen_device_event, NULL,
+ xendev);
+
+ xen_device_backend_create(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto unrealize;
+ }
+
+ xen_device_frontend_create(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto unrealize;
+ }
+
+ if (xendev_class->realize) {
+ xendev_class->realize(xendev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto unrealize;
+ }
+ }
+
+ xen_device_backend_printf(xendev, "frontend", "%s",
+ xendev->frontend_path);
+ xen_device_backend_printf(xendev, "frontend-id", "%u",
+ xendev->frontend_id);
+ xen_device_backend_printf(xendev, "hotplug-status", "connected");
+
+ xen_device_backend_set_online(xendev, true);
+ xen_device_backend_set_state(xendev, XenbusStateInitWait);
+
+ xen_device_frontend_printf(xendev, "backend", "%s",
+ xendev->backend_path);
+ xen_device_frontend_printf(xendev, "backend-id", "%u",
+ xenbus->backend_id);
+
+ xen_device_frontend_set_state(xendev, XenbusStateInitialising);
+
+ xendev->exit.notify = xen_device_exit;
+ qemu_add_exit_notifier(&xendev->exit);
+ return;
+
+unrealize:
+ xen_device_unrealize(dev, &error_abort);
+}
+
+static Property xen_device_props[] = {
+ DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
+ DOMID_INVALID),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void xen_device_class_init(ObjectClass *class, void *data)
+{
+ DeviceClass *dev_class = DEVICE_CLASS(class);
+
+ dev_class->realize = xen_device_realize;
+ dev_class->unrealize = xen_device_unrealize;
+ dev_class->props = xen_device_props;
+ dev_class->bus_type = TYPE_XEN_BUS;
+}
+
+static const TypeInfo xen_device_type_info = {
+ .name = TYPE_XEN_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(XenDevice),
+ .abstract = true,
+ .class_size = sizeof(XenDeviceClass),
+ .class_init = xen_device_class_init,
+};
+
+typedef struct XenBridge {
+ SysBusDevice busdev;
+} XenBridge;
+
+#define TYPE_XEN_BRIDGE "xen-bridge"
+
+static const TypeInfo xen_bridge_type_info = {
+ .name = TYPE_XEN_BRIDGE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XenBridge),
+};
+
+static void xen_register_types(void)
+{
+ type_register_static(&xen_bridge_type_info);
+ type_register_static(&xen_bus_type_info);
+ type_register_static(&xen_device_type_info);
+}
+
+type_init(xen_register_types)
+
+void xen_bus_init(void)
+{
+ DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
+ BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
+
+ qdev_init_nofail(dev);
+ qbus_set_bus_hotplug_handler(bus, &error_abort);
+}
diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c
index 6ec14c73ca..0e9e58f04d 100644
--- a/hw/xen/xen-common.c
+++ b/hw/xen/xen-common.c
@@ -10,7 +10,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "chardev/char.h"
#include "sysemu/accel.h"
#include "migration/misc.h"
@@ -159,33 +159,22 @@ static int xen_init(MachineState *ms)
return 0;
}
-static GlobalProperty xen_compat_props[] = {
- {
- .driver = "migration",
- .property = "store-global-state",
- .value = "off",
- },
- {
- .driver = "migration",
- .property = "send-configuration",
- .value = "off",
- },
- {
- .driver = "migration",
- .property = "send-section-footer",
- .value = "off",
- },
- { /* end of list */ },
-};
-
static void xen_accel_class_init(ObjectClass *oc, void *data)
{
AccelClass *ac = ACCEL_CLASS(oc);
+ static GlobalProperty compat[] = {
+ { "migration", "store-global-state", "off" },
+ { "migration", "send-configuration", "off" },
+ { "migration", "send-section-footer", "off" },
+ };
+
ac->name = "Xen";
ac->init_machine = xen_init;
ac->setup_post = xen_setup_post;
ac->allowed = &xen_allowed;
- ac->global_props = xen_compat_props;
+ ac->compat_props = g_ptr_array_new();
+
+ compat_props_add(ac->compat_props, compat, G_N_ELEMENTS(compat));
}
#define TYPE_XEN_ACCEL ACCEL_CLASS_NAME("xen")
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen-legacy-backend.c
index 9a8e8771ec..36fd1e9b09 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -30,7 +30,7 @@
#include "hw/boards.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pvdev.h"
#include "monitor/qdev.h"
@@ -42,49 +42,54 @@ BusState *xen_sysbus;
/* ------------------------------------------------------------- */
/* public */
-struct xs_handle *xenstore = NULL;
+struct xs_handle *xenstore;
const char *xen_protocol;
/* private */
static bool xen_feature_grant_copy;
static int debug;
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
+ const char *val)
{
return xenstore_write_str(xendev->be, node, val);
}
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
+ int ival)
{
return xenstore_write_int(xendev->be, node, ival);
}
-int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
+int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
+ int64_t ival)
{
return xenstore_write_int64(xendev->be, node, ival);
}
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node)
{
return xenstore_read_str(xendev->be, node);
}
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
+ int *ival)
{
return xenstore_read_int(xendev->be, node, ival);
}
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node)
{
return xenstore_read_str(xendev->fe, node);
}
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
+int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
+ int *ival)
{
return xenstore_read_int(xendev->fe, node, ival);
}
-int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
+int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
uint64_t *uval)
{
return xenstore_read_uint64(xendev->fe, node, uval);
@@ -92,7 +97,7 @@ int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
/* ------------------------------------------------------------- */
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
+int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state)
{
int rc;
@@ -106,7 +111,7 @@ int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
return 0;
}
-void xen_be_set_max_grant_refs(struct XenDevice *xendev,
+void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
@@ -117,7 +122,7 @@ void xen_be_set_max_grant_refs(struct XenDevice *xendev,
}
}
-void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
+void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot)
{
void *ptr;
@@ -135,7 +140,7 @@ void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
return ptr;
}
-void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
+void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
unsigned int nr_refs)
{
assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
@@ -146,7 +151,7 @@ void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
}
}
-static int compat_copy_grant_refs(struct XenDevice *xendev,
+static int compat_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain,
XenGrantCopySegment segs[],
unsigned int nr_segs)
@@ -195,7 +200,7 @@ static int compat_copy_grant_refs(struct XenDevice *xendev,
return 0;
}
-int xen_be_copy_grant_refs(struct XenDevice *xendev,
+int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain,
XenGrantCopySegment segs[],
unsigned int nr_segs)
@@ -259,10 +264,11 @@ int xen_be_copy_grant_refs(struct XenDevice *xendev,
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
- struct XenDevOps *ops)
+static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
+ int dev,
+ struct XenDevOps *ops)
{
- struct XenDevice *xendev;
+ struct XenLegacyDevice *xendev;
xendev = xen_pv_find_xendev(type, dom, dev);
if (xendev) {
@@ -314,7 +320,8 @@ static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
* Node specifies the changed field. node = NULL means
* update all fields (used for initialization).
*/
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+static void xen_be_backend_changed(struct XenLegacyDevice *xendev,
+ const char *node)
{
if (node == NULL || strcmp(node, "online") == 0) {
if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
@@ -330,7 +337,8 @@ static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
}
}
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+static void xen_be_frontend_changed(struct XenLegacyDevice *xendev,
+ const char *node)
{
int fe_state;
@@ -373,7 +381,7 @@ static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
* only affects the xendev->be_state variable as xenbus should
* already be put into that state by xend.
*/
-static int xen_be_try_setup(struct XenDevice *xendev)
+static int xen_be_try_setup(struct XenLegacyDevice *xendev)
{
char token[XEN_BUFSIZE];
int be_state;
@@ -417,7 +425,7 @@ static int xen_be_try_setup(struct XenDevice *xendev)
*
* Goes to InitWait on success.
*/
-static int xen_be_try_init(struct XenDevice *xendev)
+static int xen_be_try_init(struct XenLegacyDevice *xendev)
{
int rc = 0;
@@ -446,7 +454,7 @@ static int xen_be_try_init(struct XenDevice *xendev)
*
* Goes to Connected on success.
*/
-static int xen_be_try_initialise(struct XenDevice *xendev)
+static int xen_be_try_initialise(struct XenLegacyDevice *xendev)
{
int rc = 0;
@@ -487,7 +495,7 @@ static int xen_be_try_initialise(struct XenDevice *xendev)
* frontend being Connected. Note that this may be called more
* than once since the backend state is not modified.
*/
-static void xen_be_try_connected(struct XenDevice *xendev)
+static void xen_be_try_connected(struct XenLegacyDevice *xendev)
{
if (!xendev->ops->connected) {
return;
@@ -510,7 +518,8 @@ static void xen_be_try_connected(struct XenDevice *xendev)
*
* Goes to Closed when done.
*/
-static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+static void xen_be_disconnect(struct XenLegacyDevice *xendev,
+ enum xenbus_state state)
{
if (xendev->be_state != XenbusStateClosing &&
xendev->be_state != XenbusStateClosed &&
@@ -529,7 +538,7 @@ static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
/*
* Try to reset xendev, for reconnection by another frontend instance.
*/
-static int xen_be_try_reset(struct XenDevice *xendev)
+static int xen_be_try_reset(struct XenLegacyDevice *xendev)
{
if (xendev->fe_state != XenbusStateInitialising) {
return -1;
@@ -543,7 +552,7 @@ static int xen_be_try_reset(struct XenDevice *xendev)
/*
* state change dispatcher function
*/
-void xen_be_check_state(struct XenDevice *xendev)
+void xen_be_check_state(struct XenLegacyDevice *xendev)
{
int rc = 0;
@@ -587,7 +596,7 @@ void xen_be_check_state(struct XenDevice *xendev)
static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
{
- struct XenDevice *xendev;
+ struct XenLegacyDevice *xendev;
char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
char **dev = NULL;
unsigned int cdev, j;
@@ -620,7 +629,7 @@ static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops)
{
- struct XenDevice *xendev;
+ struct XenLegacyDevice *xendev;
char path[XEN_BUFSIZE], *bepath;
unsigned int len, dev;
@@ -628,9 +637,9 @@ void xenstore_update_be(char *watch, char *type, int dom,
if (strncmp(path, watch, len) != 0) {
return;
}
- if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+ if (sscanf(watch + len, "/%u/%255s", &dev, path) != 2) {
strcpy(path, "");
- if (sscanf(watch+len, "/%u", &dev) != 1) {
+ if (sscanf(watch + len, "/%u", &dev) != 1) {
dev = -1;
}
}
@@ -651,7 +660,7 @@ void xenstore_update_be(char *watch, char *type, int dom,
}
}
-void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev)
{
char *node;
unsigned int len;
@@ -744,7 +753,6 @@ void xen_be_register_common(void)
xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
- xen_be_register("qdisk", &xen_blkdev_ops);
#ifdef CONFIG_VIRTFS
xen_be_register("9pfs", &xen_9pfs_ops);
#endif
@@ -753,7 +761,7 @@ void xen_be_register_common(void)
#endif
}
-int xen_be_bind_evtchn(struct XenDevice *xendev)
+int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
{
if (xendev->local_port != -1) {
return 0;
@@ -789,7 +797,7 @@ static const TypeInfo xendev_type_info = {
.name = TYPE_XENBACKEND,
.parent = TYPE_XENSYSDEV,
.class_init = xendev_class_init,
- .instance_size = sizeof(struct XenDevice),
+ .instance_size = sizeof(struct XenLegacyDevice),
};
static void xen_sysbus_class_init(ObjectClass *klass, void *data)
@@ -809,11 +817,6 @@ static const TypeInfo xensysbus_info = {
}
};
-static int xen_sysdev_init(SysBusDevice *dev)
-{
- return 0;
-}
-
static Property xen_sysdev_properties[] = {
{/* end of property list */},
};
@@ -821,9 +824,7 @@ static Property xen_sysdev_properties[] = {
static void xen_sysdev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = xen_sysdev_init;
dc->props = xen_sysdev_properties;
dc->bus_type = TYPE_XENSYSBUS;
}
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index aebc19bd71..315dbc9c51 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -1,12 +1,12 @@
#include "qemu/osdep.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "qemu/option.h"
#include "sysemu/blockdev.h"
/* ------------------------------------------------------------- */
static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
- char *fe, char *be, int len)
+ char *fe, char *be, int len)
{
char *dom;
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index f1f3a3727c..5539d56c3a 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -59,7 +59,7 @@
#include "hw/pci/pci.h"
#include "hw/xen/xen.h"
#include "hw/i386/pc.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "qemu/range.h"
#include "exec/address-spaces.h"
@@ -847,6 +847,12 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
}
machine_irq = s->real_device.irq;
+ if (machine_irq == 0) {
+ XEN_PT_LOG(d, "machine irq is 0\n");
+ cmd |= PCI_COMMAND_INTX_DISABLE;
+ goto out;
+ }
+
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
if (rc < 0) {
error_setg_errno(errp, errno, "Mapping machine irq %u to"
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 47f9010c75..31ec5add1d 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -15,7 +15,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/timer.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
@@ -300,7 +300,9 @@ static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
XenPTRegInfo *reg, uint32_t real_offset,
uint32_t *data)
{
- *data = xen_pt_pci_read_intx(s);
+ if (s->real_device.irq) {
+ *data = xen_pt_pci_read_intx(s);
+ }
return 0;
}
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 135c8df1e7..b69732729b 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -5,7 +5,7 @@
#include "qapi/error.h"
#include "xen_pt.h"
#include "xen-host-pci-device.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
static unsigned long igd_guest_opregion;
static unsigned long igd_host_opregion;
@@ -185,8 +185,19 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
return;
}
+ if (bios_size < sizeof(struct rom_header)) {
+ error_setg(errp, "VGA: VBIOS image corrupt (too small)");
+ return;
+ }
+
/* Currently we fixed this address as a primary. */
rom = (struct rom_header *)bios;
+
+ if (rom->pcioffset + sizeof(struct pci_data) > bios_size) {
+ error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)");
+ return;
+ }
+
pd = (void *)(bios + (unsigned char)rom->pcioffset);
/* We may need to fixup Device Identification. */
@@ -194,6 +205,11 @@ void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
pd->device = s->real_device.device_id;
len = rom->size * 512;
+ if (len > bios_size) {
+ error_setg(errp, "VGA: VBIOS image corrupt (bad size field)");
+ return;
+ }
+
/* Then adjust the bios checksum */
for (c = (char *)bios; c < ((char *)bios + len); c++) {
checksum += *c;
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
index cc514f9157..fb4b887b92 100644
--- a/hw/xen/xen_pt_msi.c
+++ b/hw/xen/xen_pt_msi.c
@@ -11,7 +11,7 @@
#include "qemu/osdep.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "xen_pt.h"
#include "hw/i386/apic-msidef.h"
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
index aed783e844..6ef09cbf9d 100644
--- a/hw/xen/xen_pvdev.c
+++ b/hw/xen/xen_pvdev.c
@@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/qdev-core.h"
-#include "hw/xen/xen_backend.h"
+#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pvdev.h"
/* private */
@@ -31,10 +31,10 @@ struct xs_dirs {
QTAILQ_ENTRY(xs_dirs) list;
};
-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
+static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
QTAILQ_HEAD_INITIALIZER(xs_cleanup);
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
+static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
QTAILQ_HEAD_INITIALIZER(xendevs);
/* ------------------------------------------------------------- */
@@ -195,7 +195,7 @@ const char *xenbus_strstate(enum xenbus_state state)
* 2 == noisy debug messages (logfile only).
* 3 == will flood your log (logfile only).
*/
-void xen_pv_printf(struct XenDevice *xendev, int msg_level,
+void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
const char *fmt, ...)
{
va_list args;
@@ -230,7 +230,7 @@ void xen_pv_printf(struct XenDevice *xendev, int msg_level,
void xen_pv_evtchn_event(void *opaque)
{
- struct XenDevice *xendev = opaque;
+ struct XenLegacyDevice *xendev = opaque;
evtchn_port_t port;
port = xenevtchn_pending(xendev->evtchndev);
@@ -247,7 +247,7 @@ void xen_pv_evtchn_event(void *opaque)
}
}
-void xen_pv_unbind_evtchn(struct XenDevice *xendev)
+void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
{
if (xendev->local_port == -1) {
return;
@@ -258,16 +258,16 @@ void xen_pv_unbind_evtchn(struct XenDevice *xendev)
xendev->local_port = -1;
}
-int xen_pv_send_notify(struct XenDevice *xendev)
+int xen_pv_send_notify(struct XenLegacyDevice *xendev)
{
return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
}
/* ------------------------------------------------------------- */
-struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
+struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
{
- struct XenDevice *xendev;
+ struct XenLegacyDevice *xendev;
QTAILQ_FOREACH(xendev, &xendevs, next) {
if (xendev->dom != dom) {
@@ -287,7 +287,7 @@ struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
/*
* release xen backend device.
*/
-void xen_pv_del_xendev(struct XenDevice *xendev)
+void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
{
if (xendev->ops->free) {
xendev->ops->free(xendev);
@@ -312,7 +312,7 @@ void xen_pv_del_xendev(struct XenDevice *xendev)
qdev_unplug(&xendev->qdev, NULL);
}
-void xen_pv_insert_xendev(struct XenDevice *xendev)
+void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
{
QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
}
diff --git a/hw/xenpv/Makefile.objs b/hw/xenpv/Makefile.objs
index bbf5873fd1..8bfa4586ab 100644
--- a/hw/xenpv/Makefile.objs
+++ b/hw/xenpv/Makefile.objs
@@ -1,4 +1,2 @@
# Xen PV machine support
obj-$(CONFIG_XEN) += xen_machine_pv.o
-# Xen PV machine builder support
-obj-$(CONFIG_XEN_PV_DOMAIN_BUILD) += xen_domainbuild.o
diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c
deleted file mode 100644
index 188acaca16..0000000000
--- a/hw/xenpv/xen_domainbuild.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_domainbuild.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-
-#include <xenguest.h>
-
-static int xenstore_domain_mkdir(char *path)
-{
- struct xs_permissions perms_ro[] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = XS_PERM_READ,
- }};
- struct xs_permissions perms_rw[] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = XS_PERM_READ | XS_PERM_WRITE,
- }};
- const char *writable[] = { "device", "control", "error", NULL };
- char subpath[256];
- int i;
-
- if (!xs_mkdir(xenstore, 0, path)) {
- fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, path);
- return -1;
- }
- if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
- fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
- return -1;
- }
-
- for (i = 0; writable[i]; i++) {
- snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
- if (!xs_mkdir(xenstore, 0, subpath)) {
- fprintf(stderr, "%s: xs_mkdir %s: failed\n", __func__, subpath);
- return -1;
- }
- if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
- fprintf(stderr, "%s: xs_set_permissions failed\n", __func__);
- return -1;
- }
- }
- return 0;
-}
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
- const char *cmdline)
-{
- char *dom, uuid_string[42], vm[256], path[256];
- int i;
-
- qemu_uuid_unparse(&qemu_uuid, uuid_string);
- dom = xs_get_domain_path(xenstore, xen_domid);
- snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
-
- xenstore_domain_mkdir(dom);
-
- xenstore_write_str(vm, "image/ostype", "linux");
- if (kernel)
- xenstore_write_str(vm, "image/kernel", kernel);
- if (ramdisk)
- xenstore_write_str(vm, "image/ramdisk", ramdisk);
- if (cmdline)
- xenstore_write_str(vm, "image/cmdline", cmdline);
-
- /* name + id */
- xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
- xenstore_write_str(vm, "uuid", uuid_string);
- xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
- xenstore_write_int(dom, "domid", xen_domid);
- xenstore_write_str(dom, "vm", vm);
-
- /* memory */
- xenstore_write_int(dom, "memory/target", ram_size / KiB);
- xenstore_write_int(vm, "memory", ram_size / MiB);
- xenstore_write_int(vm, "maxmem", ram_size / MiB);
-
- /* cpus */
- for (i = 0; i < smp_cpus; i++) {
- snprintf(path, sizeof(path), "cpu/%d/availability",i);
- xenstore_write_str(dom, path, "online");
- }
- xenstore_write_int(vm, "vcpu_avail", smp_cpus);
- xenstore_write_int(vm, "vcpus", smp_cpus);
-
- /* vnc password */
- xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
-
- free(dom);
- return 0;
-}
-
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
- int console_port, int console_mfn)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
-
- /* signal new domain */
- xs_introduce_domain(xenstore,
- xen_domid,
- xenstore_mfn,
- xenstore_port);
-
- /* xenstore */
- xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
- xenstore_write_int(dom, "store/port", xenstore_port);
-
- /* console */
- xenstore_write_str(dom, "console/type", "ioemu");
- xenstore_write_int(dom, "console/limit", 128 * KiB);
- xenstore_write_int(dom, "console/ring-ref", console_mfn);
- xenstore_write_int(dom, "console/port", console_port);
- xen_config_dev_console(0);
-
- free(dom);
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-static QEMUTimer *xen_poll;
-
-/* check domain state once per second */
-static void xen_domain_poll(void *opaque)
-{
- struct xc_dominfo info;
- int rc;
-
- rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
- if ((rc != 1) || (info.domid != xen_domid)) {
- qemu_log("xen: domain %d is gone\n", xen_domid);
- goto quit;
- }
- if (info.dying) {
- qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
- info.crashed ? "crashed" : "",
- info.shutdown ? "shutdown" : "");
- goto quit;
- }
-
- timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
- return;
-
-quit:
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
-}
-
-static int xen_domain_watcher(void)
-{
- int qemu_running = 1;
- int fd[2], i, n, rc;
- char byte;
-
- if (pipe(fd) != 0) {
- qemu_log("%s: Huh? pipe error: %s\n", __func__, strerror(errno));
- return -1;
- }
- if (fork() != 0)
- return 0; /* not child */
-
- /* close all file handles, except stdio/out/err,
- * our watch pipe and the xen interface handle */
- n = getdtablesize();
- for (i = 3; i < n; i++) {
- if (i == fd[0])
- continue;
- close(i);
- }
-
- /*
- * Reopen xc interface, since the original is unsafe after fork
- * and was closed above.
- */
- xen_xc = xc_interface_open(0, 0, 0);
-
- /* ignore term signals */
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
-
- /* wait for qemu exiting */
- while (qemu_running) {
- rc = read(fd[0], &byte, 1);
- switch (rc) {
- case -1:
- if (errno == EINTR)
- continue;
- qemu_log("%s: Huh? read error: %s\n", __func__, strerror(errno));
- qemu_running = 0;
- break;
- case 0:
- /* EOF -> qemu exited */
- qemu_running = 0;
- break;
- default:
- qemu_log("%s: Huh? data on the watch pipe?\n", __func__);
- break;
- }
- }
-
- /* cleanup */
- qemu_log("%s: destroy domain %d\n", __func__, xen_domid);
- xc_domain_destroy(xen_xc, xen_domid);
- _exit(0);
-}
-
-/* normal cleanup */
-static void xen_domain_cleanup(void)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
- if (dom) {
- xs_rm(xenstore, 0, dom);
- free(dom);
- }
- xs_release_domain(xenstore, xen_domid);
-}
-
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
- const char *cmdline)
-{
- uint32_t ssidref = 0;
- uint32_t flags = 0;
- xen_domain_handle_t uuid;
- unsigned int xenstore_port = 0, console_port = 0;
- unsigned long xenstore_mfn = 0, console_mfn = 0;
- int rc;
-
- memcpy(uuid, &qemu_uuid, sizeof(uuid));
- rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_create() failed\n");
- goto err;
- }
- qemu_log("xen: created domain %d\n", xen_domid);
- atexit(xen_domain_cleanup);
- if (xen_domain_watcher() == -1) {
- goto err;
- }
-
- xenstore_domain_init1(kernel, ramdisk, cmdline);
-
- rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
- goto err;
- }
-
-#if 0
- rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
- goto err;
- }
-#endif
-
- rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size / KiB);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
- goto err;
- }
-
- xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
- console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
-
- rc = xc_linux_build(xen_xc, xen_domid, ram_size / MiB,
- kernel, ramdisk, cmdline,
- 0, flags,
- xenstore_port, &xenstore_mfn,
- console_port, &console_mfn);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_linux_build() failed\n");
- goto err;
- }
-
- xenstore_domain_init2(xenstore_port, xenstore_mfn,
- console_port, console_mfn);
-
- qemu_log("xen: unpausing domain %d\n", xen_domid);
- rc = xc_domain_unpause(xen_xc, xen_domid);
- if (rc < 0) {
- fprintf(stderr, "xen: xc_domain_unpause() failed\n");
- goto err;
- }
-
- xen_poll = timer_new_ms(QEMU_CLOCK_REALTIME, xen_domain_poll, NULL);
- timer_mod(xen_poll, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
- return 0;
-
-err:
- return -1;
-}
diff --git a/hw/xenpv/xen_domainbuild.h b/hw/xenpv/xen_domainbuild.h
deleted file mode 100644
index 652d9b410f..0000000000
--- a/hw/xenpv/xen_domainbuild.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef QEMU_HW_XEN_DOMAINBUILD_H
-#define QEMU_HW_XEN_DOMAINBUILD_H
-
-#include "hw/xen/xen_common.h"
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
- const char *cmdline);
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
- int console_port, int console_mfn);
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
- const char *cmdline);
-
-#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index 44d67b87c4..dcaf2a01a3 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -26,8 +26,8 @@
#include "qemu/error-report.h"
#include "hw/hw.h"
#include "hw/boards.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_domainbuild.h"
+#include "hw/xen/xen-legacy-backend.h"
+#include "hw/xen/xen-bus.h"
#include "sysemu/block-backend.h"
static void xen_init_pv(MachineState *machine)
@@ -43,21 +43,8 @@ static void xen_init_pv(MachineState *machine)
switch (xen_mode) {
case XEN_ATTACH:
- /* nothing to do, xend handles everything */
+ /* nothing to do, libxl handles everything */
break;
-#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
- case XEN_CREATE: {
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- if (xen_domain_build_pv(kernel_filename, initrd_filename,
- kernel_cmdline) < 0) {
- error_report("xen pv domain creation failed");
- exit(1);
- }
- break;
- }
-#endif
case XEN_EMULATE:
error_report("xen emulation not implemented (yet)");
exit(1);
@@ -93,6 +80,8 @@ static void xen_init_pv(MachineState *machine)
xen_config_dev_nic(nd_table + i);
}
+ xen_bus_init();
+
/* config cleanup hook */
atexit(xen_config_cleanup);
}
diff --git a/include/block/block.h b/include/block/block.h
index 7f5453b45b..f70a843b72 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -299,10 +299,10 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
int flags, Error **errp);
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
- BlockDriverState *bs,
- QDict *options, int flags);
+ BlockDriverState *bs, QDict *options);
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp);
-int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp);
+int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
+ Error **errp);
int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
BlockReopenQueue *queue, Error **errp);
void bdrv_reopen_commit(BDRVReopenState *reopen_state);
diff --git a/include/block/block_backup.h b/include/block/block_backup.h
index 994a3bd2ec..157596c296 100644
--- a/include/block/block_backup.h
+++ b/include/block/block_backup.h
@@ -20,19 +20,6 @@
#include "block/block_int.h"
-typedef struct CowRequest {
- int64_t start_byte;
- int64_t end_byte;
- QLIST_ENTRY(CowRequest) list;
- CoQueue wait_queue; /* coroutines blocked on this request */
-} CowRequest;
-
-void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset,
- uint64_t bytes);
-void backup_cow_request_begin(CowRequest *req, BlockJob *job,
- int64_t offset, uint64_t bytes);
-void backup_cow_request_end(CowRequest *req);
-
void backup_do_checkpoint(BlockJob *job, Error **errp);
#endif
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 8f38a3dec1..04a117fc81 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -83,8 +83,6 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t offset, int64_t bytes);
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
-bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
- uint64_t *offset, int *bytes);
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
@@ -99,7 +97,10 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap);
char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp);
-int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t start);
+int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset,
+ uint64_t bytes);
+bool bdrv_dirty_bitmap_next_dirty_area(BdrvDirtyBitmap *bitmap,
+ uint64_t *offset, uint64_t *bytes);
BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap,
Error **errp);
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 6a5bfe5d55..4faf394e34 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2017 Red Hat, Inc.
+ * Copyright (C) 2016-2019 Red Hat, Inc.
* Copyright (C) 2005 Anthony Liguori <anthony@codemonkey.ws>
*
* Network Block Device
@@ -263,26 +263,39 @@ struct NBDExportInfo {
bool request_sizes;
char *x_dirty_bitmap;
+ /* Set by client before nbd_receive_negotiate(), or by server results
+ * during nbd_receive_export_list() */
+ char *name; /* must be non-NULL */
+
/* In-out fields, set by client before nbd_receive_negotiate() and
* updated by server results during nbd_receive_negotiate() */
bool structured_reply;
bool base_allocation; /* base:allocation context for NBD_CMD_BLOCK_STATUS */
- /* Set by server results during nbd_receive_negotiate() */
+ /* Set by server results during nbd_receive_negotiate() and
+ * nbd_receive_export_list() */
uint64_t size;
uint16_t flags;
uint32_t min_block;
uint32_t opt_block;
uint32_t max_block;
- uint32_t meta_base_allocation_id;
+ uint32_t context_id;
+
+ /* Set by server results during nbd_receive_export_list() */
+ char *description;
+ int n_contexts;
+ char **contexts;
};
typedef struct NBDExportInfo NBDExportInfo;
-int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
- QCryptoTLSCreds *tlscreds, const char *hostname,
- QIOChannel **outioc, NBDExportInfo *info,
- Error **errp);
+int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
+ const char *hostname, QIOChannel **outioc,
+ NBDExportInfo *info, Error **errp);
+void nbd_free_export_list(NBDExportInfo *info, int count);
+int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
+ const char *hostname, NBDExportInfo **info,
+ Error **errp);
int nbd_init(int fd, QIOChannelSocket *sioc, NBDExportInfo *info,
Error **errp);
int nbd_send_request(QIOChannel *ioc, NBDRequest *request);
@@ -294,10 +307,11 @@ int nbd_errno_to_system_errno(int err);
typedef struct NBDExport NBDExport;
typedef struct NBDClient NBDClient;
-NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
- uint16_t nbdflags, void (*close)(NBDExport *),
- bool writethrough, BlockBackend *on_eject_blk,
- Error **errp);
+NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
+ uint64_t size, const char *name, const char *desc,
+ const char *bitmap, uint16_t nbdflags,
+ void (*close)(NBDExport *), bool writethrough,
+ BlockBackend *on_eject_blk, Error **errp);
void nbd_export_close(NBDExport *exp);
void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp);
void nbd_export_get(NBDExport *exp);
@@ -306,8 +320,6 @@ void nbd_export_put(NBDExport *exp);
BlockBackend *nbd_export_get_blockdev(NBDExport *exp);
NBDExport *nbd_export_find(const char *name);
-void nbd_export_set_name(NBDExport *exp, const char *name);
-void nbd_export_set_description(NBDExport *exp, const char *description);
void nbd_export_close_all(void);
void nbd_client_new(QIOChannelSocket *sioc,
@@ -320,9 +332,6 @@ void nbd_client_put(NBDClient *client);
void nbd_server_start(SocketAddress *addr, const char *tls_creds,
Error **errp);
-void nbd_export_bitmap(NBDExport *exp, const char *bitmap,
- const char *bitmap_export_name, Error **errp);
-
/* nbd_read
* Reads @size bytes from @ioc. Returns 0 on success.
*/
@@ -343,5 +352,10 @@ static inline bool nbd_reply_is_structured(NBDReply *reply)
}
const char *nbd_reply_type_lookup(uint16_t type);
+const char *nbd_opt_lookup(uint32_t opt);
+const char *nbd_rep_lookup(uint32_t rep);
+const char *nbd_info_lookup(uint16_t info);
+const char *nbd_cmd_lookup(uint16_t info);
+const char *nbd_err_lookup(int err);
#endif
diff --git a/include/chardev/char.h b/include/chardev/char.h
index 7becd8c80c..014566c3de 100644
--- a/include/chardev/char.h
+++ b/include/chardev/char.h
@@ -47,6 +47,9 @@ typedef enum {
QEMU_CHAR_FEATURE_FD_PASS,
/* Whether replay or record mode is enabled */
QEMU_CHAR_FEATURE_REPLAY,
+ /* Whether the gcontext can be changed after calling
+ * qemu_chr_be_update_read_handlers() */
+ QEMU_CHAR_FEATURE_GCONTEXT,
QEMU_CHAR_FEATURE_LAST,
} ChardevFeature;
diff --git a/include/crypto/block.h b/include/crypto/block.h
index cd18f46d56..e729d5bd66 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -75,6 +75,7 @@ typedef enum {
* @readfunc: callback for reading data from the volume
* @opaque: data to pass to @readfunc
* @flags: bitmask of QCryptoBlockOpenFlags values
+ * @n_threads: allow concurrent I/O from up to @n_threads threads
* @errp: pointer to a NULL-initialized error object
*
* Create a new block encryption object for an existing
@@ -107,6 +108,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
QCryptoBlockReadFunc readfunc,
void *opaque,
unsigned int flags,
+ size_t n_threads,
Error **errp);
/**
diff --git a/include/elf.h b/include/elf.h
index c151164b63..e816fb4d76 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -782,11 +782,11 @@ typedef struct {
/* ARM-specific values for sh_flags */
#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
- in the input to a link step */
+ in the input to a link step */
/* ARM-specific program header flags */
#define PF_ARM_SB 0x10000000 /* Segment contains the location
- addressed by the static base */
+ addressed by the static base */
/* ARM relocs. */
#define R_ARM_NONE 0 /* No reloc */
@@ -1047,7 +1047,7 @@ typedef struct {
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative
- offset to GOT */
+ offset to GOT */
#define R_X86_64_32 10 /* Direct 32 bit zero extended */
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
#define R_X86_64_16 12 /* Direct 16 bit zero extended */
@@ -1070,7 +1070,7 @@ typedef struct {
#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
- prediction. */
+ prediction. */
#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
@@ -1083,7 +1083,7 @@ typedef struct {
/* Additional section indeces. */
#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
- symbols in ANSI C. */
+ symbols in ANSI C. */
#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
/* Legal values for sh_type field of Elf32_Shdr. */
@@ -1338,6 +1338,61 @@ typedef struct {
#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
+/* RISC-V relocations. */
+#define R_RISCV_NONE 0
+#define R_RISCV_32 1
+#define R_RISCV_64 2
+#define R_RISCV_RELATIVE 3
+#define R_RISCV_COPY 4
+#define R_RISCV_JUMP_SLOT 5
+#define R_RISCV_TLS_DTPMOD32 6
+#define R_RISCV_TLS_DTPMOD64 7
+#define R_RISCV_TLS_DTPREL32 8
+#define R_RISCV_TLS_DTPREL64 9
+#define R_RISCV_TLS_TPREL32 10
+#define R_RISCV_TLS_TPREL64 11
+#define R_RISCV_BRANCH 16
+#define R_RISCV_JAL 17
+#define R_RISCV_CALL 18
+#define R_RISCV_CALL_PLT 19
+#define R_RISCV_GOT_HI20 20
+#define R_RISCV_TLS_GOT_HI20 21
+#define R_RISCV_TLS_GD_HI20 22
+#define R_RISCV_PCREL_HI20 23
+#define R_RISCV_PCREL_LO12_I 24
+#define R_RISCV_PCREL_LO12_S 25
+#define R_RISCV_HI20 26
+#define R_RISCV_LO12_I 27
+#define R_RISCV_LO12_S 28
+#define R_RISCV_TPREL_HI20 29
+#define R_RISCV_TPREL_LO12_I 30
+#define R_RISCV_TPREL_LO12_S 31
+#define R_RISCV_TPREL_ADD 32
+#define R_RISCV_ADD8 33
+#define R_RISCV_ADD16 34
+#define R_RISCV_ADD32 35
+#define R_RISCV_ADD64 36
+#define R_RISCV_SUB8 37
+#define R_RISCV_SUB16 38
+#define R_RISCV_SUB32 39
+#define R_RISCV_SUB64 40
+#define R_RISCV_GNU_VTINHERIT 41
+#define R_RISCV_GNU_VTENTRY 42
+#define R_RISCV_ALIGN 43
+#define R_RISCV_RVC_BRANCH 44
+#define R_RISCV_RVC_JUMP 45
+#define R_RISCV_RVC_LUI 46
+#define R_RISCV_GPREL_I 47
+#define R_RISCV_GPREL_S 48
+#define R_RISCV_TPREL_I 49
+#define R_RISCV_TPREL_S 50
+#define R_RISCV_RELAX 51
+#define R_RISCV_SUB6 52
+#define R_RISCV_SET6 53
+#define R_RISCV_SET8 54
+#define R_RISCV_SET16 55
+#define R_RISCV_SET32 56
+
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 18b40d6145..2ad2d6d86b 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -111,8 +111,6 @@ bool cpu_physical_memory_is_io(hwaddr phys_addr);
*/
void qemu_flush_coalesced_mmio_buffer(void);
-void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
- const uint8_t *buf, int len);
void cpu_flush_icache_range(hwaddr start, int len);
extern struct MemoryRegion io_mem_rom;
diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h
index 276dd5afce..ab4f8b6623 100644
--- a/include/exec/helper-head.h
+++ b/include/exec/helper-head.h
@@ -108,6 +108,19 @@
#define dh_is_signed_env dh_is_signed_ptr
#define dh_is_signed(t) dh_is_signed_##t
+#define dh_callflag_i32 0
+#define dh_callflag_s32 0
+#define dh_callflag_int 0
+#define dh_callflag_i64 0
+#define dh_callflag_s64 0
+#define dh_callflag_f16 0
+#define dh_callflag_f32 0
+#define dh_callflag_f64 0
+#define dh_callflag_ptr 0
+#define dh_callflag_void 0
+#define dh_callflag_noreturn TCG_CALL_NO_RETURN
+#define dh_callflag(t) glue(dh_callflag_, dh_alias(t))
+
#define dh_sizemask(t, n) \
((dh_is_64bit(t) << (n*2)) | (dh_is_signed(t) << (n*2+1)))
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index b3bdb0c399..268e0f804b 100644
--- a/include/exec/helper-tcg.h
+++ b/include/exec/helper-tcg.h
@@ -11,36 +11,43 @@
#define str(s) #s
#define DEF_HELPER_FLAGS_0(NAME, FLAGS, ret) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) },
#define DEF_HELPER_FLAGS_1(NAME, FLAGS, ret, t1) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) },
#define DEF_HELPER_FLAGS_2(NAME, FLAGS, ret, t1, t2) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
| dh_sizemask(t2, 2) },
#define DEF_HELPER_FLAGS_3(NAME, FLAGS, ret, t1, t2, t3) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
| dh_sizemask(t2, 2) | dh_sizemask(t3, 3) },
#define DEF_HELPER_FLAGS_4(NAME, FLAGS, ret, t1, t2, t3, t4) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
| dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) },
#define DEF_HELPER_FLAGS_5(NAME, FLAGS, ret, t1, t2, t3, t4, t5) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
| dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) \
| dh_sizemask(t5, 5) },
#define DEF_HELPER_FLAGS_6(NAME, FLAGS, ret, t1, t2, t3, t4, t5, t6) \
- { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \
+ { .func = HELPER(NAME), .name = str(NAME), \
+ .flags = FLAGS | dh_callflag(ret), \
.sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \
| dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) \
| dh_sizemask(t5, 5) | dh_sizemask(t6, 6) },
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 8e61450de3..cd2f209b64 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -379,9 +379,9 @@ struct MemoryRegion {
MemoryRegion *alias;
hwaddr alias_offset;
int32_t priority;
- QTAILQ_HEAD(subregions, MemoryRegion) subregions;
+ QTAILQ_HEAD(, MemoryRegion) subregions;
QTAILQ_ENTRY(MemoryRegion) subregions_link;
- QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
+ QTAILQ_HEAD(, CoalescedMemoryRange) coalesced;
const char *name;
unsigned ioeventfd_nb;
MemoryRegionIoeventfd *ioeventfds;
@@ -445,7 +445,7 @@ struct AddressSpace {
int ioeventfd_nb;
struct MemoryRegionIoeventfd *ioeventfds;
- QTAILQ_HEAD(memory_listeners_as, MemoryListener) listeners;
+ QTAILQ_HEAD(, MemoryListener) listeners;
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
};
@@ -1792,6 +1792,32 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
MemTxAttrs attrs,
const uint8_t *buf, int len);
+/**
+ * address_space_write_rom: write to address space, including ROM.
+ *
+ * This function writes to the specified address space, but will
+ * write data to both ROM and RAM. This is used for non-guest
+ * writes like writes from the gdb debug stub or initial loading
+ * of ROM contents.
+ *
+ * Note that portions of the write which attempt to write data to
+ * a device will be silently ignored -- only real RAM and ROM will
+ * be written to.
+ *
+ * Return a MemTxResult indicating whether the operation succeeded
+ * or failed (eg unassigned memory, device rejected the transaction,
+ * IOMMU fault).
+ *
+ * @as: #AddressSpace to be accessed
+ * @addr: address within that address space
+ * @attrs: memory transaction attributes
+ * @buf: buffer with the data transferred
+ * @len: the number of bytes to write
+ */
+MemTxResult address_space_write_rom(AddressSpace *as, hwaddr addr,
+ MemTxAttrs attrs,
+ const uint8_t *buf, int len);
+
/* address_space_ld*: load from an address space
* address_space_st*: store to an address space
*
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 32d53789f8..ecdc83c147 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -79,6 +79,7 @@
#pragma GCC poison CONFIG_MOXIE_DIS
#pragma GCC poison CONFIG_NIOS2_DIS
#pragma GCC poison CONFIG_PPC_DIS
+#pragma GCC poison CONFIG_RISCV_DIS
#pragma GCC poison CONFIG_S390_DIS
#pragma GCC poison CONFIG_SH4_DIS
#pragma GCC poison CONFIG_SPARC_DIS
diff --git a/include/exec/tb-hash.h b/include/exec/tb-hash.h
index 0526c4f678..4f3a37d927 100644
--- a/include/exec/tb-hash.h
+++ b/include/exec/tb-hash.h
@@ -20,7 +20,7 @@
#ifndef EXEC_TB_HASH_H
#define EXEC_TB_HASH_H
-#include "exec/tb-hash-xx.h"
+#include "qemu/xxhash.h"
#ifdef CONFIG_SOFTMMU
@@ -61,7 +61,7 @@ static inline
uint32_t tb_hash_func(tb_page_addr_t phys_pc, target_ulong pc, uint32_t flags,
uint32_t cf_mask, uint32_t trace_vcpu_dstate)
{
- return tb_hash_func7(phys_pc, pc, flags, cf_mask, trace_vcpu_dstate);
+ return qemu_xxhash7(phys_pc, pc, flags, cf_mask, trace_vcpu_dstate);
}
#endif
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 8fd9f9bbae..38a5e99cf3 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -464,6 +464,21 @@ static inline int float32_is_zero_or_denormal(float32 a)
return (float32_val(a) & 0x7f800000) == 0;
}
+static inline bool float32_is_normal(float32 a)
+{
+ return ((float32_val(a) + 0x00800000) & 0x7fffffff) >= 0x01000000;
+}
+
+static inline bool float32_is_denormal(float32 a)
+{
+ return float32_is_zero_or_denormal(a) && !float32_is_zero(a);
+}
+
+static inline bool float32_is_zero_or_normal(float32 a)
+{
+ return float32_is_normal(a) || float32_is_zero(a);
+}
+
static inline float32 float32_set_sign(float32 a, int sign)
{
return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31));
@@ -605,6 +620,21 @@ static inline int float64_is_zero_or_denormal(float64 a)
return (float64_val(a) & 0x7ff0000000000000LL) == 0;
}
+static inline bool float64_is_normal(float64 a)
+{
+ return ((float64_val(a) + (1ULL << 52)) & -1ULL >> 1) >= 1ULL << 53;
+}
+
+static inline bool float64_is_denormal(float64 a)
+{
+ return float64_is_zero_or_denormal(a) && !float64_is_zero(a);
+}
+
+static inline bool float64_is_zero_or_normal(float64 a)
+{
+ return float64_is_normal(a) || float64_is_zero(a);
+}
+
static inline float64 float64_set_sign(float64 a, int sign)
{
return make_float64((float64_val(a) & 0x7fffffffffffffffULL)
diff --git a/include/glib-compat.h b/include/glib-compat.h
index fdf95a255d..8a078c5288 100644
--- a/include/glib-compat.h
+++ b/include/glib-compat.h
@@ -83,6 +83,62 @@ static inline gboolean g_strv_contains_qemu(const gchar *const *strv,
}
#define g_strv_contains(a, b) g_strv_contains_qemu(a, b)
+#if !GLIB_CHECK_VERSION(2, 58, 0)
+typedef struct QemuGSpawnFds {
+ GSpawnChildSetupFunc child_setup;
+ gpointer user_data;
+ gint stdin_fd;
+ gint stdout_fd;
+ gint stderr_fd;
+} QemuGSpawnFds;
+
+static inline void
+qemu_gspawn_fds_setup(gpointer user_data)
+{
+ QemuGSpawnFds *q = (QemuGSpawnFds *)user_data;
+
+ dup2(q->stdin_fd, 0);
+ dup2(q->stdout_fd, 1);
+ dup2(q->stderr_fd, 2);
+ q->child_setup(q->user_data);
+}
+#endif
+
+static inline gboolean
+g_spawn_async_with_fds_qemu(const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ gint stdin_fd,
+ gint stdout_fd,
+ gint stderr_fd,
+ GError **error)
+{
+#if GLIB_CHECK_VERSION(2, 58, 0)
+ return g_spawn_async_with_fds(working_directory, argv, envp, flags,
+ child_setup, user_data,
+ child_pid, stdin_fd, stdout_fd, stderr_fd,
+ error);
+#else
+ QemuGSpawnFds setup = {
+ .child_setup = child_setup,
+ .user_data = user_data,
+ .stdin_fd = stdin_fd,
+ .stdout_fd = stdout_fd,
+ .stderr_fd = stderr_fd,
+ };
+
+ return g_spawn_async(working_directory, argv, envp, flags,
+ qemu_gspawn_fds_setup, &setup,
+ child_pid, error);
+#endif
+}
+
+#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
+ g_spawn_async_with_fds_qemu(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
#if defined(_WIN32) && !GLIB_CHECK_VERSION(2, 50, 0)
/*
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index af8e023968..f9aa4bd398 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -40,18 +40,13 @@ enum {
ACPI_FADT_F_LOW_POWER_S0_IDLE_CAPABLE,
};
-struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */
- uint64_t signature; /* ACPI signature, contains "RSD PTR " */
- uint8_t checksum; /* To make sum of struct == 0 */
- uint8_t oem_id [6]; /* OEM identification */
- uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
- uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
- uint32_t length; /* XSDT Length in bytes including hdr */
- uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
- uint8_t extended_checksum; /* Checksum of entire table */
- uint8_t reserved [3]; /* Reserved field must be 0 */
-} QEMU_PACKED;
-typedef struct AcpiRsdpDescriptor AcpiRsdpDescriptor;
+typedef struct AcpiRsdpData {
+ uint8_t oem_id[6] QEMU_NONSTRING; /* OEM identification */
+ uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
+
+ unsigned *rsdt_tbl_offset;
+ unsigned *xsdt_tbl_offset;
+} AcpiRsdpData;
/* Table structure from Linux kernel (the ACPI tables are under the
BSD license) */
@@ -62,10 +57,13 @@ typedef struct AcpiRsdpDescriptor AcpiRsdpDescriptor;
uint32_t length; /* Length of table, in bytes, including header */ \
uint8_t revision; /* ACPI Specification minor version # */ \
uint8_t checksum; /* To make sum of entire table == 0 */ \
- uint8_t oem_id [6]; /* OEM identification */ \
- uint8_t oem_table_id [8]; /* OEM table identification */ \
+ uint8_t oem_id[6] \
+ QEMU_NONSTRING; /* OEM identification */ \
+ uint8_t oem_table_id[8] \
+ QEMU_NONSTRING; /* OEM table identification */ \
uint32_t oem_revision; /* OEM revision number */ \
- uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */ \
+ uint8_t asl_compiler_id[4] \
+ QEMU_NONSTRING; /* ASL compiler vendor ID */ \
uint32_t asl_compiler_revision; /* ASL compiler revision number */
@@ -628,6 +626,8 @@ struct AcpiIortItsGroup {
} QEMU_PACKED;
typedef struct AcpiIortItsGroup AcpiIortItsGroup;
+#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE 1
+
struct AcpiIortSmmu3 {
ACPI_IORT_NODE_HEADER_DEF
uint64_t base_address;
diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h
index c20ace0d0b..bbf541263a 100644
--- a/include/hw/acpi/acpi.h
+++ b/include/hw/acpi/acpi.h
@@ -69,13 +69,13 @@
#define ACPI_BITMASK_WAKE_STATUS 0x8000
#define ACPI_BITMASK_ALL_FIXED_STATUS (\
- ACPI_BITMASK_TIMER_STATUS | \
- ACPI_BITMASK_BUS_MASTER_STATUS | \
- ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
- ACPI_BITMASK_POWER_BUTTON_STATUS | \
- ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
- ACPI_BITMASK_RT_CLOCK_STATUS | \
- ACPI_BITMASK_WAKE_STATUS)
+ ACPI_BITMASK_TIMER_STATUS | \
+ ACPI_BITMASK_BUS_MASTER_STATUS | \
+ ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
+ ACPI_BITMASK_POWER_BUTTON_STATUS | \
+ ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
+ ACPI_BITMASK_RT_CLOCK_STATUS | \
+ ACPI_BITMASK_WAKE_STATUS)
/* PM1x_EN */
#define ACPI_BITMASK_TIMER_ENABLE 0x0001
diff --git a/include/hw/acpi/acpi_dev_interface.h b/include/hw/acpi/acpi_dev_interface.h
index dabf4c4fc9..43ff119179 100644
--- a/include/hw/acpi/acpi_dev_interface.h
+++ b/include/hw/acpi/acpi_dev_interface.h
@@ -25,11 +25,7 @@ typedef enum {
INTERFACE_CHECK(AcpiDeviceIf, (obj), \
TYPE_ACPI_DEVICE_IF)
-
-typedef struct AcpiDeviceIf {
- /* <private> */
- Object Parent;
-} AcpiDeviceIf;
+typedef struct AcpiDeviceIf AcpiDeviceIf;
void acpi_send_event(DeviceState *dev, AcpiEventStatusBits event);
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 6c36903c0a..1a563ad756 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -388,6 +388,8 @@ void acpi_add_table(GArray *table_offsets, GArray *table_data);
void acpi_build_tables_init(AcpiBuildTables *tables);
void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre);
void
+build_rsdp(GArray *tbl, BIOSLinker *linker, AcpiRsdpData *rsdp_data);
+void
build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
const char *oem_id, const char *oem_table_id);
void
diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h
index 8a65f99fc8..8bc4a4c01d 100644
--- a/include/hw/acpi/pcihp.h
+++ b/include/hw/acpi/pcihp.h
@@ -56,10 +56,15 @@ typedef struct AcpiPciHpState {
void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root,
MemoryRegion *address_space_io, bool bridges_enabled);
+void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp);
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp);
+void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ AcpiPciHpState *s, DeviceState *dev,
+ Error **errp);
/* Called on reset */
void acpi_pcihp_reset(AcpiPciHpState *s);
diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index 3580ffd50c..1a2a57a21f 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -18,6 +18,8 @@
#include "qemu/units.h"
#include "hw/registerfields.h"
+#include "hw/acpi/aml-build.h"
+#include "sysemu/tpm.h"
#define TPM_TIS_ADDR_BASE 0xFED40000
#define TPM_TIS_ADDR_SIZE 0x5000
@@ -188,4 +190,23 @@ REG32(CRB_DATA_BUFFER, 0x80)
#define TPM2_START_METHOD_MMIO 6
#define TPM2_START_METHOD_CRB 7
+/*
+ * Physical Presence Interface
+ */
+#define TPM_PPI_ADDR_SIZE 0x400
+#define TPM_PPI_ADDR_BASE 0xFED45000
+
+#define TPM_PPI_VERSION_NONE 0
+#define TPM_PPI_VERSION_1_30 1
+
+/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
+#define TPM_PPI_FUNC_NOT_IMPLEMENTED (0 << 0)
+#define TPM_PPI_FUNC_BIOS_ONLY (1 << 0)
+#define TPM_PPI_FUNC_BLOCKED (2 << 0)
+#define TPM_PPI_FUNC_ALLOWED_USR_REQ (3 << 0)
+#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
+#define TPM_PPI_FUNC_MASK (7 << 0)
+
+void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev);
+
#endif /* HW_ACPI_TPM_H */
diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
index efb8fc8123..389e128d0f 100644
--- a/include/hw/arm/allwinner-a10.h
+++ b/include/hw/arm/allwinner-a10.h
@@ -35,6 +35,7 @@ typedef struct AwA10State {
AwA10PICState intc;
AwEmacState emac;
AllwinnerAHCIState sata;
+ MemoryRegion sram_a;
} AwA10State;
#define ALLWINNER_H_
diff --git a/include/hw/arm/linux-boot-if.h b/include/hw/arm/linux-boot-if.h
index aba4479a14..7bbdfd1cc6 100644
--- a/include/hw/arm/linux-boot-if.h
+++ b/include/hw/arm/linux-boot-if.h
@@ -16,10 +16,7 @@
#define ARM_LINUX_BOOT_IF(obj) \
INTERFACE_CHECK(ARMLinuxBootIf, (obj), TYPE_ARM_LINUX_BOOT_IF)
-typedef struct ARMLinuxBootIf {
- /*< private >*/
- Object parent_obj;
-} ARMLinuxBootIf;
+typedef struct ARMLinuxBootIf ARMLinuxBootIf;
typedef struct ARMLinuxBootIfClass {
/*< private >*/
diff --git a/include/hw/arm/nrf51.h b/include/hw/arm/nrf51.h
new file mode 100644
index 0000000000..175bb6c301
--- /dev/null
+++ b/include/hw/arm/nrf51.h
@@ -0,0 +1,45 @@
+/*
+ * Nordic Semiconductor nRF51 Series SOC Common Defines
+ *
+ * This file hosts generic defines used in various nRF51 peripheral devices.
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef NRF51_H
+#define NRF51_H
+
+#define NRF51_FLASH_BASE 0x00000000
+#define NRF51_FICR_BASE 0x10000000
+#define NRF51_FICR_SIZE 0x00000100
+#define NRF51_UICR_BASE 0x10001000
+#define NRF51_SRAM_BASE 0x20000000
+
+#define NRF51_IOMEM_BASE 0x40000000
+#define NRF51_IOMEM_SIZE 0x20000000
+
+#define NRF51_UART_BASE 0x40002000
+#define NRF51_TIMER_BASE 0x40008000
+#define NRF51_TIMER_SIZE 0x00001000
+#define NRF51_RNG_BASE 0x4000D000
+#define NRF51_NVMC_BASE 0x4001E000
+#define NRF51_GPIO_BASE 0x50000000
+
+#define NRF51_PRIVATE_BASE 0xF0000000
+#define NRF51_PRIVATE_SIZE 0x10000000
+
+#define NRF51_PAGE_SIZE 1024
+
+/* Trigger */
+#define NRF51_TRIGGER_TASK 0x01
+
+/* Events */
+#define NRF51_EVENT_CLEAR 0x00
+
+#endif
diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h
index 73fc92e9a8..e06f0304b4 100644
--- a/include/hw/arm/nrf51_soc.h
+++ b/include/hw/arm/nrf51_soc.h
@@ -13,11 +13,16 @@
#include "hw/sysbus.h"
#include "hw/arm/armv7m.h"
#include "hw/char/nrf51_uart.h"
+#include "hw/misc/nrf51_rng.h"
+#include "hw/gpio/nrf51_gpio.h"
+#include "hw/timer/nrf51_timer.h"
#define TYPE_NRF51_SOC "nrf51-soc"
#define NRF51_SOC(obj) \
OBJECT_CHECK(NRF51State, (obj), TYPE_NRF51_SOC)
+#define NRF51_NUM_TIMERS 3
+
typedef struct NRF51State {
/*< private >*/
SysBusDevice parent_obj;
@@ -26,10 +31,14 @@ typedef struct NRF51State {
ARMv7MState cpu;
NRF51UARTState uart;
+ NRF51RNGState rng;
+ NRF51GPIOState gpio;
+ NRF51TimerState timer[NRF51_NUM_TIMERS];
MemoryRegion iomem;
MemoryRegion sram;
MemoryRegion flash;
+ MemoryRegion clock;
uint32_t sram_size;
uint32_t flash_size;
diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h
index 0df1199caa..f6dfb5c0cf 100644
--- a/include/hw/arm/pxa.h
+++ b/include/hw/arm/pxa.h
@@ -12,6 +12,7 @@
#include "exec/memory.h"
#include "target/arm/cpu-qom.h"
+#include "hw/pcmcia.h"
/* Interrupt numbers */
# define PXA2XX_PIC_SSP3 0
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
index 9da621e4b6..ec7c859d08 100644
--- a/include/hw/arm/xlnx-versal.h
+++ b/include/hw/arm/xlnx-versal.h
@@ -22,7 +22,7 @@
#define XLNX_VERSAL_NR_ACPUS 2
#define XLNX_VERSAL_NR_UARTS 2
#define XLNX_VERSAL_NR_GEMS 2
-#define XLNX_VERSAL_NR_IRQS 256
+#define XLNX_VERSAL_NR_IRQS 192
typedef struct Versal {
/*< private >*/
@@ -75,9 +75,9 @@ typedef struct Versal {
#define VERSAL_GEM1_IRQ_0 58
#define VERSAL_GEM1_WAKE_IRQ_0 59
-/* Architecturally eserved IRQs suitable for virtualization. */
-#define VERSAL_RSVD_HIGH_IRQ_FIRST 160
-#define VERSAL_RSVD_HIGH_IRQ_LAST 255
+/* Architecturally reserved IRQs suitable for virtualization. */
+#define VERSAL_RSVD_IRQ_FIRST 111
+#define VERSAL_RSVD_IRQ_LAST 118
#define MM_TOP_RSVD 0xa0000000U
#define MM_TOP_RSVD_SIZE 0x4000000
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 98f925ab84..591515c760 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -31,6 +31,7 @@
#include "hw/display/xlnx_dp.h"
#include "hw/intc/xlnx-zynqmp-ipi.h"
#include "hw/timer/xlnx-zynqmp-rtc.h"
+#include "hw/cpu/cluster.h"
#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@@ -77,6 +78,8 @@ typedef struct XlnxZynqMPState {
DeviceState parent_obj;
/*< public >*/
+ CPUClusterState apu_cluster;
+ CPUClusterState rpu_cluster;
ARMCPU apu_cpu[XLNX_ZYNQMP_NUM_APU_CPUS];
ARMCPU rpu_cpu[XLNX_ZYNQMP_NUM_RPU_CPUS];
GICState gic;
diff --git a/include/hw/boards.h b/include/hw/boards.h
index f82f28468b..02f114085f 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -69,7 +69,6 @@ int machine_kvm_shadow_mem(MachineState *machine);
int machine_phandle_start(MachineState *machine);
bool machine_dump_guest_core(MachineState *machine);
bool machine_mem_merge(MachineState *machine);
-void machine_register_compat_props(MachineState *machine);
HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
void machine_set_cpu_numa_node(MachineState *machine,
const CpuInstanceProperties *props,
@@ -191,10 +190,11 @@ struct MachineClass {
const char *default_machine_opts;
const char *default_boot_order;
const char *default_display;
- GArray *compat_props;
+ GPtrArray *compat_props;
const char *hw_version;
ram_addr_t default_ram_size;
const char *default_cpu_type;
+ bool default_kernel_irqchip_split;
bool option_rom_has_mr;
bool rom_file_has_mr;
int minimum_page_bits;
@@ -288,20 +288,46 @@ struct MachineState {
} \
type_init(machine_initfn##_register_types)
-#define SET_MACHINE_COMPAT(m, COMPAT) \
- do { \
- int i; \
- static GlobalProperty props[] = { \
- COMPAT \
- { /* end of list */ } \
- }; \
- if (!m->compat_props) { \
- m->compat_props = g_array_new(false, false, sizeof(void *)); \
- } \
- for (i = 0; props[i].driver != NULL; i++) { \
- GlobalProperty *prop = &props[i]; \
- g_array_append_val(m->compat_props, prop); \
- } \
- } while (0)
+extern GlobalProperty hw_compat_3_1[];
+extern const size_t hw_compat_3_1_len;
+
+extern GlobalProperty hw_compat_3_0[];
+extern const size_t hw_compat_3_0_len;
+
+extern GlobalProperty hw_compat_2_12[];
+extern const size_t hw_compat_2_12_len;
+
+extern GlobalProperty hw_compat_2_11[];
+extern const size_t hw_compat_2_11_len;
+
+extern GlobalProperty hw_compat_2_10[];
+extern const size_t hw_compat_2_10_len;
+
+extern GlobalProperty hw_compat_2_9[];
+extern const size_t hw_compat_2_9_len;
+
+extern GlobalProperty hw_compat_2_8[];
+extern const size_t hw_compat_2_8_len;
+
+extern GlobalProperty hw_compat_2_7[];
+extern const size_t hw_compat_2_7_len;
+
+extern GlobalProperty hw_compat_2_6[];
+extern const size_t hw_compat_2_6_len;
+
+extern GlobalProperty hw_compat_2_5[];
+extern const size_t hw_compat_2_5_len;
+
+extern GlobalProperty hw_compat_2_4[];
+extern const size_t hw_compat_2_4_len;
+
+extern GlobalProperty hw_compat_2_3[];
+extern const size_t hw_compat_2_3_len;
+
+extern GlobalProperty hw_compat_2_2[];
+extern const size_t hw_compat_2_2_len;
+
+extern GlobalProperty hw_compat_2_1[];
+extern const size_t hw_compat_2_1_len;
#endif
diff --git a/include/hw/char/nrf51_uart.h b/include/hw/char/nrf51_uart.h
index e3ecb7c81c..eb1c15b490 100644
--- a/include/hw/char/nrf51_uart.h
+++ b/include/hw/char/nrf51_uart.h
@@ -16,7 +16,6 @@
#include "hw/registerfields.h"
#define UART_FIFO_LENGTH 6
-#define UART_BASE 0x40002000
#define UART_SIZE 0x1000
#define TYPE_NRF51_UART "nrf51_soc.uart"
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index 0acfbbc382..abd5cf71a9 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -35,7 +35,7 @@
#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
-struct SerialState {
+typedef struct SerialState {
uint16_t divider;
uint8_t rbr; /* receive register */
uint8_t thr; /* transmit holding register */
@@ -77,7 +77,7 @@ struct SerialState {
QEMUTimer *modem_status_poll;
MemoryRegion io;
-};
+} SerialState;
extern const VMStateDescription vmstate_serial;
extern const MemoryRegionOps serial_io_ops;
diff --git a/include/hw/compat.h b/include/hw/compat.h
deleted file mode 100644
index 6f4d5fc647..0000000000
--- a/include/hw/compat.h
+++ /dev/null
@@ -1,288 +0,0 @@
-#ifndef HW_COMPAT_H
-#define HW_COMPAT_H
-
-#define HW_COMPAT_3_0 \
- /* empty */
-
-#define HW_COMPAT_2_12 \
- {\
- .driver = "migration",\
- .property = "decompress-error-check",\
- .value = "off",\
- },{\
- .driver = "hda-audio",\
- .property = "use-timer",\
- .value = "false",\
- },{\
- .driver = "cirrus-vga",\
- .property = "global-vmstate",\
- .value = "true",\
- },{\
- .driver = "VGA",\
- .property = "global-vmstate",\
- .value = "true",\
- },{\
- .driver = "vmware-svga",\
- .property = "global-vmstate",\
- .value = "true",\
- },{\
- .driver = "qxl-vga",\
- .property = "global-vmstate",\
- .value = "true",\
- },
-
-#define HW_COMPAT_2_11 \
- {\
- .driver = "hpet",\
- .property = "hpet-offset-saved",\
- .value = "false",\
- },{\
- .driver = "virtio-blk-pci",\
- .property = "vectors",\
- .value = "2",\
- },{\
- .driver = "vhost-user-blk-pci",\
- .property = "vectors",\
- .value = "2",\
- },{\
- .driver = "e1000",\
- .property = "migrate_tso_props",\
- .value = "off",\
- },
-
-#define HW_COMPAT_2_10 \
- {\
- .driver = "virtio-mouse-device",\
- .property = "wheel-axis",\
- .value = "false",\
- },{\
- .driver = "virtio-tablet-device",\
- .property = "wheel-axis",\
- .value = "false",\
- },
-
-#define HW_COMPAT_2_9 \
- {\
- .driver = "pci-bridge",\
- .property = "shpc",\
- .value = "off",\
- },{\
- .driver = "intel-iommu",\
- .property = "pt",\
- .value = "off",\
- },{\
- .driver = "virtio-net-device",\
- .property = "x-mtu-bypass-backend",\
- .value = "off",\
- },{\
- .driver = "pcie-root-port",\
- .property = "x-migrate-msix",\
- .value = "false",\
- },
-
-#define HW_COMPAT_2_8 \
- {\
- .driver = "fw_cfg_mem",\
- .property = "x-file-slots",\
- .value = stringify(0x10),\
- },{\
- .driver = "fw_cfg_io",\
- .property = "x-file-slots",\
- .value = stringify(0x10),\
- },{\
- .driver = "pflash_cfi01",\
- .property = "old-multiple-chip-handling",\
- .value = "on",\
- },{\
- .driver = "pci-bridge",\
- .property = "shpc",\
- .value = "on",\
- },{\
- .driver = TYPE_PCI_DEVICE,\
- .property = "x-pcie-extcap-init",\
- .value = "off",\
- },{\
- .driver = "virtio-pci",\
- .property = "x-pcie-deverr-init",\
- .value = "off",\
- },{\
- .driver = "virtio-pci",\
- .property = "x-pcie-lnkctl-init",\
- .value = "off",\
- },{\
- .driver = "virtio-pci",\
- .property = "x-pcie-pm-init",\
- .value = "off",\
- },{\
- .driver = "cirrus-vga",\
- .property = "vgamem_mb",\
- .value = "8",\
- },{\
- .driver = "isa-cirrus-vga",\
- .property = "vgamem_mb",\
- .value = "8",\
- },
-
-#define HW_COMPAT_2_7 \
- {\
- .driver = "virtio-pci",\
- .property = "page-per-vq",\
- .value = "on",\
- },{\
- .driver = "virtio-serial-device",\
- .property = "emergency-write",\
- .value = "off",\
- },{\
- .driver = "ioapic",\
- .property = "version",\
- .value = "0x11",\
- },{\
- .driver = "intel-iommu",\
- .property = "x-buggy-eim",\
- .value = "true",\
- },{\
- .driver = "virtio-pci",\
- .property = "x-ignore-backend-features",\
- .value = "on",\
- },
-
-#define HW_COMPAT_2_6 \
- {\
- .driver = "virtio-mmio",\
- .property = "format_transport_address",\
- .value = "off",\
- },{\
- .driver = "virtio-pci",\
- .property = "disable-modern",\
- .value = "on",\
- },{\
- .driver = "virtio-pci",\
- .property = "disable-legacy",\
- .value = "off",\
- },
-
-#define HW_COMPAT_2_5 \
- {\
- .driver = "isa-fdc",\
- .property = "fallback",\
- .value = "144",\
- },{\
- .driver = "pvscsi",\
- .property = "x-old-pci-configuration",\
- .value = "on",\
- },{\
- .driver = "pvscsi",\
- .property = "x-disable-pcie",\
- .value = "on",\
- },\
- {\
- .driver = "vmxnet3",\
- .property = "x-old-msi-offsets",\
- .value = "on",\
- },{\
- .driver = "vmxnet3",\
- .property = "x-disable-pcie",\
- .value = "on",\
- },
-
-#define HW_COMPAT_2_4 \
- {\
- .driver = "virtio-blk-device",\
- .property = "scsi",\
- .value = "true",\
- },{\
- .driver = "e1000",\
- .property = "extra_mac_registers",\
- .value = "off",\
- },{\
- .driver = "virtio-pci",\
- .property = "x-disable-pcie",\
- .value = "on",\
- },{\
- .driver = "virtio-pci",\
- .property = "migrate-extra",\
- .value = "off",\
- },{\
- .driver = "fw_cfg_mem",\
- .property = "dma_enabled",\
- .value = "off",\
- },{\
- .driver = "fw_cfg_io",\
- .property = "dma_enabled",\
- .value = "off",\
- },
-
-#define HW_COMPAT_2_3 \
- {\
- .driver = "virtio-blk-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "virtio-balloon-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "virtio-9p-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "virtio-rng-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = TYPE_PCI_DEVICE,\
- .property = "x-pcie-lnksta-dllla",\
- .value = "off",\
- },{\
- .driver = "migration",\
- .property = "send-configuration",\
- .value = "off",\
- },{\
- .driver = "migration",\
- .property = "send-section-footer",\
- .value = "off",\
- },{\
- .driver = "migration",\
- .property = "store-global-state",\
- .value = "off",\
- },
-
-#define HW_COMPAT_2_2 \
- /* empty */
-
-#define HW_COMPAT_2_1 \
- {\
- .driver = "intel-hda",\
- .property = "old_msi_addr",\
- .value = "on",\
- },{\
- .driver = "VGA",\
- .property = "qemu-extended-regs",\
- .value = "off",\
- },{\
- .driver = "secondary-vga",\
- .property = "qemu-extended-regs",\
- .value = "off",\
- },{\
- .driver = "virtio-scsi-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "usb-mouse",\
- .property = "usb_version",\
- .value = stringify(1),\
- },{\
- .driver = "usb-kbd",\
- .property = "usb_version",\
- .value = stringify(1),\
- },{\
- .driver = "virtio-pci",\
- .property = "virtio-pci-bus-master-bug-migration",\
- .value = "on",\
- },
-
-#endif /* HW_COMPAT_H */
diff --git a/include/hw/cpu/cluster.h b/include/hw/cpu/cluster.h
new file mode 100644
index 0000000000..7381823243
--- /dev/null
+++ b/include/hw/cpu/cluster.h
@@ -0,0 +1,58 @@
+/*
+ * QEMU CPU cluster
+ *
+ * Copyright (c) 2018 GreenSocs SAS
+ *
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 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/gpl-2.0.html>
+ */
+#ifndef HW_CPU_CLUSTER_H
+#define HW_CPU_CLUSTER_H
+
+#include "qemu/osdep.h"
+#include "hw/qdev.h"
+
+/*
+ * CPU Cluster type
+ *
+ * A cluster is a group of CPUs which are all identical and have the same view
+ * of the rest of the system. It is mainly an internal QEMU representation and
+ * does not necessarily match with the notion of clusters on the real hardware.
+ *
+ * If CPUs are not identical (for example, Cortex-A53 and Cortex-A57 CPUs in an
+ * Arm big.LITTLE system) they should be in different clusters. If the CPUs do
+ * not have the same view of memory (for example the main CPU and a management
+ * controller processor) they should be in different clusters.
+ */
+
+#define TYPE_CPU_CLUSTER "cpu-cluster"
+#define CPU_CLUSTER(obj) \
+ OBJECT_CHECK(CPUClusterState, (obj), TYPE_CPU_CLUSTER)
+
+/**
+ * CPUClusterState:
+ * @cluster_id: The cluster ID. This value is for internal use only and should
+ * not be exposed directly to the user or to the guest.
+ *
+ * State of a CPU cluster.
+ */
+typedef struct CPUClusterState {
+ /*< private >*/
+ DeviceState parent_obj;
+
+ /*< public >*/
+ uint32_t cluster_id;
+} CPUClusterState;
+
+#endif
diff --git a/include/hw/devices.h b/include/hw/devices.h
index 0e27feb0c2..b5f1662225 100644
--- a/include/hw/devices.h
+++ b/include/hw/devices.h
@@ -4,6 +4,7 @@
/* Devices that have nowhere better to go. */
#include "hw/hw.h"
+#include "ui/console.h"
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index 81cecaf27e..e2cb675195 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -343,7 +343,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
}
if (pentry)
- *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
+ *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb, sym_cb);
@@ -482,7 +482,9 @@ static int glue(load_elf, SZ)(const char *name, int fd,
rom_add_elf_program(label, data, file_size, mem_size,
addr, as);
} else {
- cpu_physical_memory_write(addr, data, file_size);
+ address_space_write(as ? as : &address_space_memory,
+ addr, MEMTXATTRS_UNSPECIFIED,
+ data, file_size);
g_free(data);
}
}
diff --git a/include/hw/smbios/smbios.h b/include/hw/firmware/smbios.h
index eeb5a4d7b6..eeb5a4d7b6 100644
--- a/include/hw/smbios/smbios.h
+++ b/include/hw/firmware/smbios.h
diff --git a/include/hw/fw-path-provider.h b/include/hw/fw-path-provider.h
index 050cb05d92..5df893a3d8 100644
--- a/include/hw/fw-path-provider.h
+++ b/include/hw/fw-path-provider.h
@@ -30,9 +30,7 @@
#define FW_PATH_PROVIDER(obj) \
INTERFACE_CHECK(FWPathProvider, (obj), TYPE_FW_PATH_PROVIDER)
-typedef struct FWPathProvider {
- Object parent_obj;
-} FWPathProvider;
+typedef struct FWPathProvider FWPathProvider;
typedef struct FWPathProviderClass {
InterfaceClass parent_class;
diff --git a/include/hw/gpio/nrf51_gpio.h b/include/hw/gpio/nrf51_gpio.h
new file mode 100644
index 0000000000..337ee534bb
--- /dev/null
+++ b/include/hw/gpio/nrf51_gpio.h
@@ -0,0 +1,69 @@
+/*
+ * nRF51 System-on-Chip general purpose input/output register definition
+ *
+ * QEMU interface:
+ * + sysbus MMIO regions 0: GPIO registers
+ * + Unnamed GPIO inputs 0-31: Set tri-state input level for GPIO pin.
+ * Level -1: Externally Disconnected/Floating; Pull-up/down will be regarded
+ * Level 0: Input externally driven LOW
+ * Level 1: Input externally driven HIGH
+ * + Unnamed GPIO outputs 0-31:
+ * Level -1: Disconnected/Floating
+ * Level 0: Driven LOW
+ * Level 1: Driven HIGH
+ *
+ * Accuracy of the peripheral model:
+ * + The nRF51 GPIO output driver supports two modes, standard and high-current
+ * mode. These different drive modes are not modeled and handled the same.
+ * + Pin SENSEing is not modeled/implemented.
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef NRF51_GPIO_H
+#define NRF51_GPIO_H
+
+#include "hw/sysbus.h"
+#define TYPE_NRF51_GPIO "nrf51_soc.gpio"
+#define NRF51_GPIO(obj) OBJECT_CHECK(NRF51GPIOState, (obj), TYPE_NRF51_GPIO)
+
+#define NRF51_GPIO_PINS 32
+
+#define NRF51_GPIO_SIZE 0x1000
+
+#define NRF51_GPIO_REG_OUT 0x504
+#define NRF51_GPIO_REG_OUTSET 0x508
+#define NRF51_GPIO_REG_OUTCLR 0x50C
+#define NRF51_GPIO_REG_IN 0x510
+#define NRF51_GPIO_REG_DIR 0x514
+#define NRF51_GPIO_REG_DIRSET 0x518
+#define NRF51_GPIO_REG_DIRCLR 0x51C
+#define NRF51_GPIO_REG_CNF_START 0x700
+#define NRF51_GPIO_REG_CNF_END 0x77F
+
+#define NRF51_GPIO_PULLDOWN 1
+#define NRF51_GPIO_PULLUP 3
+
+typedef struct NRF51GPIOState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ qemu_irq irq;
+
+ uint32_t out;
+ uint32_t in;
+ uint32_t in_mask;
+ uint32_t dir;
+ uint32_t cnf[NRF51_GPIO_PINS];
+
+ uint32_t old_out;
+ uint32_t old_out_connected;
+
+ qemu_irq output[NRF51_GPIO_PINS];
+} NRF51GPIOState;
+
+
+#endif
diff --git a/include/hw/hotplug.h b/include/hw/hotplug.h
index 1a0516a479..6321e292fd 100644
--- a/include/hw/hotplug.h
+++ b/include/hw/hotplug.h
@@ -23,11 +23,7 @@
#define HOTPLUG_HANDLER(obj) \
INTERFACE_CHECK(HotplugHandler, (obj), TYPE_HOTPLUG_HANDLER)
-
-typedef struct HotplugHandler {
- /* <private> */
- Object Parent;
-} HotplugHandler;
+typedef struct HotplugHandler HotplugHandler;
/**
* hotplug_fn:
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 5dc166158b..cf4c45a98f 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -82,6 +82,8 @@ int i2c_recv(I2CBus *bus);
DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr);
+typedef struct bitbang_i2c_interface bitbang_i2c_interface;
+
/* lm832x.c */
void lm832x_key_event(DeviceState *dev, int key, int state);
diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h
index 0891a9c948..b3450bacf7 100644
--- a/include/hw/i2c/ppc4xx_i2c.h
+++ b/include/hw/i2c/ppc4xx_i2c.h
@@ -31,9 +31,6 @@
#include "hw/sysbus.h"
#include "hw/i2c/i2c.h"
-/* from hw/i2c/bitbang_i2c.h */
-typedef struct bitbang_i2c_interface bitbang_i2c_interface;
-
#define TYPE_PPC4xx_I2C "ppc4xx-i2c"
#define PPC4xx_I2C(obj) OBJECT_CHECK(PPC4xxI2CState, (obj), TYPE_PPC4xx_I2C)
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
index d8b1b9ee81..5c61c05999 100644
--- a/include/hw/i2c/smbus.h
+++ b/include/hw/i2c/smbus.h
@@ -35,6 +35,8 @@
#define SMBUS_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE)
+typedef struct SMBusDevice SMBusDevice;
+
typedef struct SMBusDeviceClass
{
I2CSlaveClass parent_class;
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index ed4e758273..a321cc9691 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -245,6 +245,7 @@ struct IntelIOMMUState {
OnOffAuto intr_eim; /* Toggle for EIM cabability */
bool buggy_eim; /* Force buggy EIM unless eim=off */
uint8_t aw_bits; /* Host/IOVA address width (in bits) */
+ bool dma_drain; /* Whether DMA r/w draining enabled */
/*
* Protects IOMMU states in general. Currently it protects the
diff --git a/include/hw/i386/ioapic.h b/include/hw/i386/ioapic.h
index 9c8816f11f..59fcb158a7 100644
--- a/include/hw/i386/ioapic.h
+++ b/include/hw/i386/ioapic.h
@@ -23,6 +23,9 @@
#define IOAPIC_NUM_PINS 24
#define IO_APIC_DEFAULT_ADDRESS 0xfec00000
+#define TYPE_KVM_IOAPIC "kvm-ioapic"
+#define TYPE_IOAPIC "ioapic"
+
void ioapic_eoi_broadcast(int vector);
#endif /* HW_IOAPIC_H */
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 136fe497b6..882fd8dfd2 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -13,7 +13,6 @@
#include "qemu/bitmap.h"
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
-#include "hw/compat.h"
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
#include "hw/acpi/acpi_dev_interface.h"
@@ -49,9 +48,9 @@ struct PCMachineState {
AcpiNVDIMMState acpi_nvdimm_state;
bool acpi_build_enabled;
- bool smbus;
- bool sata;
- bool pit;
+ bool smbus_enabled;
+ bool sata_enabled;
+ bool pit_enabled;
/* RAM information (sizes, addresses, configuration): */
ram_addr_t below_4g_mem_size, above_4g_mem_size;
@@ -97,7 +96,7 @@ struct PCMachineState {
* way we can use 1GByte pages in the host.
*
*/
-struct PCMachineClass {
+typedef struct PCMachineClass {
/*< private >*/
MachineClass parent_class;
@@ -134,7 +133,7 @@ struct PCMachineClass {
/* use DMA capable linuxboot option rom */
bool linuxboot_dma_enabled;
-};
+} PCMachineClass;
#define TYPE_PC_MACHINE "generic-pc-machine"
#define PC_MACHINE(obj) \
@@ -294,668 +293,70 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
-#define PC_COMPAT_3_0 \
- HW_COMPAT_3_0 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "x-hv-synic-kvm-only",\
- .value = "on",\
- },{\
- .driver = "Skylake-Server" "-" TYPE_X86_CPU,\
- .property = "pku",\
- .value = "off",\
- },{\
- .driver = "Skylake-Server-IBRS" "-" TYPE_X86_CPU,\
- .property = "pku",\
- .value = "off",\
- },
-
-#define PC_COMPAT_2_12 \
- HW_COMPAT_2_12 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "legacy-cache",\
- .value = "on",\
- },{\
- .driver = TYPE_X86_CPU,\
- .property = "topoext",\
- .value = "off",\
- },{\
- .driver = "EPYC-" TYPE_X86_CPU,\
- .property = "xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "EPYC-IBPB-" TYPE_X86_CPU,\
- .property = "xlevel",\
- .value = stringify(0x8000000a),\
- },
-
-#define PC_COMPAT_2_11 \
- HW_COMPAT_2_11 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "x-migrate-smi-count",\
- .value = "off",\
- },{\
- .driver = "Skylake-Server" "-" TYPE_X86_CPU,\
- .property = "clflushopt",\
- .value = "off",\
- },
-
-#define PC_COMPAT_2_10 \
- HW_COMPAT_2_10 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "x-hv-max-vps",\
- .value = "0x40",\
- },{\
- .driver = "i440FX-pcihost",\
- .property = "x-pci-hole64-fix",\
- .value = "off",\
- },{\
- .driver = "q35-pcihost",\
- .property = "x-pci-hole64-fix",\
- .value = "off",\
- },
-
-#define PC_COMPAT_2_9 \
- HW_COMPAT_2_9 \
- {\
- .driver = "mch",\
- .property = "extended-tseg-mbytes",\
- .value = stringify(0),\
- },\
-
-#define PC_COMPAT_2_8 \
- HW_COMPAT_2_8 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "tcg-cpuid",\
- .value = "off",\
- },\
- {\
- .driver = "kvmclock",\
- .property = "x-mach-use-reliable-get-clock",\
- .value = "off",\
- },\
- {\
- .driver = "ICH9-LPC",\
- .property = "x-smi-broadcast",\
- .value = "off",\
- },\
- {\
- .driver = TYPE_X86_CPU,\
- .property = "vmware-cpuid-freq",\
- .value = "off",\
- },\
- {\
- .driver = "Haswell-" TYPE_X86_CPU,\
- .property = "stepping",\
- .value = "1",\
- },
-
-#define PC_COMPAT_2_7 \
- HW_COMPAT_2_7 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "l3-cache",\
- .value = "off",\
- },\
- {\
- .driver = TYPE_X86_CPU,\
- .property = "full-cpuid-auto-level",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G3" "-" TYPE_X86_CPU,\
- .property = "family",\
- .value = "15",\
- },\
- {\
- .driver = "Opteron_G3" "-" TYPE_X86_CPU,\
- .property = "model",\
- .value = "6",\
- },\
- {\
- .driver = "Opteron_G3" "-" TYPE_X86_CPU,\
- .property = "stepping",\
- .value = "1",\
- },\
- {\
- .driver = "isa-pcspk",\
- .property = "migrate",\
- .value = "off",\
- },
-
-#define PC_COMPAT_2_6 \
- HW_COMPAT_2_6 \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "cpuid-0xb",\
- .value = "off",\
- },{\
- .driver = "vmxnet3",\
- .property = "romfile",\
- .value = "",\
- },\
- {\
- .driver = TYPE_X86_CPU,\
- .property = "fill-mtrr-mask",\
- .value = "off",\
- },\
- {\
- .driver = "apic-common",\
- .property = "legacy-instance-id",\
- .value = "on",\
- },
-
-#define PC_COMPAT_2_5 \
- HW_COMPAT_2_5
+extern GlobalProperty pc_compat_3_1[];
+extern const size_t pc_compat_3_1_len;
+
+extern GlobalProperty pc_compat_3_0[];
+extern const size_t pc_compat_3_0_len;
+
+extern GlobalProperty pc_compat_2_12[];
+extern const size_t pc_compat_2_12_len;
+
+extern GlobalProperty pc_compat_2_11[];
+extern const size_t pc_compat_2_11_len;
+
+extern GlobalProperty pc_compat_2_10[];
+extern const size_t pc_compat_2_10_len;
+
+extern GlobalProperty pc_compat_2_9[];
+extern const size_t pc_compat_2_9_len;
+
+extern GlobalProperty pc_compat_2_8[];
+extern const size_t pc_compat_2_8_len;
+
+extern GlobalProperty pc_compat_2_7[];
+extern const size_t pc_compat_2_7_len;
+
+extern GlobalProperty pc_compat_2_6[];
+extern const size_t pc_compat_2_6_len;
+
+extern GlobalProperty pc_compat_2_5[];
+extern const size_t pc_compat_2_5_len;
+
+extern GlobalProperty pc_compat_2_4[];
+extern const size_t pc_compat_2_4_len;
+
+extern GlobalProperty pc_compat_2_3[];
+extern const size_t pc_compat_2_3_len;
+
+extern GlobalProperty pc_compat_2_2[];
+extern const size_t pc_compat_2_2_len;
+
+extern GlobalProperty pc_compat_2_1[];
+extern const size_t pc_compat_2_1_len;
+
+extern GlobalProperty pc_compat_2_0[];
+extern const size_t pc_compat_2_0_len;
+
+extern GlobalProperty pc_compat_1_7[];
+extern const size_t pc_compat_1_7_len;
+
+extern GlobalProperty pc_compat_1_6[];
+extern const size_t pc_compat_1_6_len;
+
+extern GlobalProperty pc_compat_1_5[];
+extern const size_t pc_compat_1_5_len;
+
+extern GlobalProperty pc_compat_1_4[];
+extern const size_t pc_compat_1_4_len;
/* Helper for setting model-id for CPU models that changed model-id
* depending on QEMU versions up to QEMU 2.4.
*/
#define PC_CPU_MODEL_IDS(v) \
- {\
- .driver = "qemu32-" TYPE_X86_CPU,\
- .property = "model-id",\
- .value = "QEMU Virtual CPU version " v,\
- },\
- {\
- .driver = "qemu64-" TYPE_X86_CPU,\
- .property = "model-id",\
- .value = "QEMU Virtual CPU version " v,\
- },\
- {\
- .driver = "athlon-" TYPE_X86_CPU,\
- .property = "model-id",\
- .value = "QEMU Virtual CPU version " v,\
- },
-
-#define PC_COMPAT_2_4 \
- HW_COMPAT_2_4 \
- PC_CPU_MODEL_IDS("2.4.0") \
- {\
- .driver = "Haswell-" TYPE_X86_CPU,\
- .property = "abm",\
- .value = "off",\
- },\
- {\
- .driver = "Haswell-noTSX-" TYPE_X86_CPU,\
- .property = "abm",\
- .value = "off",\
- },\
- {\
- .driver = "Broadwell-" TYPE_X86_CPU,\
- .property = "abm",\
- .value = "off",\
- },\
- {\
- .driver = "Broadwell-noTSX-" TYPE_X86_CPU,\
- .property = "abm",\
- .value = "off",\
- },\
- {\
- .driver = "host" "-" TYPE_X86_CPU,\
- .property = "host-cache-info",\
- .value = "on",\
- },\
- {\
- .driver = TYPE_X86_CPU,\
- .property = "check",\
- .value = "off",\
- },\
- {\
- .driver = "qemu64" "-" TYPE_X86_CPU,\
- .property = "sse4a",\
- .value = "on",\
- },\
- {\
- .driver = "qemu64" "-" TYPE_X86_CPU,\
- .property = "abm",\
- .value = "on",\
- },\
- {\
- .driver = "qemu64" "-" TYPE_X86_CPU,\
- .property = "popcnt",\
- .value = "on",\
- },\
- {\
- .driver = "qemu32" "-" TYPE_X86_CPU,\
- .property = "popcnt",\
- .value = "on",\
- },{\
- .driver = "Opteron_G2" "-" TYPE_X86_CPU,\
- .property = "rdtscp",\
- .value = "on",\
- },{\
- .driver = "Opteron_G3" "-" TYPE_X86_CPU,\
- .property = "rdtscp",\
- .value = "on",\
- },{\
- .driver = "Opteron_G4" "-" TYPE_X86_CPU,\
- .property = "rdtscp",\
- .value = "on",\
- },{\
- .driver = "Opteron_G5" "-" TYPE_X86_CPU,\
- .property = "rdtscp",\
- .value = "on",\
- },
-
-
-#define PC_COMPAT_2_3 \
- HW_COMPAT_2_3 \
- PC_CPU_MODEL_IDS("2.3.0") \
- {\
- .driver = TYPE_X86_CPU,\
- .property = "arat",\
- .value = "off",\
- },{\
- .driver = "qemu64" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(4),\
- },{\
- .driver = "kvm64" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(5),\
- },{\
- .driver = "pentium3" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(2),\
- },{\
- .driver = "n270" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(5),\
- },{\
- .driver = "Conroe" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(4),\
- },{\
- .driver = "Penryn" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(4),\
- },{\
- .driver = "Nehalem" "-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(4),\
- },{\
- .driver = "n270" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Penryn" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Conroe" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Nehalem" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Westmere" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "SandyBridge" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "IvyBridge" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Haswell" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Haswell-noTSX" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Broadwell" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = "Broadwell-noTSX" "-" TYPE_X86_CPU,\
- .property = "min-xlevel",\
- .value = stringify(0x8000000a),\
- },{\
- .driver = TYPE_X86_CPU,\
- .property = "kvm-no-smi-migration",\
- .value = "on",\
- },
-
-#define PC_COMPAT_2_2 \
- HW_COMPAT_2_2 \
- PC_CPU_MODEL_IDS("2.2.0") \
- {\
- .driver = "kvm64" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "kvm32" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Conroe" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Penryn" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Nehalem" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Westmere" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "SandyBridge" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Haswell" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Broadwell" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G1" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G2" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G3" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G4" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Opteron_G5" "-" TYPE_X86_CPU,\
- .property = "vme",\
- .value = "off",\
- },\
- {\
- .driver = "Haswell" "-" TYPE_X86_CPU,\
- .property = "f16c",\
- .value = "off",\
- },\
- {\
- .driver = "Haswell" "-" TYPE_X86_CPU,\
- .property = "rdrand",\
- .value = "off",\
- },\
- {\
- .driver = "Broadwell" "-" TYPE_X86_CPU,\
- .property = "f16c",\
- .value = "off",\
- },\
- {\
- .driver = "Broadwell" "-" TYPE_X86_CPU,\
- .property = "rdrand",\
- .value = "off",\
- },
-
-#define PC_COMPAT_2_1 \
- HW_COMPAT_2_1 \
- PC_CPU_MODEL_IDS("2.1.0") \
- {\
- .driver = "coreduo" "-" TYPE_X86_CPU,\
- .property = "vmx",\
- .value = "on",\
- },\
- {\
- .driver = "core2duo" "-" TYPE_X86_CPU,\
- .property = "vmx",\
- .value = "on",\
- },
-
-#define PC_COMPAT_2_0 \
- PC_CPU_MODEL_IDS("2.0.0") \
- {\
- .driver = "virtio-scsi-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = "PIIX4_PM",\
- .property = "memory-hotplug-support",\
- .value = "off",\
- },\
- {\
- .driver = "apic",\
- .property = "version",\
- .value = stringify(0x11),\
- },\
- {\
- .driver = "nec-usb-xhci",\
- .property = "superspeed-ports-first",\
- .value = "off",\
- },\
- {\
- .driver = "nec-usb-xhci",\
- .property = "force-pcie-endcap",\
- .value = "on",\
- },\
- {\
- .driver = "pci-serial",\
- .property = "prog_if",\
- .value = stringify(0),\
- },\
- {\
- .driver = "pci-serial-2x",\
- .property = "prog_if",\
- .value = stringify(0),\
- },\
- {\
- .driver = "pci-serial-4x",\
- .property = "prog_if",\
- .value = stringify(0),\
- },\
- {\
- .driver = "virtio-net-pci",\
- .property = "guest_announce",\
- .value = "off",\
- },\
- {\
- .driver = "ICH9-LPC",\
- .property = "memory-hotplug-support",\
- .value = "off",\
- },{\
- .driver = "xio3130-downstream",\
- .property = COMPAT_PROP_PCP,\
- .value = "off",\
- },{\
- .driver = "ioh3420",\
- .property = COMPAT_PROP_PCP,\
- .value = "off",\
- },
-
-#define PC_COMPAT_1_7 \
- PC_CPU_MODEL_IDS("1.7.0") \
- {\
- .driver = TYPE_USB_DEVICE,\
- .property = "msos-desc",\
- .value = "no",\
- },\
- {\
- .driver = "PIIX4_PM",\
- .property = "acpi-pci-hotplug-with-bridge-support",\
- .value = "off",\
- },\
- {\
- .driver = "hpet",\
- .property = HPET_INTCAP,\
- .value = stringify(4),\
- },
-
-#define PC_COMPAT_1_6 \
- PC_CPU_MODEL_IDS("1.6.0") \
- {\
- .driver = "e1000",\
- .property = "mitigation",\
- .value = "off",\
- },{\
- .driver = "qemu64-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(2),\
- },{\
- .driver = "qemu32-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(3),\
- },{\
- .driver = "i440FX-pcihost",\
- .property = "short_root_bus",\
- .value = stringify(1),\
- },{\
- .driver = "q35-pcihost",\
- .property = "short_root_bus",\
- .value = stringify(1),\
- },
-
-#define PC_COMPAT_1_5 \
- PC_CPU_MODEL_IDS("1.5.0") \
- {\
- .driver = "Conroe-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(2),\
- },{\
- .driver = "Conroe-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(2),\
- },{\
- .driver = "Penryn-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(2),\
- },{\
- .driver = "Penryn-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(2),\
- },{\
- .driver = "Nehalem-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(2),\
- },{\
- .driver = "Nehalem-" TYPE_X86_CPU,\
- .property = "min-level",\
- .value = stringify(2),\
- },{\
- .driver = "virtio-net-pci",\
- .property = "any_layout",\
- .value = "off",\
- },{\
- .driver = TYPE_X86_CPU,\
- .property = "pmu",\
- .value = "on",\
- },{\
- .driver = "i440FX-pcihost",\
- .property = "short_root_bus",\
- .value = stringify(0),\
- },{\
- .driver = "q35-pcihost",\
- .property = "short_root_bus",\
- .value = stringify(0),\
- },
-
-#define PC_COMPAT_1_4 \
- PC_CPU_MODEL_IDS("1.4.0") \
- {\
- .driver = "scsi-hd",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "scsi-cd",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "scsi-disk",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "ide-hd",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "ide-cd",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "ide-drive",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "virtio-blk-pci",\
- .property = "discard_granularity",\
- .value = stringify(0),\
- },{\
- .driver = "virtio-serial-pci",\
- .property = "vectors",\
- /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\
- .value = stringify(0xFFFFFFFF),\
- },{ \
- .driver = "virtio-net-pci", \
- .property = "ctrl_guest_offloads", \
- .value = "off", \
- },{\
- .driver = "e1000",\
- .property = "romfile",\
- .value = "pxe-e1000.rom",\
- },{\
- .driver = "ne2k_pci",\
- .property = "romfile",\
- .value = "pxe-ne2k_pci.rom",\
- },{\
- .driver = "pcnet",\
- .property = "romfile",\
- .value = "pxe-pcnet.rom",\
- },{\
- .driver = "rtl8139",\
- .property = "romfile",\
- .value = "pxe-rtl8139.rom",\
- },{\
- .driver = "virtio-net-pci",\
- .property = "romfile",\
- .value = "pxe-virtio.rom",\
- },{\
- .driver = "486-" TYPE_X86_CPU,\
- .property = "model",\
- .value = stringify(0),\
- },\
- {\
- .driver = "n270" "-" TYPE_X86_CPU,\
- .property = "movbe",\
- .value = "off",\
- },\
- {\
- .driver = "Westmere" "-" TYPE_X86_CPU,\
- .property = "pclmulqdq",\
- .value = "off",\
- },
+ { "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
+ { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
+ { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
#define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \
static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \
diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h
index 2b22a579a3..dcd9719a2c 100644
--- a/include/hw/i386/x86-iommu.h
+++ b/include/hw/i386/x86-iommu.h
@@ -74,13 +74,15 @@ typedef struct IEC_Notifier IEC_Notifier;
struct X86IOMMUState {
SysBusDevice busdev;
- bool intr_supported; /* Whether vIOMMU supports IR */
+ OnOffAuto intr_supported; /* Whether vIOMMU supports IR */
bool dt_supported; /* Whether vIOMMU supports DT */
bool pt_supported; /* Whether vIOMMU supports pass-through */
IommuType type; /* IOMMU type - AMD/Intel */
QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
};
+bool x86_iommu_ir_supported(X86IOMMUState *s);
+
/* Generic IRQ entry information when interrupt remapping is enabled */
struct X86IOMMUIrq {
/* Used by both IOAPIC/MSI interrupt remapping */
diff --git a/include/hw/ide/ahci.h b/include/hw/ide/ahci.h
index b7bb2b02d6..b44e3000cf 100644
--- a/include/hw/ide/ahci.h
+++ b/include/hw/ide/ahci.h
@@ -73,13 +73,13 @@ typedef struct SysbusAHCIState {
#define ALLWINNER_AHCI_MMIO_OFF 0x80
#define ALLWINNER_AHCI_MMIO_SIZE 0x80
-struct AllwinnerAHCIState {
+typedef struct AllwinnerAHCIState {
/*< private >*/
SysbusAHCIState parent_obj;
/*< public >*/
MemoryRegion mmio;
uint32_t regs[ALLWINNER_AHCI_MMIO_SIZE/4];
-};
+} AllwinnerAHCIState;
#endif /* HW_IDE_AHCI_H */
diff --git a/include/hw/ide/internal.h b/include/hw/ide/internal.h
index 594081e57f..880413ddc7 100644
--- a/include/hw/ide/internal.h
+++ b/include/hw/ide/internal.h
@@ -342,7 +342,7 @@ enum ide_dma_cmd {
extern const char *IDE_DMA_CMD_lookup[IDE_DMA__COUNT];
#define ide_cmd_is_read(s) \
- ((s)->dma_cmd == IDE_DMA_READ)
+ ((s)->dma_cmd == IDE_DMA_READ)
typedef struct IDEBufferedRequest {
QLIST_ENTRY(IDEBufferedRequest) list;
diff --git a/include/hw/input/ps2.h b/include/hw/input/ps2.h
index 213aa16aa3..b60455d4f6 100644
--- a/include/hw/input/ps2.h
+++ b/include/hw/input/ps2.h
@@ -31,6 +31,8 @@
#define PS2_MOUSE_BUTTON_SIDE 0x08
#define PS2_MOUSE_BUTTON_EXTRA 0x10
+typedef struct PS2State PS2State;
+
/* ps2.c */
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
diff --git a/include/hw/intc/intc.h b/include/hw/intc/intc.h
index 27d9828943..fb3e8e621f 100644
--- a/include/hw/intc/intc.h
+++ b/include/hw/intc/intc.h
@@ -15,9 +15,7 @@
INTERFACE_CHECK(InterruptStatsProvider, (obj), \
TYPE_INTERRUPT_STATS_PROVIDER)
-typedef struct InterruptStatsProvider {
- Object parent;
-} InterruptStatsProvider;
+typedef struct InterruptStatsProvider InterruptStatsProvider;
typedef struct InterruptStatsProviderClass {
InterfaceClass parent;
diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h
index 0affe5a4d8..99661d2bf0 100644
--- a/include/hw/ipmi/ipmi.h
+++ b/include/hw/ipmi/ipmi.h
@@ -114,9 +114,7 @@ uint32_t ipmi_next_uuid(void);
#define IPMI_INTERFACE_GET_CLASS(class) \
OBJECT_GET_CLASS(IPMIInterfaceClass, (class), TYPE_IPMI_INTERFACE)
-typedef struct IPMIInterface {
- Object parent;
-} IPMIInterface;
+typedef struct IPMIInterface IPMIInterface;
typedef struct IPMIInterfaceClass {
InterfaceClass parent;
diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h
index b9dbab24b4..e62ac91c19 100644
--- a/include/hw/isa/isa.h
+++ b/include/hw/isa/isa.h
@@ -43,10 +43,6 @@ static inline uint16_t applesmc_port(void)
#define ISADMA(obj) \
INTERFACE_CHECK(IsaDma, (obj), TYPE_ISADMA)
-struct IsaDma {
- Object parent;
-};
-
typedef enum {
ISADMA_TRANSFER_VERIFY,
ISADMA_TRANSFER_READ,
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 67a0af84ac..de8a29603b 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -11,7 +11,22 @@
* On error, errno is also set as appropriate.
*/
int64_t get_image_size(const char *filename);
-int load_image(const char *filename, uint8_t *addr); /* deprecated */
+/**
+ * load_image_size: load an image file into specified buffer
+ * @filename: Path to the image file
+ * @addr: Buffer to load image into
+ * @size: Size of buffer in bytes
+ *
+ * Load an image file from disk into the specified buffer.
+ * If the image is larger than the specified buffer, only
+ * @size bytes are read (this is not considered an error).
+ *
+ * Prefer to use the GLib function g_file_get_contents() rather
+ * than a "get_image_size()/g_malloc()/load_image_size()" sequence.
+ *
+ * Returns the number of bytes read, or -1 on error. On error,
+ * errno is also set as appropriate.
+ */
ssize_t load_image_size(const char *filename, void *addr, size_t size);
/**load_image_targphys_as:
@@ -160,10 +175,15 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp);
int load_aout(const char *filename, hwaddr addr, int max_sz,
int bswap_needed, hwaddr target_page_size);
+#define LOAD_UIMAGE_LOADADDR_INVALID (-1)
+
/** load_uimage_as:
* @filename: Path of uimage file
* @ep: Populated with program entry point. Ignored if NULL.
- * @loadaddr: Populated with the load address. Ignored if NULL.
+ * @loadaddr: load address if none specified in the image or when loading a
+ * ramdisk. Populated with the load address. Ignored if NULL or
+ * LOAD_UIMAGE_LOADADDR_INVALID (images which do not specify a load
+ * address will not be loadable).
* @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL.
* @translate_fn: optional function to translate load addresses
* @translate_opaque: opaque data passed to @translate_fn
diff --git a/include/hw/mem/memory-device.h b/include/hw/mem/memory-device.h
index e904e194d5..0293a96abb 100644
--- a/include/hw/mem/memory-device.h
+++ b/include/hw/mem/memory-device.h
@@ -25,9 +25,7 @@
#define MEMORY_DEVICE(obj) \
INTERFACE_CHECK(MemoryDeviceState, (obj), TYPE_MEMORY_DEVICE)
-typedef struct MemoryDeviceState {
- Object parent_obj;
-} MemoryDeviceState;
+typedef struct MemoryDeviceState MemoryDeviceState;
/**
* MemoryDeviceClass:
diff --git a/include/hw/misc/mips_itu.h b/include/hw/misc/mips_itu.h
index 030eb4ac62..c44e7672b6 100644
--- a/include/hw/misc/mips_itu.h
+++ b/include/hw/misc/mips_itu.h
@@ -66,6 +66,14 @@ typedef struct MIPSITUState {
/* ITC Configuration Tags */
uint64_t ITCAddressMap[ITC_ADDRESSMAP_NUM];
MemoryRegion tag_io;
+
+ /* ITU Control Register */
+ uint64_t icr0;
+
+ /* SAAR */
+ bool saar_present;
+ void *saar;
+
} MIPSITUState;
/* Get ITC Configuration Tag memory region. */
diff --git a/include/hw/misc/nrf51_rng.h b/include/hw/misc/nrf51_rng.h
new file mode 100644
index 0000000000..3d6bf79997
--- /dev/null
+++ b/include/hw/misc/nrf51_rng.h
@@ -0,0 +1,83 @@
+/*
+ * nRF51 Random Number Generator
+ *
+ * QEMU interface:
+ * + Property "period_unfiltered_us": Time between two biased values in
+ * microseconds.
+ * + Property "period_filtered_us": Time between two unbiased values in
+ * microseconds.
+ * + sysbus MMIO regions 0: Memory Region with tasks, events and registers
+ * to be mapped to the peripherals instance address by the SOC.
+ * + Named GPIO output "irq": Interrupt line of the peripheral. Must be
+ * connected to the associated peripheral interrupt line of the NVIC.
+ * + Named GPIO output "eep_valrdy": Event set when new random value is ready
+ * to be read.
+ * + Named GPIO input "tep_start": Task that triggers start of continuous
+ * generation of random values.
+ * + Named GPIO input "tep_stop": Task that ends continuous generation of
+ * random values.
+ *
+ * Accuracy of the peripheral model:
+ * + Stochastic properties of different configurations of the random source
+ * are not modeled.
+ * + Generation of unfiltered and filtered random values take at least the
+ * average generation time stated in the production specification;
+ * non-deterministic generation times are not modeled.
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef NRF51_RNG_H
+#define NRF51_RNG_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#define TYPE_NRF51_RNG "nrf51_soc.rng"
+#define NRF51_RNG(obj) OBJECT_CHECK(NRF51RNGState, (obj), TYPE_NRF51_RNG)
+
+#define NRF51_RNG_SIZE 0x1000
+
+#define NRF51_RNG_TASK_START 0x000
+#define NRF51_RNG_TASK_STOP 0x004
+#define NRF51_RNG_EVENT_VALRDY 0x100
+#define NRF51_RNG_REG_SHORTS 0x200
+#define NRF51_RNG_REG_SHORTS_VALRDY_STOP 0
+#define NRF51_RNG_REG_INTEN 0x300
+#define NRF51_RNG_REG_INTEN_VALRDY 0
+#define NRF51_RNG_REG_INTENSET 0x304
+#define NRF51_RNG_REG_INTENCLR 0x308
+#define NRF51_RNG_REG_CONFIG 0x504
+#define NRF51_RNG_REG_CONFIG_DECEN 0
+#define NRF51_RNG_REG_VALUE 0x508
+
+typedef struct {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ qemu_irq irq;
+
+ /* Event End Points */
+ qemu_irq eep_valrdy;
+
+ QEMUTimer timer;
+
+ /* Time between generation of successive unfiltered values in us */
+ uint16_t period_unfiltered_us;
+ /* Time between generation of successive filtered values in us */
+ uint16_t period_filtered_us;
+
+ uint8_t value;
+
+ uint32_t active;
+ uint32_t event_valrdy;
+ uint32_t shortcut_stop_on_valrdy;
+ uint32_t interrupt_enabled;
+ uint32_t filter_enabled;
+
+} NRF51RNGState;
+
+
+#endif /* NRF51_RNG_H_ */
diff --git a/include/hw/nmi.h b/include/hw/nmi.h
index d092c684a1..ad857f3832 100644
--- a/include/hw/nmi.h
+++ b/include/hw/nmi.h
@@ -34,9 +34,7 @@
#define NMI(obj) \
INTERFACE_CHECK(NMI, (obj), TYPE_NMI)
-typedef struct NMIState {
- Object parent_obj;
-} NMIState;
+typedef struct NMIState NMIState;
typedef struct NMIClass {
InterfaceClass parent_class;
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
index 7c66c3872f..a5a7bf4837 100644
--- a/include/hw/pci-host/spapr.h
+++ b/include/hw/pci-host/spapr.h
@@ -94,12 +94,13 @@ struct sPAPRPHBState {
((1ULL << 32) - SPAPR_PCI_MEM_WIN_BUS_OFFSET)
#define SPAPR_PCI_MEM64_WIN_SIZE 0x10000000000ULL /* 1 TiB */
-/* Without manual configuration, all PCI outbound windows will be
- * within this range */
+/* All PCI outbound windows will be within this range */
#define SPAPR_PCI_BASE (1ULL << 45) /* 32 TiB */
#define SPAPR_PCI_LIMIT (1ULL << 46) /* 64 TiB */
-#define SPAPR_PCI_2_7_MMIO_WIN_SIZE 0xf80000000
+#define SPAPR_MAX_PHBS ((SPAPR_PCI_LIMIT - SPAPR_PCI_BASE) / \
+ SPAPR_PCI_MEM64_WIN_SIZE - 1)
+
#define SPAPR_PCI_IO_WIN_SIZE 0x10000
#define SPAPR_PCI_MSI_WINDOW 0x40000000000ULL
@@ -111,8 +112,6 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
return spapr_qirq(spapr, phb->lsi_table[pin].irq);
}
-PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index);
-
int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt,
uint32_t nr_msis);
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index e6514bba23..d87f5f93e9 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -405,8 +405,10 @@ PCIBus *pci_root_bus_new(DeviceState *parent, const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, const char *typename);
+void pci_root_bus_cleanup(PCIBus *bus);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
+void pci_bus_irqs_cleanup(PCIBus *bus);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
@@ -417,6 +419,7 @@ PCIBus *pci_register_root_bus(DeviceState *parent, const char *name,
MemoryRegion *address_space_io,
uint8_t devfn_min, int nirq,
const char *typename);
+void pci_unregister_root_bus(PCIBus *bus);
void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
@@ -737,6 +740,19 @@ static inline int pci_is_express(const PCIDevice *d)
return d->cap_present & QEMU_PCI_CAP_EXPRESS;
}
+static inline int pci_is_express_downstream_port(const PCIDevice *d)
+{
+ uint8_t type;
+
+ if (!pci_is_express(d) || !d->exp.exp_cap) {
+ return 0;
+ }
+
+ type = pcie_cap_get_type(d);
+
+ return type == PCI_EXP_TYPE_DOWNSTREAM || type == PCI_EXP_TYPE_ROOT_PORT;
+}
+
static inline uint32_t pci_config_size(const PCIDevice *d)
{
return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index cdff7edfd1..ba488818d2 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -99,6 +99,12 @@ void pci_bridge_reset(DeviceState *qdev);
void pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
void pci_bridge_exitfn(PCIDevice *pci_dev);
+void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp);
/*
* before qdev initialization(qdev_init()), this function sets bus_name and
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
index b71e369703..5b82a0d244 100644
--- a/include/hw/pci/pcie.h
+++ b/include/hw/pci/pcie.h
@@ -126,13 +126,18 @@ uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
void pcie_add_capability(PCIDevice *dev,
uint16_t cap_id, uint8_t cap_ver,
uint16_t offset, uint16_t size);
+void pcie_sync_bridge_lnk(PCIDevice *dev);
void pcie_ari_init(PCIDevice *dev, uint16_t offset, uint16_t nextfn);
void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num);
void pcie_ats_init(PCIDevice *dev, uint16_t offset);
-void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp);
-void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp);
+void pcie_cap_slot_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void pcie_cap_slot_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp);
#endif /* QEMU_PCIE_H */
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index 0736014bfd..df242a0caf 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -49,6 +49,10 @@ struct PCIESlot {
/* pci express switch port with slot */
uint8_t chassis;
uint16_t slot;
+
+ PCIExpLinkSpeed speed;
+ PCIExpLinkWidth width;
+
QLIST_ENTRY(PCIESlot) next;
};
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index a95522a13b..ad4e7808b8 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -34,10 +34,29 @@
/* PCI_EXP_LINK{CAP, STA} */
/* link speed */
-#define PCI_EXP_LNK_LS_25 1
+typedef enum PCIExpLinkSpeed {
+ QEMU_PCI_EXP_LNK_2_5GT = 1,
+ QEMU_PCI_EXP_LNK_5GT,
+ QEMU_PCI_EXP_LNK_8GT,
+ QEMU_PCI_EXP_LNK_16GT,
+} PCIExpLinkSpeed;
+
+#define QEMU_PCI_EXP_LNKCAP_MLS(speed) (speed)
+#define QEMU_PCI_EXP_LNKSTA_CLS QEMU_PCI_EXP_LNKCAP_MLS
+
+typedef enum PCIExpLinkWidth {
+ QEMU_PCI_EXP_LNK_X1 = 1,
+ QEMU_PCI_EXP_LNK_X2 = 2,
+ QEMU_PCI_EXP_LNK_X4 = 4,
+ QEMU_PCI_EXP_LNK_X8 = 8,
+ QEMU_PCI_EXP_LNK_X12 = 12,
+ QEMU_PCI_EXP_LNK_X16 = 16,
+ QEMU_PCI_EXP_LNK_X32 = 32,
+} PCIExpLinkWidth;
#define PCI_EXP_LNK_MLW_SHIFT ctz32(PCI_EXP_LNKCAP_MLW)
-#define PCI_EXP_LNK_MLW_1 (1 << PCI_EXP_LNK_MLW_SHIFT)
+#define QEMU_PCI_EXP_LNKCAP_MLW(width) (width << PCI_EXP_LNK_MLW_SHIFT)
+#define QEMU_PCI_EXP_LNKSTA_NLW QEMU_PCI_EXP_LNKCAP_MLW
/* PCI_EXP_LINKCAP */
#define PCI_EXP_LNKCAP_ASPMS_SHIFT ctz32(PCI_EXP_LNKCAP_ASPMS)
diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h
index ee19fecf61..18f6ec1cd5 100644
--- a/include/hw/pci/shpc.h
+++ b/include/hw/pci/shpc.h
@@ -45,10 +45,12 @@ void shpc_free(PCIDevice *dev);
void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
-void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
- Error **errp);
-void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
- DeviceState *dev, Error **errp);
+void shpc_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void shpc_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
+void shpc_device_unplug_request_cb(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp);
extern VMStateInfo shpc_vmstate_info;
#define SHPC_VMSTATE(_field, _type, _test) \
diff --git a/include/hw/pcmcia.h b/include/hw/pcmcia.h
index 79cac9c761..1b4080764f 100644
--- a/include/hw/pcmcia.h
+++ b/include/hw/pcmcia.h
@@ -18,13 +18,13 @@ typedef struct PCMCIASocket {
#define PCMCIA_CARD_CLASS(cls) \
OBJECT_CLASS_CHECK(PCMCIACardClass, cls, TYPE_PCMCIA_CARD)
-struct PCMCIACardState {
+typedef struct PCMCIACardState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
PCMCIASocket *slot;
-};
+} PCMCIACardState;
typedef struct PCMCIACardClass {
/*< private >*/
diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h
index 5eb982197d..dad08fe9be 100644
--- a/include/hw/ppc/openpic.h
+++ b/include/hw/ppc/openpic.h
@@ -20,6 +20,8 @@ enum {
OPENPIC_OUTPUT_NB,
};
+typedef struct IrqLines { qemu_irq irq[OPENPIC_OUTPUT_NB]; } IrqLines;
+
#define OPENPIC_MODEL_RAVEN 0
#define OPENPIC_MODEL_FSL_MPIC_20 1
#define OPENPIC_MODEL_FSL_MPIC_42 2
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 86d5f54e54..6b65397b7e 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -98,7 +98,7 @@ typedef struct PnvChipClass {
DeviceRealize parent_realize;
uint32_t (*core_pir)(PnvChip *chip, uint32_t core_id);
- Object *(*intc_create)(PnvChip *chip, Object *child, Error **errp);
+ void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
ISABus *(*isa_create)(PnvChip *chip, Error **errp);
} PnvChipClass;
diff --git a/include/hw/ppc/pnv_psi.h b/include/hw/ppc/pnv_psi.h
index f6af5eae1f..64ac73512e 100644
--- a/include/hw/ppc/pnv_psi.h
+++ b/include/hw/ppc/pnv_psi.h
@@ -40,6 +40,7 @@ typedef struct PnvPsi {
/* Interrupt generation */
ICSState ics;
+ qemu_irq *qirqs;
/* Registers */
uint64_t regs[PSIHB_XSCOM_MAX];
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 6279711fe8..a947a0a0dc 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -8,14 +8,16 @@
#include "hw/mem/pc-dimm.h"
#include "hw/ppc/spapr_ovec.h"
#include "hw/ppc/spapr_irq.h"
+#include "hw/ppc/spapr_xive.h" /* For sPAPRXive */
+#include "hw/ppc/xics.h" /* For ICSState */
struct VIOsPAPRBus;
struct sPAPRPHBState;
struct sPAPRNVRAM;
+
typedef struct sPAPREventLogEntry sPAPREventLogEntry;
typedef struct sPAPREventSource sPAPREventSource;
typedef struct sPAPRPendingHPT sPAPRPendingHPT;
-typedef struct ICSState ICSState;
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
#define SPAPR_ENTRY_POINT 0x100
@@ -102,6 +104,7 @@ struct sPAPRMachineClass {
/*< public >*/
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
+ bool update_dt_enabled; /* enable KVMPPC_H_UPDATE_DT */
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
bool pre_2_10_has_unused_icps;
bool legacy_irq_allocation;
@@ -138,6 +141,9 @@ struct sPAPRMachineState {
int vrma_adjust;
ssize_t rtas_size;
void *rtas_blob;
+ uint32_t fdt_size;
+ uint32_t fdt_initial_size;
+ void *fdt_blob;
long kernel_size;
bool kernel_le;
uint32_t initrd_base;
@@ -175,6 +181,9 @@ struct sPAPRMachineState {
const char *icp_type;
int32_t irq_map_nr;
unsigned long *irq_map;
+ sPAPRXive *xive;
+ sPAPRIrq *irq;
+ qemu_irq *qirqs;
bool cmd_line_caps[SPAPR_CAP_NUM];
sPAPRCapabilities def, eff, mig;
@@ -441,6 +450,7 @@ struct sPAPRMachineState {
#define H_GET_EM_PARMS 0x2B8
#define H_SET_MPP 0x2D0
#define H_GET_MPP 0x2D4
+#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
#define H_XIRR_X 0x2FC
#define H_RANDOM 0x300
#define H_SET_MODE 0x31C
@@ -450,7 +460,20 @@ struct sPAPRMachineState {
#define H_INVALIDATE_PID 0x378
#define H_REGISTER_PROC_TBL 0x37C
#define H_SIGNAL_SYS_RESET 0x380
-#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET
+
+#define H_INT_GET_SOURCE_INFO 0x3A8
+#define H_INT_SET_SOURCE_CONFIG 0x3AC
+#define H_INT_GET_SOURCE_CONFIG 0x3B0
+#define H_INT_GET_QUEUE_INFO 0x3B4
+#define H_INT_SET_QUEUE_CONFIG 0x3B8
+#define H_INT_GET_QUEUE_CONFIG 0x3BC
+#define H_INT_SET_OS_REPORTING_LINE 0x3C0
+#define H_INT_GET_OS_REPORTING_LINE 0x3C4
+#define H_INT_ESB 0x3C8
+#define H_INT_SYNC 0x3CC
+#define H_INT_RESET 0x3D0
+
+#define MAX_HCALL_OPCODE H_INT_RESET
/* The hcalls above are standardized in PAPR and implemented by pHyp
* as well.
@@ -464,7 +487,8 @@ struct sPAPRMachineState {
#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
/* Client Architecture support */
#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2)
-#define KVMPPC_HCALL_MAX KVMPPC_H_CAS
+#define KVMPPC_H_UPDATE_DT (KVMPPC_HCALL_BASE + 0x3)
+#define KVMPPC_HCALL_MAX KVMPPC_H_UPDATE_DT
typedef struct sPAPRDeviceTreeUpdateHeader {
uint32_t version_id;
@@ -737,6 +761,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
Error **errp);
void spapr_clear_pending_events(sPAPRMachineState *spapr);
+int spapr_max_server_number(sPAPRMachineState *spapr);
/* CPU and LMB DRC release callbacks. */
void spapr_core_release(DeviceState *dev);
@@ -808,5 +833,11 @@ int spapr_caps_post_migration(sPAPRMachineState *spapr);
void spapr_check_pagesize(sPAPRMachineState *spapr, hwaddr pagesize,
Error **errp);
+/*
+ * XIVE definitions
+ */
+#define SPAPR_OV5_XIVE_LEGACY 0x0
+#define SPAPR_OV5_XIVE_EXPLOIT 0x40
+#define SPAPR_OV5_XIVE_BOTH 0x80 /* Only to advertise on the platform */
#endif /* HW_SPAPR_H */
diff --git a/include/hw/ppc/spapr_irq.h b/include/hw/ppc/spapr_irq.h
index a467ce696e..14b02c3aca 100644
--- a/include/hw/ppc/spapr_irq.h
+++ b/include/hw/ppc/spapr_irq.h
@@ -13,6 +13,7 @@
/*
* IRQ range offsets per device type
*/
+#define SPAPR_IRQ_IPI 0x0
#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */
#define SPAPR_IRQ_HOTPLUG 0x1001
#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */
@@ -32,20 +33,33 @@ void spapr_irq_msi_reset(sPAPRMachineState *spapr);
typedef struct sPAPRIrq {
uint32_t nr_irqs;
uint32_t nr_msis;
+ uint8_t ov5;
void (*init)(sPAPRMachineState *spapr, Error **errp);
int (*claim)(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void (*free)(sPAPRMachineState *spapr, int irq, int num);
qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
+ void (*dt_populate)(sPAPRMachineState *spapr, uint32_t nr_servers,
+ void *fdt, uint32_t phandle);
+ void (*cpu_intc_create)(sPAPRMachineState *spapr, PowerPCCPU *cpu,
+ Error **errp);
+ int (*post_load)(sPAPRMachineState *spapr, int version_id);
+ void (*reset)(sPAPRMachineState *spapr, Error **errp);
+ void (*set_irq)(void *opaque, int srcno, int val);
} sPAPRIrq;
extern sPAPRIrq spapr_irq_xics;
extern sPAPRIrq spapr_irq_xics_legacy;
+extern sPAPRIrq spapr_irq_xive;
+extern sPAPRIrq spapr_irq_dual;
+void spapr_irq_init(sPAPRMachineState *spapr, Error **errp);
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
+int spapr_irq_post_load(sPAPRMachineState *spapr, int version_id);
+void spapr_irq_reset(sPAPRMachineState *spapr, Error **errp);
/*
* XICS legacy routines
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
new file mode 100644
index 0000000000..9bec9192e4
--- /dev/null
+++ b/include/hw/ppc/spapr_xive.h
@@ -0,0 +1,50 @@
+/*
+ * QEMU PowerPC sPAPR XIVE interrupt controller model
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_SPAPR_XIVE_H
+#define PPC_SPAPR_XIVE_H
+
+#include "hw/ppc/xive.h"
+
+#define TYPE_SPAPR_XIVE "spapr-xive"
+#define SPAPR_XIVE(obj) OBJECT_CHECK(sPAPRXive, (obj), TYPE_SPAPR_XIVE)
+
+typedef struct sPAPRXive {
+ XiveRouter parent;
+
+ /* Internal interrupt source for IPIs and virtual devices */
+ XiveSource source;
+ hwaddr vc_base;
+
+ /* END ESB MMIOs */
+ XiveENDSource end_source;
+ hwaddr end_base;
+
+ /* Routing table */
+ XiveEAS *eat;
+ uint32_t nr_irqs;
+ XiveEND *endt;
+ uint32_t nr_ends;
+
+ /* TIMA mapping address */
+ hwaddr tm_base;
+ MemoryRegion tm_mmio;
+} sPAPRXive;
+
+bool spapr_xive_irq_claim(sPAPRXive *xive, uint32_t lisn, bool lsi);
+bool spapr_xive_irq_free(sPAPRXive *xive, uint32_t lisn);
+void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon);
+
+void spapr_xive_hcall_init(sPAPRMachineState *spapr);
+void spapr_dt_xive(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+ uint32_t phandle);
+void spapr_xive_set_tctx_os_cam(XiveTCTX *tctx);
+void spapr_xive_mmio_set_enabled(sPAPRXive *xive, bool enable);
+
+#endif /* PPC_SPAPR_XIVE_H */
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
index 9958443d19..fad786e8b2 100644
--- a/include/hw/ppc/xics.h
+++ b/include/hw/ppc/xics.h
@@ -131,7 +131,6 @@ struct ICSState {
/*< public >*/
uint32_t nr_irqs;
uint32_t offset;
- qemu_irq *qirqs;
ICSIRQState *irqs;
XICSFabric *xics;
};
@@ -140,8 +139,7 @@ struct ICSState {
static inline bool ics_valid_irq(ICSState *ics, uint32_t nr)
{
- return (ics->offset != 0) && (nr >= ics->offset)
- && (nr < (ics->offset + ics->nr_irqs));
+ return (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs));
}
struct ICSIRQState {
@@ -181,8 +179,6 @@ typedef struct XICSFabricClass {
ICPState *(*icp_get)(XICSFabric *xi, int server);
} XICSFabricClass;
-void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle);
-
ICPState *xics_icp_get(XICSFabric *xi, int server);
/* Internal XICS interfaces */
@@ -194,6 +190,8 @@ void icp_eoi(ICPState *icp, uint32_t xirr);
void ics_simple_write_xive(ICSState *ics, int nr, int server,
uint8_t priority, uint8_t saved_priority);
+void ics_simple_set_irq(void *opaque, int srcno, int val);
+void ics_kvm_set_irq(void *opaque, int srcno, int val);
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
void icp_pic_print_info(ICPState *icp, Monitor *mon);
@@ -202,11 +200,6 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon);
void ics_resend(ICSState *ics);
void icp_resend(ICPState *ss);
-typedef struct sPAPRMachineState sPAPRMachineState;
-
-int xics_kvm_init(sPAPRMachineState *spapr, Error **errp);
-void xics_spapr_init(sPAPRMachineState *spapr);
-
Object *icp_create(Object *cpu, const char *type, XICSFabric *xi,
Error **errp);
diff --git a/include/hw/ppc/xics_spapr.h b/include/hw/ppc/xics_spapr.h
new file mode 100644
index 0000000000..b1ab27d022
--- /dev/null
+++ b/include/hw/ppc/xics_spapr.h
@@ -0,0 +1,37 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010, 2011 David Gibson, IBM Corporation.
+ *
+ * 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 XICS_SPAPR_H
+#define XICS_SPAPR_H
+
+#include "hw/ppc/spapr.h"
+
+void spapr_dt_xics(sPAPRMachineState *spapr, uint32_t nr_servers, void *fdt,
+ uint32_t phandle);
+int xics_kvm_init(sPAPRMachineState *spapr, Error **errp);
+void xics_spapr_init(sPAPRMachineState *spapr);
+
+#endif /* XICS_SPAPR_H */
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
new file mode 100644
index 0000000000..ec23253ba4
--- /dev/null
+++ b/include/hw/ppc/xive.h
@@ -0,0 +1,424 @@
+/*
+ * QEMU PowerPC XIVE interrupt controller model
+ *
+ *
+ * The POWER9 processor comes with a new interrupt controller, called
+ * XIVE as "eXternal Interrupt Virtualization Engine".
+ *
+ * = Overall architecture
+ *
+ *
+ * XIVE Interrupt Controller
+ * +------------------------------------+ IPIs
+ * | +---------+ +---------+ +--------+ | +-------+
+ * | |VC | |CQ | |PC |----> | CORES |
+ * | | esb | | | | |----> | |
+ * | | eas | | Bridge | | tctx |----> | |
+ * | |SC end | | | | nvt | | | |
+ * +------+ | +---------+ +----+----+ +--------+ | +-+-+-+-+
+ * | RAM | +------------------|-----------------+ | | |
+ * | | | | | |
+ * | | | | | |
+ * | | +--------------------v------------------------v-v-v--+ other
+ * | <--+ Power Bus +--> chips
+ * | esb | +---------+-----------------------+------------------+
+ * | eas | | |
+ * | end | +--|------+ |
+ * | nvt | +----+----+ | +----+----+
+ * +------+ |SC | | |SC |
+ * | | | | |
+ * | PQ-bits | | | PQ-bits |
+ * | local |-+ | in VC |
+ * +---------+ +---------+
+ * PCIe NX,NPU,CAPI
+ *
+ * SC: Source Controller (aka. IVSE)
+ * VC: Virtualization Controller (aka. IVRE)
+ * PC: Presentation Controller (aka. IVPE)
+ * CQ: Common Queue (Bridge)
+ *
+ * PQ-bits: 2 bits source state machine (P:pending Q:queued)
+ * esb: Event State Buffer (Array of PQ bits in an IVSE)
+ * eas: Event Assignment Structure
+ * end: Event Notification Descriptor
+ * nvt: Notification Virtual Target
+ * tctx: Thread interrupt Context
+ *
+ *
+ * The XIVE IC is composed of three sub-engines :
+ *
+ * - Interrupt Virtualization Source Engine (IVSE), or Source
+ * Controller (SC). These are found in PCI PHBs, in the PSI host
+ * bridge controller, but also inside the main controller for the
+ * core IPIs and other sub-chips (NX, CAP, NPU) of the
+ * chip/processor. They are configured to feed the IVRE with events.
+ *
+ * - Interrupt Virtualization Routing Engine (IVRE) or Virtualization
+ * Controller (VC). Its job is to match an event source with an
+ * Event Notification Descriptor (END).
+ *
+ * - Interrupt Virtualization Presentation Engine (IVPE) or
+ * Presentation Controller (PC). It maintains the interrupt context
+ * state of each thread and handles the delivery of the external
+ * exception to the thread.
+ *
+ * In XIVE 1.0, the sub-engines used to be referred as:
+ *
+ * SC Source Controller
+ * VC Virtualization Controller
+ * PC Presentation Controller
+ * CQ Common Queue (PowerBUS Bridge)
+ *
+ *
+ * = XIVE internal tables
+ *
+ * Each of the sub-engines uses a set of tables to redirect exceptions
+ * from event sources to CPU threads.
+ *
+ * +-------+
+ * User or OS | EQ |
+ * or +------>|entries|
+ * Hypervisor | | .. |
+ * Memory | +-------+
+ * | ^
+ * | |
+ * +-------------------------------------------------+
+ * | |
+ * Hypervisor +------+ +---+--+ +---+--+ +------+
+ * Memory | ESB | | EAT | | ENDT | | NVTT |
+ * (skiboot) +----+-+ +----+-+ +----+-+ +------+
+ * ^ | ^ | ^ | ^
+ * | | | | | | |
+ * +-------------------------------------------------+
+ * | | | | | | |
+ * | | | | | | |
+ * +----|--|--------|--|--------|--|-+ +-|-----+ +------+
+ * | | | | | | | | | | tctx| |Thread|
+ * IPI or --> | + v + v + v |---| + .. |-----> |
+ * HW events --> | | | | | |
+ * IVSE | IVRE | | IVPE | +------+
+ * +---------------------------------+ +-------+
+ *
+ *
+ *
+ * The IVSE have a 2-bits state machine, P for pending and Q for queued,
+ * for each source that allows events to be triggered. They are stored in
+ * an Event State Buffer (ESB) array and can be controlled by MMIOs.
+ *
+ * If the event is let through, the IVRE looks up in the Event Assignment
+ * Structure (EAS) table for an Event Notification Descriptor (END)
+ * configured for the source. Each Event Notification Descriptor defines
+ * a notification path to a CPU and an in-memory Event Queue, in which
+ * will be enqueued an EQ data for the OS to pull.
+ *
+ * The IVPE determines if a Notification Virtual Target (NVT) can
+ * handle the event by scanning the thread contexts of the VCPUs
+ * dispatched on the processor HW threads. It maintains the state of
+ * the thread interrupt context (TCTX) of each thread in a NVT table.
+ *
+ * = Acronyms
+ *
+ * Description In XIVE 1.0, used to be referred as
+ *
+ * EAS Event Assignment Structure IVE Interrupt Virt. Entry
+ * EAT Event Assignment Table IVT Interrupt Virt. Table
+ * ENDT Event Notif. Descriptor Table EQDT Event Queue Desc. Table
+ * EQ Event Queue same
+ * ESB Event State Buffer SBE State Bit Entry
+ * NVT Notif. Virtual Target VPD Virtual Processor Desc.
+ * NVTT Notif. Virtual Target Table VPDT Virtual Processor Desc. Table
+ * TCTX Thread interrupt Context
+ *
+ *
+ * Copyright (c) 2017-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef PPC_XIVE_H
+#define PPC_XIVE_H
+
+#include "hw/qdev-core.h"
+#include "hw/sysbus.h"
+#include "hw/ppc/xive_regs.h"
+
+/*
+ * XIVE Fabric (Interface between Source and Router)
+ */
+
+typedef struct XiveNotifier {
+ Object parent;
+} XiveNotifier;
+
+#define TYPE_XIVE_NOTIFIER "xive-notifier"
+#define XIVE_NOTIFIER(obj) \
+ OBJECT_CHECK(XiveNotifier, (obj), TYPE_XIVE_NOTIFIER)
+#define XIVE_NOTIFIER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(XiveNotifierClass, (klass), TYPE_XIVE_NOTIFIER)
+#define XIVE_NOTIFIER_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XiveNotifierClass, (obj), TYPE_XIVE_NOTIFIER)
+
+typedef struct XiveNotifierClass {
+ InterfaceClass parent;
+ void (*notify)(XiveNotifier *xn, uint32_t lisn);
+} XiveNotifierClass;
+
+/*
+ * XIVE Interrupt Source
+ */
+
+#define TYPE_XIVE_SOURCE "xive-source"
+#define XIVE_SOURCE(obj) OBJECT_CHECK(XiveSource, (obj), TYPE_XIVE_SOURCE)
+
+/*
+ * XIVE Interrupt Source characteristics, which define how the ESB are
+ * controlled.
+ */
+#define XIVE_SRC_H_INT_ESB 0x1 /* ESB managed with hcall H_INT_ESB */
+#define XIVE_SRC_STORE_EOI 0x2 /* Store EOI supported */
+
+typedef struct XiveSource {
+ DeviceState parent;
+
+ /* IRQs */
+ uint32_t nr_irqs;
+ unsigned long *lsi_map;
+
+ /* PQ bits and LSI assertion bit */
+ uint8_t *status;
+
+ /* ESB memory region */
+ uint64_t esb_flags;
+ uint32_t esb_shift;
+ MemoryRegion esb_mmio;
+
+ XiveNotifier *xive;
+} XiveSource;
+
+/*
+ * ESB MMIO setting. Can be one page, for both source triggering and
+ * source management, or two different pages. See below for magic
+ * values.
+ */
+#define XIVE_ESB_4K 12 /* PSI HB only */
+#define XIVE_ESB_4K_2PAGE 13
+#define XIVE_ESB_64K 16
+#define XIVE_ESB_64K_2PAGE 17
+
+static inline bool xive_source_esb_has_2page(XiveSource *xsrc)
+{
+ return xsrc->esb_shift == XIVE_ESB_64K_2PAGE ||
+ xsrc->esb_shift == XIVE_ESB_4K_2PAGE;
+}
+
+/* The trigger page is always the first/even page */
+static inline hwaddr xive_source_esb_page(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+ return (1ull << xsrc->esb_shift) * srcno;
+}
+
+/* In a two pages ESB MMIO setting, the odd page is for management */
+static inline hwaddr xive_source_esb_mgmt(XiveSource *xsrc, int srcno)
+{
+ hwaddr addr = xive_source_esb_page(xsrc, srcno);
+
+ if (xive_source_esb_has_2page(xsrc)) {
+ addr += (1 << (xsrc->esb_shift - 1));
+ }
+
+ return addr;
+}
+
+/*
+ * Each interrupt source has a 2-bit state machine which can be
+ * controlled by MMIO. P indicates that an interrupt is pending (has
+ * been sent to a queue and is waiting for an EOI). Q indicates that
+ * the interrupt has been triggered while pending.
+ *
+ * This acts as a coalescing mechanism in order to guarantee that a
+ * given interrupt only occurs at most once in a queue.
+ *
+ * When doing an EOI, the Q bit will indicate if the interrupt
+ * needs to be re-triggered.
+ */
+#define XIVE_STATUS_ASSERTED 0x4 /* Extra bit for LSI */
+#define XIVE_ESB_VAL_P 0x2
+#define XIVE_ESB_VAL_Q 0x1
+
+#define XIVE_ESB_RESET 0x0
+#define XIVE_ESB_PENDING XIVE_ESB_VAL_P
+#define XIVE_ESB_QUEUED (XIVE_ESB_VAL_P | XIVE_ESB_VAL_Q)
+#define XIVE_ESB_OFF XIVE_ESB_VAL_Q
+
+/*
+ * "magic" Event State Buffer (ESB) MMIO offsets.
+ *
+ * The following offsets into the ESB MMIO allow to read or manipulate
+ * the PQ bits. They must be used with an 8-byte load instruction.
+ * They all return the previous state of the interrupt (atomically).
+ *
+ * Additionally, some ESB pages support doing an EOI via a store and
+ * some ESBs support doing a trigger via a separate trigger page.
+ */
+#define XIVE_ESB_STORE_EOI 0x400 /* Store */
+#define XIVE_ESB_LOAD_EOI 0x000 /* Load */
+#define XIVE_ESB_GET 0x800 /* Load */
+#define XIVE_ESB_SET_PQ_00 0xc00 /* Load */
+#define XIVE_ESB_SET_PQ_01 0xd00 /* Load */
+#define XIVE_ESB_SET_PQ_10 0xe00 /* Load */
+#define XIVE_ESB_SET_PQ_11 0xf00 /* Load */
+
+uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno);
+uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);
+
+void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset,
+ Monitor *mon);
+
+static inline bool xive_source_irq_is_lsi(XiveSource *xsrc, uint32_t srcno)
+{
+ assert(srcno < xsrc->nr_irqs);
+ return test_bit(srcno, xsrc->lsi_map);
+}
+
+static inline void xive_source_irq_set(XiveSource *xsrc, uint32_t srcno,
+ bool lsi)
+{
+ assert(srcno < xsrc->nr_irqs);
+ if (lsi) {
+ bitmap_set(xsrc->lsi_map, srcno, 1);
+ }
+}
+
+void xive_source_set_irq(void *opaque, int srcno, int val);
+
+/*
+ * XIVE Router
+ */
+
+typedef struct XiveRouter {
+ SysBusDevice parent;
+} XiveRouter;
+
+#define TYPE_XIVE_ROUTER "xive-router"
+#define XIVE_ROUTER(obj) \
+ OBJECT_CHECK(XiveRouter, (obj), TYPE_XIVE_ROUTER)
+#define XIVE_ROUTER_CLASS(klass) \
+ OBJECT_CLASS_CHECK(XiveRouterClass, (klass), TYPE_XIVE_ROUTER)
+#define XIVE_ROUTER_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XiveRouterClass, (obj), TYPE_XIVE_ROUTER)
+
+typedef struct XiveRouterClass {
+ SysBusDeviceClass parent;
+
+ /* XIVE table accessors */
+ int (*get_eas)(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
+ XiveEAS *eas);
+ int (*get_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end);
+ int (*write_end)(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
+ int (*get_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt);
+ int (*write_nvt)(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt, uint8_t word_number);
+} XiveRouterClass;
+
+void xive_eas_pic_print_info(XiveEAS *eas, uint32_t lisn, Monitor *mon);
+
+int xive_router_get_eas(XiveRouter *xrtr, uint8_t eas_blk, uint32_t eas_idx,
+ XiveEAS *eas);
+int xive_router_get_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end);
+int xive_router_write_end(XiveRouter *xrtr, uint8_t end_blk, uint32_t end_idx,
+ XiveEND *end, uint8_t word_number);
+int xive_router_get_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt);
+int xive_router_write_nvt(XiveRouter *xrtr, uint8_t nvt_blk, uint32_t nvt_idx,
+ XiveNVT *nvt, uint8_t word_number);
+
+
+/*
+ * XIVE END ESBs
+ */
+
+#define TYPE_XIVE_END_SOURCE "xive-end-source"
+#define XIVE_END_SOURCE(obj) \
+ OBJECT_CHECK(XiveENDSource, (obj), TYPE_XIVE_END_SOURCE)
+
+typedef struct XiveENDSource {
+ DeviceState parent;
+
+ uint32_t nr_ends;
+ uint8_t block_id;
+
+ /* ESB memory region */
+ uint32_t esb_shift;
+ MemoryRegion esb_mmio;
+
+ XiveRouter *xrtr;
+} XiveENDSource;
+
+/*
+ * For legacy compatibility, the exceptions define up to 256 different
+ * priorities. P9 implements only 9 levels : 8 active levels [0 - 7]
+ * and the least favored level 0xFF.
+ */
+#define XIVE_PRIORITY_MAX 7
+
+void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon);
+void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon);
+
+/*
+ * XIVE Thread interrupt Management (TM) context
+ */
+
+#define TYPE_XIVE_TCTX "xive-tctx"
+#define XIVE_TCTX(obj) OBJECT_CHECK(XiveTCTX, (obj), TYPE_XIVE_TCTX)
+
+/*
+ * XIVE Thread interrupt Management register rings :
+ *
+ * QW-0 User event-based exception state
+ * QW-1 O/S OS context for priority management, interrupt acks
+ * QW-2 Pool hypervisor pool context for virtual processors dispatched
+ * QW-3 Physical physical thread context and security context
+ */
+#define XIVE_TM_RING_COUNT 4
+#define XIVE_TM_RING_SIZE 0x10
+
+typedef struct XiveTCTX {
+ DeviceState parent_obj;
+
+ CPUState *cs;
+ qemu_irq output;
+
+ uint8_t regs[XIVE_TM_RING_COUNT * XIVE_TM_RING_SIZE];
+} XiveTCTX;
+
+/*
+ * XIVE Thread Interrupt Management Aera (TIMA)
+ *
+ * This region gives access to the registers of the thread interrupt
+ * management context. It is four page wide, each page providing a
+ * different view of the registers. The page with the lower offset is
+ * the most privileged and gives access to the entire context.
+ */
+#define XIVE_TM_HW_PAGE 0x0
+#define XIVE_TM_HV_PAGE 0x1
+#define XIVE_TM_OS_PAGE 0x2
+#define XIVE_TM_USER_PAGE 0x3
+
+extern const MemoryRegionOps xive_tm_ops;
+
+void xive_tctx_pic_print_info(XiveTCTX *tctx, Monitor *mon);
+Object *xive_tctx_create(Object *cpu, XiveRouter *xrtr, Error **errp);
+
+static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx)
+{
+ return (nvt_blk << 19) | nvt_idx;
+}
+
+#endif /* PPC_XIVE_H */
diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
new file mode 100644
index 0000000000..bf36678a24
--- /dev/null
+++ b/include/hw/ppc/xive_regs.h
@@ -0,0 +1,235 @@
+/*
+ * QEMU PowerPC XIVE internal structure definitions
+ *
+ *
+ * The XIVE structures are accessed by the HW and their format is
+ * architected to be big-endian. Some macros are provided to ease
+ * access to the different fields.
+ *
+ *
+ * Copyright (c) 2016-2018, IBM Corporation.
+ *
+ * This code is licensed under the GPL version 2 or later. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef PPC_XIVE_REGS_H
+#define PPC_XIVE_REGS_H
+
+/*
+ * Interrupt source number encoding on PowerBUS
+ */
+#define XIVE_SRCNO_BLOCK(srcno) (((srcno) >> 28) & 0xf)
+#define XIVE_SRCNO_INDEX(srcno) ((srcno) & 0x0fffffff)
+#define XIVE_SRCNO(blk, idx) ((uint32_t)(blk) << 28 | (idx))
+
+#define TM_SHIFT 16
+
+/* TM register offsets */
+#define TM_QW0_USER 0x000 /* All rings */
+#define TM_QW1_OS 0x010 /* Ring 0..2 */
+#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
+#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
+
+/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
+#define TM_NSR 0x0 /* + + - + */
+#define TM_CPPR 0x1 /* - + - + */
+#define TM_IPB 0x2 /* - + + + */
+#define TM_LSMFB 0x3 /* - + + + */
+#define TM_ACK_CNT 0x4 /* - + - - */
+#define TM_INC 0x5 /* - + - + */
+#define TM_AGE 0x6 /* - + - + */
+#define TM_PIPR 0x7 /* - + - + */
+
+#define TM_WORD0 0x0
+#define TM_WORD1 0x4
+
+/*
+ * QW word 2 contains the valid bit at the top and other fields
+ * depending on the QW.
+ */
+#define TM_WORD2 0x8
+#define TM_QW0W2_VU PPC_BIT32(0)
+#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1, 31) /* XX 2,31 ? */
+#define TM_QW1W2_VO PPC_BIT32(0)
+#define TM_QW1W2_OS_CAM PPC_BITMASK32(8, 31)
+#define TM_QW2W2_VP PPC_BIT32(0)
+#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8, 31)
+#define TM_QW3W2_VT PPC_BIT32(0)
+#define TM_QW3W2_LP PPC_BIT32(6)
+#define TM_QW3W2_LE PPC_BIT32(7)
+#define TM_QW3W2_T PPC_BIT32(31)
+
+/*
+ * In addition to normal loads to "peek" and writes (only when invalid)
+ * using 4 and 8 bytes accesses, the above registers support these
+ * "special" byte operations:
+ *
+ * - Byte load from QW0[NSR] - User level NSR (EBB)
+ * - Byte store to QW0[NSR] - User level NSR (EBB)
+ * - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
+ * - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
+ * otherwise VT||0000000
+ * - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
+ *
+ * Then we have all these "special" CI ops at these offset that trigger
+ * all sorts of side effects:
+ */
+#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
+#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
+#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */
+#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user
+ * context */
+#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
+#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS
+ * context to reg */
+#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate Pool
+ * context to reg*/
+#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
+#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd
+ * line */
+#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
+#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even
+ * line */
+#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
+/* XXX more... */
+
+/* NSR fields for the various QW ack types */
+#define TM_QW0_NSR_EB PPC_BIT8(0)
+#define TM_QW1_NSR_EO PPC_BIT8(0)
+#define TM_QW3_NSR_HE PPC_BITMASK8(0, 1)
+#define TM_QW3_NSR_HE_NONE 0
+#define TM_QW3_NSR_HE_POOL 1
+#define TM_QW3_NSR_HE_PHYS 2
+#define TM_QW3_NSR_HE_LSI 3
+#define TM_QW3_NSR_I PPC_BIT8(2)
+#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3, 7)
+
+/*
+ * EAS (Event Assignment Structure)
+ *
+ * One per interrupt source. Targets an interrupt to a given Event
+ * Notification Descriptor (END) and provides the corresponding
+ * logical interrupt number (END data)
+ */
+typedef struct XiveEAS {
+ /*
+ * Use a single 64-bit definition to make it easier to perform
+ * atomic updates
+ */
+ uint64_t w;
+#define EAS_VALID PPC_BIT(0)
+#define EAS_END_BLOCK PPC_BITMASK(4, 7) /* Destination END block# */
+#define EAS_END_INDEX PPC_BITMASK(8, 31) /* Destination END index */
+#define EAS_MASKED PPC_BIT(32) /* Masked */
+#define EAS_END_DATA PPC_BITMASK(33, 63) /* Data written to the END */
+} XiveEAS;
+
+#define xive_eas_is_valid(eas) (be64_to_cpu((eas)->w) & EAS_VALID)
+#define xive_eas_is_masked(eas) (be64_to_cpu((eas)->w) & EAS_MASKED)
+
+static inline uint64_t xive_get_field64(uint64_t mask, uint64_t word)
+{
+ return (be64_to_cpu(word) & mask) >> ctz64(mask);
+}
+
+static inline uint64_t xive_set_field64(uint64_t mask, uint64_t word,
+ uint64_t value)
+{
+ uint64_t tmp =
+ (be64_to_cpu(word) & ~mask) | ((value << ctz64(mask)) & mask);
+ return cpu_to_be64(tmp);
+}
+
+static inline uint32_t xive_get_field32(uint32_t mask, uint32_t word)
+{
+ return (be32_to_cpu(word) & mask) >> ctz32(mask);
+}
+
+static inline uint32_t xive_set_field32(uint32_t mask, uint32_t word,
+ uint32_t value)
+{
+ uint32_t tmp =
+ (be32_to_cpu(word) & ~mask) | ((value << ctz32(mask)) & mask);
+ return cpu_to_be32(tmp);
+}
+
+/* Event Notification Descriptor (END) */
+typedef struct XiveEND {
+ uint32_t w0;
+#define END_W0_VALID PPC_BIT32(0) /* "v" bit */
+#define END_W0_ENQUEUE PPC_BIT32(1) /* "q" bit */
+#define END_W0_UCOND_NOTIFY PPC_BIT32(2) /* "n" bit */
+#define END_W0_BACKLOG PPC_BIT32(3) /* "b" bit */
+#define END_W0_PRECL_ESC_CTL PPC_BIT32(4) /* "p" bit */
+#define END_W0_ESCALATE_CTL PPC_BIT32(5) /* "e" bit */
+#define END_W0_UNCOND_ESCALATE PPC_BIT32(6) /* "u" bit - DD2.0 */
+#define END_W0_SILENT_ESCALATE PPC_BIT32(7) /* "s" bit - DD2.0 */
+#define END_W0_QSIZE PPC_BITMASK32(12, 15)
+#define END_W0_SW0 PPC_BIT32(16)
+#define END_W0_FIRMWARE END_W0_SW0 /* Owned by FW */
+#define END_QSIZE_4K 0
+#define END_QSIZE_64K 4
+#define END_W0_HWDEP PPC_BITMASK32(24, 31)
+ uint32_t w1;
+#define END_W1_ESn PPC_BITMASK32(0, 1)
+#define END_W1_ESn_P PPC_BIT32(0)
+#define END_W1_ESn_Q PPC_BIT32(1)
+#define END_W1_ESe PPC_BITMASK32(2, 3)
+#define END_W1_ESe_P PPC_BIT32(2)
+#define END_W1_ESe_Q PPC_BIT32(3)
+#define END_W1_GENERATION PPC_BIT32(9)
+#define END_W1_PAGE_OFF PPC_BITMASK32(10, 31)
+ uint32_t w2;
+#define END_W2_MIGRATION_REG PPC_BITMASK32(0, 3)
+#define END_W2_OP_DESC_HI PPC_BITMASK32(4, 31)
+ uint32_t w3;
+#define END_W3_OP_DESC_LO PPC_BITMASK32(0, 31)
+ uint32_t w4;
+#define END_W4_ESC_END_BLOCK PPC_BITMASK32(4, 7)
+#define END_W4_ESC_END_INDEX PPC_BITMASK32(8, 31)
+ uint32_t w5;
+#define END_W5_ESC_END_DATA PPC_BITMASK32(1, 31)
+ uint32_t w6;
+#define END_W6_FORMAT_BIT PPC_BIT32(8)
+#define END_W6_NVT_BLOCK PPC_BITMASK32(9, 12)
+#define END_W6_NVT_INDEX PPC_BITMASK32(13, 31)
+ uint32_t w7;
+#define END_W7_F0_IGNORE PPC_BIT32(0)
+#define END_W7_F0_BLK_GROUPING PPC_BIT32(1)
+#define END_W7_F0_PRIORITY PPC_BITMASK32(8, 15)
+#define END_W7_F1_WAKEZ PPC_BIT32(0)
+#define END_W7_F1_LOG_SERVER_ID PPC_BITMASK32(1, 31)
+} XiveEND;
+
+#define xive_end_is_valid(end) (be32_to_cpu((end)->w0) & END_W0_VALID)
+#define xive_end_is_enqueue(end) (be32_to_cpu((end)->w0) & END_W0_ENQUEUE)
+#define xive_end_is_notify(end) (be32_to_cpu((end)->w0) & END_W0_UCOND_NOTIFY)
+#define xive_end_is_backlog(end) (be32_to_cpu((end)->w0) & END_W0_BACKLOG)
+#define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & END_W0_ESCALATE_CTL)
+
+/* Notification Virtual Target (NVT) */
+typedef struct XiveNVT {
+ uint32_t w0;
+#define NVT_W0_VALID PPC_BIT32(0)
+ uint32_t w1;
+ uint32_t w2;
+ uint32_t w3;
+ uint32_t w4;
+ uint32_t w5;
+ uint32_t w6;
+ uint32_t w7;
+ uint32_t w8;
+#define NVT_W8_GRP_VALID PPC_BIT32(0)
+ uint32_t w9;
+ uint32_t wa;
+ uint32_t wb;
+ uint32_t wc;
+ uint32_t wd;
+ uint32_t we;
+ uint32_t wf;
+} XiveNVT;
+
+#define xive_nvt_is_valid(nvt) (be32_to_cpu((nvt)->w0) & NVT_W0_VALID)
+
+#endif /* PPC_XIVE_REGS_H */
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index a24d0dd566..0a84c42756 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -197,7 +197,7 @@ typedef struct BusChild {
/**
* BusState:
- * @hotplug_device: link to a hotplug device associated with bus.
+ * @hotplug_handler: link to a hotplug handler associated with bus.
*/
struct BusState {
Object obj;
@@ -206,7 +206,7 @@ struct BusState {
HotplugHandler *hotplug_handler;
int max_index;
bool realized;
- QTAILQ_HEAD(ChildrenHead, BusChild) children;
+ QTAILQ_HEAD(, BusChild) children;
QLIST_ENTRY(BusState) sibling;
};
@@ -249,24 +249,30 @@ struct PropertyInfo {
/**
* GlobalProperty:
- * @user_provided: Set to true if property comes from user-provided config
- * (command-line or config file).
* @used: Set to true if property was used when initializing a device.
- * @errp: Error destination, used like first argument of error_setg()
- * in case property setting fails later. If @errp is NULL, we
- * print warnings instead of ignoring errors silently. For
- * hotplugged devices, errp is always ignored and warnings are
- * printed instead.
+ * @optional: If set to true, GlobalProperty will be skipped without errors
+ * if the property doesn't exist.
+ *
+ * An error is fatal for non-hotplugged devices, when the global is applied.
*/
typedef struct GlobalProperty {
const char *driver;
const char *property;
const char *value;
- bool user_provided;
bool used;
- Error **errp;
+ bool optional;
} GlobalProperty;
+static inline void
+compat_props_add(GPtrArray *arr,
+ GlobalProperty props[], size_t nelem)
+{
+ int i;
+ for (i = 0; i < nelem; i++) {
+ g_ptr_array_add(arr, (void *)&props[i]);
+ }
+}
+
/*** Board API. This should go away once we have a machine config file. ***/
DeviceState *qdev_create(BusState *bus, const char *name);
@@ -412,6 +418,8 @@ const char *qdev_fw_name(DeviceState *dev);
Object *qdev_get_machine(void);
+void object_apply_compat_props(Object *obj);
+
/* FIXME: make this a link<> */
void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 4f60cc88f3..b6758c852e 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -36,6 +36,8 @@ extern const PropertyInfo qdev_prop_uuid;
extern const PropertyInfo qdev_prop_arraylen;
extern const PropertyInfo qdev_prop_link;
extern const PropertyInfo qdev_prop_off_auto_pcibar;
+extern const PropertyInfo qdev_prop_pcie_link_speed;
+extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
.name = (_name), \
@@ -217,6 +219,12 @@ extern const PropertyInfo qdev_prop_off_auto_pcibar;
#define DEFINE_PROP_OFF_AUTO_PCIBAR(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_off_auto_pcibar, \
OffAutoPCIBAR)
+#define DEFINE_PROP_PCIE_LINK_SPEED(_n, _s, _f, _d) \
+ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_speed, \
+ PCIExpLinkSpeed)
+#define DEFINE_PROP_PCIE_LINK_WIDTH(_n, _s, _f, _d) \
+ DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pcie_link_width, \
+ PCIExpLinkWidth)
#define DEFINE_PROP_UUID(_name, _state, _field) { \
.name = (_name), \
@@ -249,42 +257,12 @@ void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_register_global(GlobalProperty *prop);
-void qdev_prop_register_global_list(GlobalProperty *props);
int qdev_prop_check_globals(void);
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);
/**
- * register_compat_prop:
- *
- * Register internal (not user-provided) global property, changing the
- * default value of a given property in a device type. This can be used
- * for enabling machine-type compatibility or for enabling
- * accelerator-specific defaults in devices.
- *
- * The property values set using this function must be always valid and
- * never report setter errors, as the property will have
- * GlobalProperty::errp set to &error_abort.
- *
- * User-provided global properties should override internal global
- * properties, so callers of this function should ensure that it is
- * called before user-provided global properties are registered.
- *
- * @driver: Device type to be affected
- * @property: Property whose default value is going to be changed
- * @value: New default value for the property
- */
-void register_compat_prop(const char *driver, const char *property,
- const char *value);
-/*
- * register_compat_props_array(): using register_compat_prop(), which
- * only registers internal global properties (which has lower priority
- * than user-provided global properties)
- */
-void register_compat_props_array(GlobalProperty *prop);
-
-/**
* qdev_property_add_static:
* @dev: Device to add the property to.
* @prop: The qdev property definition.
diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
index e8b4d9ffa3..be13cc1304 100644
--- a/include/hw/riscv/sifive_u.h
+++ b/include/hw/riscv/sifive_u.h
@@ -63,7 +63,8 @@ enum {
};
enum {
- SIFIVE_U_CLOCK_FREQ = 1000000000
+ SIFIVE_U_CLOCK_FREQ = 1000000000,
+ SIFIVE_U_GEM_CLOCK_FREQ = 125000000
};
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
diff --git a/include/hw/riscv/sifive_uart.h b/include/hw/riscv/sifive_uart.h
index 504f18a60f..c8dc1c57fd 100644
--- a/include/hw/riscv/sifive_uart.h
+++ b/include/hw/riscv/sifive_uart.h
@@ -43,6 +43,9 @@ enum {
SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */
};
+#define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7)
+#define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7)
+
#define TYPE_SIFIVE_UART "riscv.sifive.uart"
#define SIFIVE_UART(obj) \
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 91163d6cbf..f12deaebd6 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -38,14 +38,18 @@ enum {
VIRT_PLIC,
VIRT_UART0,
VIRT_VIRTIO,
- VIRT_DRAM
+ VIRT_DRAM,
+ VIRT_PCIE_MMIO,
+ VIRT_PCIE_PIO,
+ VIRT_PCIE_ECAM
};
enum {
UART0_IRQ = 10,
VIRTIO_IRQ = 1, /* 1 to 8 */
VIRTIO_COUNT = 8,
- VIRTIO_NDEV = 10
+ PCIE_IRQ = 0x20, /* 32 to 35 */
+ VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
};
enum {
@@ -62,6 +66,13 @@ enum {
#define VIRT_PLIC_CONTEXT_BASE 0x200000
#define VIRT_PLIC_CONTEXT_STRIDE 0x1000
+#define FDT_PCI_ADDR_CELLS 3
+#define FDT_PCI_INT_CELLS 1
+#define FDT_PLIC_ADDR_CELLS 0
+#define FDT_PLIC_INT_CELLS 1
+#define FDT_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + 1 + \
+ FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS)
+
#if defined(TARGET_RISCV32)
#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
#elif defined(TARGET_RISCV64)
diff --git a/include/hw/s390x/tod.h b/include/hw/s390x/tod.h
index 413c0d7c02..47ef9de869 100644
--- a/include/hw/s390x/tod.h
+++ b/include/hw/s390x/tod.h
@@ -31,13 +31,19 @@ typedef struct S390TODState {
/* private */
DeviceState parent_obj;
- /* unused by KVM implementation */
+ /*
+ * Used by TCG to remember the time base. Used by KVM to backup the TOD
+ * while the TOD is stopped.
+ */
S390TOD base;
+ /* Used by KVM to remember if the TOD is stopped and base is valid. */
+ bool stopped;
} S390TODState;
typedef struct S390TODClass {
/* private */
DeviceClass parent_class;
+ void (*parent_realize)(DeviceState *dev, Error **errp);
/* public */
void (*get)(const S390TODState *td, S390TOD *tod, Error **errp);
@@ -50,7 +56,7 @@ typedef struct S390TODClass {
/* Converts ns to s390's clock format */
static inline uint64_t time2tod(uint64_t ns)
{
- return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9);
+ return (ns << 9) / 125 + (((ns & 0xff80000000000000ull) / 125) << 9);
}
/* Converts s390's clock format to ns */
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 682a0d2de0..adab63d1c9 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -23,6 +23,8 @@ struct ESPState {
int32_t ti_size;
uint32_t ti_rptr, ti_wptr;
uint32_t status;
+ uint32_t deferred_status;
+ bool deferred_complete;
uint32_t dma;
uint8_t ti_buf[TI_BUFSZ];
SCSIBus bus;
diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h
index fbcee94ed7..adfedb2efc 100644
--- a/include/hw/sh4/sh_intc.h
+++ b/include/hw/sh4/sh_intc.h
@@ -61,21 +61,21 @@ struct intc_desc {
int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
void sh_intc_toggle_source(struct intc_source *source,
- int enable_adj, int assert_adj);
+ int enable_adj, int assert_adj);
void sh_intc_register_sources(struct intc_desc *desc,
- struct intc_vect *vectors,
- int nr_vectors,
- struct intc_group *groups,
- int nr_groups);
+ struct intc_vect *vectors,
+ int nr_vectors,
+ struct intc_group *groups,
+ int nr_groups);
int sh_intc_init(MemoryRegion *sysmem,
struct intc_desc *desc,
- int nr_sources,
- struct intc_mask_reg *mask_regs,
- int nr_mask_regs,
- struct intc_prio_reg *prio_regs,
- int nr_prio_regs);
+ int nr_sources,
+ struct intc_mask_reg *mask_regs,
+ int nr_mask_regs,
+ struct intc_prio_reg *prio_regs,
+ int nr_prio_regs);
void sh_intc_set_irl(void *opaque, int n, int level);
diff --git a/include/hw/smbios/ipmi.h b/include/hw/smbios/ipmi.h
deleted file mode 100644
index 1c9aae38f2..0000000000
--- a/include/hw/smbios/ipmi.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * IPMI SMBIOS firmware handling
- *
- * Copyright (c) 2015,2016 Corey Minyard, MontaVista Software, LLC
- *
- * 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_SMBIOS_IPMI_H
-#define QEMU_SMBIOS_IPMI_H
-
-void smbios_build_type_38_table(void);
-
-#endif /* QEMU_SMBIOS_IPMI_H */
diff --git a/include/hw/stream.h b/include/hw/stream.h
index c370ba0c66..15774f07ab 100644
--- a/include/hw/stream.h
+++ b/include/hw/stream.h
@@ -14,9 +14,7 @@
#define STREAM_SLAVE(obj) \
INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
-typedef struct StreamSlave {
- Object Parent;
-} StreamSlave;
+typedef struct StreamSlave StreamSlave;
typedef void (*StreamCanPushNotifyFn)(void *opaque);
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 0b59a3b8d6..1aedcf05c9 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -38,9 +38,6 @@ typedef struct SysBusDevice SysBusDevice;
typedef struct SysBusDeviceClass {
/*< private >*/
DeviceClass parent_class;
- /*< public >*/
-
- int (*init)(SysBusDevice *dev);
/*
* Let the sysbus device format its own non-PIO, non-MMIO unit address.
diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h
index db5e43a8da..6f8db04fce 100644
--- a/include/hw/timer/m48t59.h
+++ b/include/hw/timer/m48t59.h
@@ -13,9 +13,7 @@
#define NVRAM(obj) \
INTERFACE_CHECK(Nvram, (obj), TYPE_NVRAM)
-typedef struct Nvram {
- Object parent;
-} Nvram;
+typedef struct Nvram Nvram;
typedef struct NvramClass {
InterfaceClass parent;
diff --git a/include/hw/timer/nrf51_timer.h b/include/hw/timer/nrf51_timer.h
new file mode 100644
index 0000000000..85cad2300d
--- /dev/null
+++ b/include/hw/timer/nrf51_timer.h
@@ -0,0 +1,80 @@
+/*
+ * nRF51 System-on-Chip Timer peripheral
+ *
+ * QEMU interface:
+ * + sysbus MMIO regions 0: GPIO registers
+ * + sysbus irq
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef NRF51_TIMER_H
+#define NRF51_TIMER_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#define TYPE_NRF51_TIMER "nrf51_soc.timer"
+#define NRF51_TIMER(obj) OBJECT_CHECK(NRF51TimerState, (obj), TYPE_NRF51_TIMER)
+
+#define NRF51_TIMER_REG_COUNT 4
+
+#define NRF51_TIMER_TASK_START 0x000
+#define NRF51_TIMER_TASK_STOP 0x004
+#define NRF51_TIMER_TASK_COUNT 0x008
+#define NRF51_TIMER_TASK_CLEAR 0x00C
+#define NRF51_TIMER_TASK_SHUTDOWN 0x010
+#define NRF51_TIMER_TASK_CAPTURE_0 0x040
+#define NRF51_TIMER_TASK_CAPTURE_3 0x04C
+
+#define NRF51_TIMER_EVENT_COMPARE_0 0x140
+#define NRF51_TIMER_EVENT_COMPARE_1 0x144
+#define NRF51_TIMER_EVENT_COMPARE_2 0x148
+#define NRF51_TIMER_EVENT_COMPARE_3 0x14C
+
+#define NRF51_TIMER_REG_SHORTS 0x200
+#define NRF51_TIMER_REG_SHORTS_MASK 0xf0f
+#define NRF51_TIMER_REG_INTENSET 0x304
+#define NRF51_TIMER_REG_INTENCLR 0x308
+#define NRF51_TIMER_REG_INTEN_MASK 0xf0000
+#define NRF51_TIMER_REG_MODE 0x504
+#define NRF51_TIMER_REG_MODE_MASK 0x01
+#define NRF51_TIMER_TIMER 0
+#define NRF51_TIMER_COUNTER 1
+#define NRF51_TIMER_REG_BITMODE 0x508
+#define NRF51_TIMER_REG_BITMODE_MASK 0x03
+#define NRF51_TIMER_WIDTH_16 0
+#define NRF51_TIMER_WIDTH_8 1
+#define NRF51_TIMER_WIDTH_24 2
+#define NRF51_TIMER_WIDTH_32 3
+#define NRF51_TIMER_REG_PRESCALER 0x510
+#define NRF51_TIMER_REG_PRESCALER_MASK 0x0F
+#define NRF51_TIMER_REG_CC0 0x540
+#define NRF51_TIMER_REG_CC3 0x54C
+
+typedef struct NRF51TimerState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ QEMUTimer timer;
+ int64_t timer_start_ns;
+ int64_t update_counter_ns;
+ uint32_t counter;
+
+ bool running;
+
+ uint8_t events_compare[NRF51_TIMER_REG_COUNT];
+ uint32_t cc[NRF51_TIMER_REG_COUNT];
+ uint32_t shorts;
+ uint32_t inten;
+ uint32_t mode;
+ uint32_t bitmode;
+ uint32_t prescaler;
+
+} NRF51TimerState;
+
+
+#endif
diff --git a/include/hw/usb.h b/include/hw/usb.h
index a5080adecc..c21f41c8a9 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -408,7 +408,7 @@ struct USBPacket {
struct USBCombinedPacket {
USBPacket *first;
- QTAILQ_HEAD(packets_head, USBPacket) packets;
+ QTAILQ_HEAD(, USBPacket) packets;
QEMUIOVector iov;
};
@@ -593,8 +593,6 @@ const char *usb_device_get_product_desc(USBDevice *dev);
const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
-int ehci_create_ich9_with_companions(PCIBus *bus, int slot);
-
/* quirks.c */
/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index 1b434d02f6..7624c9f511 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -180,8 +180,8 @@ int vfio_get_device(VFIOGroup *group, const char *name,
VFIODevice *vbasedev, Error **errp);
extern const MemoryRegionOps vfio_region_ops;
-extern QLIST_HEAD(vfio_group_head, VFIOGroup) vfio_group_list;
-extern QLIST_HEAD(vfio_as_head, VFIOAddressSpace) vfio_address_spaces;
+typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList;
+extern VFIOGroupList vfio_group_list;
#ifdef CONFIG_LINUX
int vfio_get_region_info(VFIODevice *vbasedev, int index,
diff --git a/include/hw/vfio/vfio-platform.h b/include/hw/vfio/vfio-platform.h
index 0ee10b1d71..30d3c28d3b 100644
--- a/include/hw/vfio/vfio-platform.h
+++ b/include/hw/vfio/vfio-platform.h
@@ -53,7 +53,7 @@ typedef struct VFIOPlatformDevice {
VFIORegion **regions;
QLIST_HEAD(, VFIOINTp) intp_list; /* list of IRQs */
/* queue of pending IRQs */
- QSIMPLEQ_HEAD(pending_intp_queue, VFIOINTp) pending_intp_queue;
+ QSIMPLEQ_HEAD(, VFIOINTp) pending_intp_queue;
char *compat; /* DT compatible values, separated by NUL */
unsigned int num_compat; /* number of compatible values */
uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 4d7f3c82ca..bd662752d2 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -44,6 +44,82 @@ typedef struct virtio_net_conf
uint8_t duplex;
} virtio_net_conf;
+/* Coalesced packets type & status */
+typedef enum {
+ RSC_COALESCE, /* Data been coalesced */
+ RSC_FINAL, /* Will terminate current connection */
+ RSC_NO_MATCH, /* No matched in the buffer pool */
+ RSC_BYPASS, /* Packet to be bypass, not tcp, tcp ctrl, etc */
+ RSC_CANDIDATE /* Data want to be coalesced */
+} CoalesceStatus;
+
+typedef struct VirtioNetRscStat {
+ uint32_t received;
+ uint32_t coalesced;
+ uint32_t over_size;
+ uint32_t cache;
+ uint32_t empty_cache;
+ uint32_t no_match_cache;
+ uint32_t win_update;
+ uint32_t no_match;
+ uint32_t tcp_syn;
+ uint32_t tcp_ctrl_drain;
+ uint32_t dup_ack;
+ uint32_t dup_ack1;
+ uint32_t dup_ack2;
+ uint32_t pure_ack;
+ uint32_t ack_out_of_win;
+ uint32_t data_out_of_win;
+ uint32_t data_out_of_order;
+ uint32_t data_after_pure_ack;
+ uint32_t bypass_not_tcp;
+ uint32_t tcp_option;
+ uint32_t tcp_all_opt;
+ uint32_t ip_frag;
+ uint32_t ip_ecn;
+ uint32_t ip_hacked;
+ uint32_t ip_option;
+ uint32_t purge_failed;
+ uint32_t drain_failed;
+ uint32_t final_failed;
+ int64_t timer;
+} VirtioNetRscStat;
+
+/* Rsc unit general info used to checking if can coalescing */
+typedef struct VirtioNetRscUnit {
+ void *ip; /* ip header */
+ uint16_t *ip_plen; /* data len pointer in ip header field */
+ struct tcp_header *tcp; /* tcp header */
+ uint16_t tcp_hdrlen; /* tcp header len */
+ uint16_t payload; /* pure payload without virtio/eth/ip/tcp */
+} VirtioNetRscUnit;
+
+/* Coalesced segmant */
+typedef struct VirtioNetRscSeg {
+ QTAILQ_ENTRY(VirtioNetRscSeg) next;
+ void *buf;
+ size_t size;
+ uint16_t packets;
+ uint16_t dup_ack;
+ bool is_coalesced; /* need recal ipv4 header checksum, mark here */
+ VirtioNetRscUnit unit;
+ NetClientState *nc;
+} VirtioNetRscSeg;
+
+typedef struct VirtIONet VirtIONet;
+
+/* Chain is divided by protocol(ipv4/v6) and NetClientInfo */
+typedef struct VirtioNetRscChain {
+ QTAILQ_ENTRY(VirtioNetRscChain) next;
+ VirtIONet *n; /* VirtIONet */
+ uint16_t proto;
+ uint8_t gso_type;
+ uint16_t max_payload;
+ QEMUTimer *drain_timer;
+ QTAILQ_HEAD(, VirtioNetRscSeg) buffers;
+ VirtioNetRscStat stat;
+} VirtioNetRscChain;
+
/* Maximum packet size we can receive from tap device: header + 64k */
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
@@ -59,19 +135,25 @@ typedef struct VirtIONetQueue {
struct VirtIONet *n;
} VirtIONetQueue;
-typedef struct VirtIONet {
+struct VirtIONet {
VirtIODevice parent_obj;
uint8_t mac[ETH_ALEN];
uint16_t status;
VirtIONetQueue *vqs;
VirtQueue *ctrl_vq;
NICState *nic;
+ /* RSC Chains - temporary storage of coalesced data,
+ all these data are lost in case of migration */
+ QTAILQ_HEAD(, VirtioNetRscChain) rsc_chains;
uint32_t tx_timeout;
int32_t tx_burst;
uint32_t has_vnet_hdr;
size_t host_hdr_len;
size_t guest_hdr_len;
uint64_t host_features;
+ uint32_t rsc_timeout;
+ uint8_t rsc4_enabled;
+ uint8_t rsc6_enabled;
uint8_t has_ufo;
uint32_t mergeable_rx_bufs;
uint8_t promisc;
@@ -103,7 +185,7 @@ typedef struct VirtIONet {
int announce_counter;
bool needs_vnet_hdr_swap;
bool mtu_bypass_backend;
-} VirtIONet;
+};
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
const char *type);
diff --git a/include/hw/xen/io/ring.h b/include/hw/xen/io/ring.h
index ffa3ebadc8..1adacf09f9 100644
--- a/include/hw/xen/io/ring.h
+++ b/include/hw/xen/io/ring.h
@@ -235,8 +235,8 @@ typedef struct __name##_back_ring __name##_back_ring_t
* to be ineffective where _req is a struct which consists of only bitfields.
*/
#define RING_COPY_REQUEST(_r, _idx, _req) do { \
- /* Use volatile to force the copy into _req. */ \
- *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \
+ /* Use volatile to force the copy into _req. */ \
+ *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \
} while (0)
#define RING_GET_RESPONSE(_r, _idx) \
diff --git a/include/hw/xen/xen-backend.h b/include/hw/xen/xen-backend.h
new file mode 100644
index 0000000000..010d712638
--- /dev/null
+++ b/include/hw/xen/xen-backend.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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 HW_XEN_BACKEND_H
+#define HW_XEN_BACKEND_H
+
+#include "hw/xen/xen-bus.h"
+
+typedef struct XenBackendInstance XenBackendInstance;
+
+typedef void (*XenBackendDeviceCreate)(XenBackendInstance *backend,
+ QDict *opts, Error **errp);
+typedef void (*XenBackendDeviceDestroy)(XenBackendInstance *backend,
+ Error **errp);
+
+typedef struct XenBackendInfo {
+ const char *type;
+ XenBackendDeviceCreate create;
+ XenBackendDeviceDestroy destroy;
+} XenBackendInfo;
+
+XenBus *xen_backend_get_bus(XenBackendInstance *backend);
+const char *xen_backend_get_name(XenBackendInstance *backend);
+
+void xen_backend_set_device(XenBackendInstance *backend,
+ XenDevice *xendevice);
+XenDevice *xen_backend_get_device(XenBackendInstance *backend);
+
+void xen_backend_register(const XenBackendInfo *info);
+
+void xen_backend_device_create(XenBus *xenbus, const char *type,
+ const char *name, QDict *opts, Error **errp);
+bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp);
+
+#endif /* HW_XEN_BACKEND_H */
diff --git a/include/hw/xen/xen-block.h b/include/hw/xen/xen-block.h
new file mode 100644
index 0000000000..11d351b4b3
--- /dev/null
+++ b/include/hw/xen/xen-block.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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 HW_XEN_BLOCK_H
+#define HW_XEN_BLOCK_H
+
+#include "hw/xen/xen-bus.h"
+#include "hw/block/block.h"
+#include "hw/block/dataplane/xen-block.h"
+#include "sysemu/iothread.h"
+
+typedef enum XenBlockVdevType {
+ XEN_BLOCK_VDEV_TYPE_INVALID,
+ XEN_BLOCK_VDEV_TYPE_DP,
+ XEN_BLOCK_VDEV_TYPE_XVD,
+ XEN_BLOCK_VDEV_TYPE_HD,
+ XEN_BLOCK_VDEV_TYPE_SD,
+ XEN_BLOCK_VDEV_TYPE__MAX
+} XenBlockVdevType;
+
+typedef struct XenBlockVdev {
+ XenBlockVdevType type;
+ unsigned long disk;
+ unsigned long partition;
+ unsigned long number;
+} XenBlockVdev;
+
+
+typedef struct XenBlockProperties {
+ XenBlockVdev vdev;
+ BlockConf conf;
+ unsigned int max_ring_page_order;
+ IOThread *iothread;
+} XenBlockProperties;
+
+typedef struct XenBlockDrive {
+ char *id;
+ char *node_name;
+} XenBlockDrive;
+
+typedef struct XenBlockIOThread {
+ char *id;
+} XenBlockIOThread;
+
+typedef struct XenBlockDevice {
+ XenDevice xendev;
+ XenBlockProperties props;
+ const char *device_type;
+ unsigned int info;
+ XenBlockDataPlane *dataplane;
+ XenBlockDrive *drive;
+ XenBlockIOThread *iothread;
+} XenBlockDevice;
+
+typedef void (*XenBlockDeviceRealize)(XenBlockDevice *blockdev, Error **errp);
+typedef void (*XenBlockDeviceUnrealize)(XenBlockDevice *blockdev, Error **errp);
+
+typedef struct XenBlockDeviceClass {
+ /*< private >*/
+ XenDeviceClass parent_class;
+ /*< public >*/
+ XenBlockDeviceRealize realize;
+ XenBlockDeviceUnrealize unrealize;
+} XenBlockDeviceClass;
+
+#define TYPE_XEN_BLOCK_DEVICE "xen-block"
+#define XEN_BLOCK_DEVICE(obj) \
+ OBJECT_CHECK(XenBlockDevice, (obj), TYPE_XEN_BLOCK_DEVICE)
+#define XEN_BLOCK_DEVICE_CLASS(class) \
+ OBJECT_CLASS_CHECK(XenBlockDeviceClass, (class), TYPE_XEN_BLOCK_DEVICE)
+#define XEN_BLOCK_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XenBlockDeviceClass, (obj), TYPE_XEN_BLOCK_DEVICE)
+
+typedef struct XenDiskDevice {
+ XenBlockDevice blockdev;
+} XenDiskDevice;
+
+#define TYPE_XEN_DISK_DEVICE "xen-disk"
+#define XEN_DISK_DEVICE(obj) \
+ OBJECT_CHECK(XenDiskDevice, (obj), TYPE_XEN_DISK_DEVICE)
+
+typedef struct XenCDRomDevice {
+ XenBlockDevice blockdev;
+} XenCDRomDevice;
+
+#define TYPE_XEN_CDROM_DEVICE "xen-cdrom"
+#define XEN_CDROM_DEVICE(obj) \
+ OBJECT_CHECK(XenCDRomDevice, (obj), TYPE_XEN_CDROM_DEVICE)
+
+#endif /* HW_XEN_BLOCK_H */
diff --git a/include/hw/xen/xen-bus-helper.h b/include/hw/xen/xen-bus-helper.h
new file mode 100644
index 0000000000..4c0f747445
--- /dev/null
+++ b/include/hw/xen/xen-bus-helper.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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 HW_XEN_BUS_HELPER_H
+#define HW_XEN_BUS_HELPER_H
+
+#include "hw/xen/xen_common.h"
+
+const char *xs_strstate(enum xenbus_state state);
+
+void xs_node_create(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, struct xs_permissions perms[],
+ unsigned int nr_perms, Error **errp);
+void xs_node_destroy(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, Error **errp);
+
+/* Write to node/key unless node is empty, in which case write to key */
+void xs_node_vprintf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, va_list ap)
+ GCC_FMT_ATTR(6, 0);
+void xs_node_printf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, ...)
+ GCC_FMT_ATTR(6, 7);
+
+/* Read from node/key unless node is empty, in which case read from key */
+int xs_node_vscanf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, va_list ap);
+int xs_node_scanf(struct xs_handle *xsh, xs_transaction_t tid,
+ const char *node, const char *key, Error **errp,
+ const char *fmt, ...);
+
+/* Watch node/key unless node is empty, in which case watch key */
+void xs_node_watch(struct xs_handle *xsh, const char *node, const char *key,
+ char *token, Error **errp);
+void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *key,
+ const char *token, Error **errp);
+
+#endif /* HW_XEN_BUS_HELPER_H */
diff --git a/include/hw/xen/xen-bus.h b/include/hw/xen/xen-bus.h
new file mode 100644
index 0000000000..3183f10e3c
--- /dev/null
+++ b/include/hw/xen/xen-bus.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018 Citrix Systems Inc.
+ *
+ * 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 HW_XEN_BUS_H
+#define HW_XEN_BUS_H
+
+#include "hw/xen/xen_common.h"
+#include "hw/sysbus.h"
+#include "qemu/notify.h"
+
+typedef void (*XenWatchHandler)(void *opaque);
+
+typedef struct XenWatch XenWatch;
+
+typedef struct XenDevice {
+ DeviceState qdev;
+ domid_t frontend_id;
+ char *name;
+ char *backend_path, *frontend_path;
+ enum xenbus_state backend_state, frontend_state;
+ Notifier exit;
+ XenWatch *backend_state_watch, *frontend_state_watch;
+ bool backend_online;
+ XenWatch *backend_online_watch;
+ xengnttab_handle *xgth;
+ bool feature_grant_copy;
+ xenevtchn_handle *xeh;
+ NotifierList event_notifiers;
+} XenDevice;
+
+typedef char *(*XenDeviceGetName)(XenDevice *xendev, Error **errp);
+typedef void (*XenDeviceRealize)(XenDevice *xendev, Error **errp);
+typedef void (*XenDeviceFrontendChanged)(XenDevice *xendev,
+ enum xenbus_state frontend_state,
+ Error **errp);
+typedef void (*XenDeviceUnrealize)(XenDevice *xendev, Error **errp);
+
+typedef struct XenDeviceClass {
+ /*< private >*/
+ DeviceClass parent_class;
+ /*< public >*/
+ const char *backend;
+ const char *device;
+ XenDeviceGetName get_name;
+ XenDeviceRealize realize;
+ XenDeviceFrontendChanged frontend_changed;
+ XenDeviceUnrealize unrealize;
+} XenDeviceClass;
+
+#define TYPE_XEN_DEVICE "xen-device"
+#define XEN_DEVICE(obj) \
+ OBJECT_CHECK(XenDevice, (obj), TYPE_XEN_DEVICE)
+#define XEN_DEVICE_CLASS(class) \
+ OBJECT_CLASS_CHECK(XenDeviceClass, (class), TYPE_XEN_DEVICE)
+#define XEN_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XenDeviceClass, (obj), TYPE_XEN_DEVICE)
+
+typedef struct XenBus {
+ BusState qbus;
+ domid_t backend_id;
+ struct xs_handle *xsh;
+ NotifierList watch_notifiers;
+ XenWatch *backend_watch;
+} XenBus;
+
+typedef struct XenBusClass {
+ /*< private >*/
+ BusClass parent_class;
+} XenBusClass;
+
+#define TYPE_XEN_BUS "xen-bus"
+#define XEN_BUS(obj) \
+ OBJECT_CHECK(XenBus, (obj), TYPE_XEN_BUS)
+#define XEN_BUS_CLASS(class) \
+ OBJECT_CLASS_CHECK(XenBusClass, (class), TYPE_XEN_BUS)
+#define XEN_BUS_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XenBusClass, (obj), TYPE_XEN_BUS)
+
+void xen_bus_init(void);
+
+void xen_device_backend_set_state(XenDevice *xendev,
+ enum xenbus_state state);
+enum xenbus_state xen_device_backend_get_state(XenDevice *xendev);
+
+void xen_device_backend_printf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+ GCC_FMT_ATTR(3, 4);
+void xen_device_frontend_printf(XenDevice *xendev, const char *key,
+ const char *fmt, ...)
+ GCC_FMT_ATTR(3, 4);
+
+int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
+ const char *fmt, ...);
+
+void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
+ Error **errp);
+void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
+ unsigned int nr_refs, int prot,
+ Error **errp);
+void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
+ unsigned int nr_refs, Error **errp);
+
+typedef struct XenDeviceGrantCopySegment {
+ union {
+ void *virt;
+ struct {
+ uint32_t ref;
+ off_t offset;
+ } foreign;
+ } source, dest;
+ size_t len;
+} XenDeviceGrantCopySegment;
+
+void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
+ XenDeviceGrantCopySegment segs[],
+ unsigned int nr_segs, Error **errp);
+
+typedef struct XenEventChannel XenEventChannel;
+
+typedef void (*XenEventHandler)(void *opaque);
+
+XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
+ unsigned int port,
+ XenEventHandler handler,
+ void *opaque, Error **errp);
+void xen_device_notify_event_channel(XenDevice *xendev,
+ XenEventChannel *channel,
+ Error **errp);
+void xen_device_unbind_event_channel(XenDevice *xendev,
+ XenEventChannel *channel,
+ Error **errp);
+
+#endif /* HW_XEN_BUS_H */
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen-legacy-backend.h
index 9c17fdd85d..20cb47b5bf 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen-legacy-backend.h
@@ -11,7 +11,7 @@
#define TYPE_XENBACKEND "xen-backend"
#define XENBACKEND_DEVICE(obj) \
- OBJECT_CHECK(XenDevice, (obj), TYPE_XENBACKEND)
+ OBJECT_CHECK(XenLegacyDevice, (obj), TYPE_XENBACKEND)
/* variables */
extern struct xs_handle *xenstore;
@@ -20,32 +20,37 @@ extern DeviceState *xen_sysdev;
extern BusState *xen_sysbus;
int xenstore_mkdir(char *path, int p);
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
-int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival);
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
-void xenstore_update_fe(char *watch, struct XenDevice *xendev);
+int xenstore_write_be_str(struct XenLegacyDevice *xendev, const char *node,
+ const char *val);
+int xenstore_write_be_int(struct XenLegacyDevice *xendev, const char *node,
+ int ival);
+int xenstore_write_be_int64(struct XenLegacyDevice *xendev, const char *node,
+ int64_t ival);
+char *xenstore_read_be_str(struct XenLegacyDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenLegacyDevice *xendev, const char *node,
+ int *ival);
+void xenstore_update_fe(char *watch, struct XenLegacyDevice *xendev);
void xenstore_update_be(char *watch, char *type, int dom,
struct XenDevOps *ops);
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
-int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
+char *xenstore_read_fe_str(struct XenLegacyDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenLegacyDevice *xendev, const char *node,
+ int *ival);
+int xenstore_read_fe_uint64(struct XenLegacyDevice *xendev, const char *node,
uint64_t *uval);
-void xen_be_check_state(struct XenDevice *xendev);
+void xen_be_check_state(struct XenLegacyDevice *xendev);
/* xen backend driver bits */
int xen_be_init(void);
void xen_be_register_common(void);
int xen_be_register(const char *type, struct XenDevOps *ops);
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
-int xen_be_bind_evtchn(struct XenDevice *xendev);
-void xen_be_set_max_grant_refs(struct XenDevice *xendev,
+int xen_be_set_state(struct XenLegacyDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenLegacyDevice *xendev);
+void xen_be_set_max_grant_refs(struct XenLegacyDevice *xendev,
unsigned int nr_refs);
-void *xen_be_map_grant_refs(struct XenDevice *xendev, uint32_t *refs,
+void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
unsigned int nr_refs, int prot);
-void xen_be_unmap_grant_refs(struct XenDevice *xendev, void *ptr,
+void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
unsigned int nr_refs);
typedef struct XenGrantCopySegment {
@@ -59,17 +64,17 @@ typedef struct XenGrantCopySegment {
size_t len;
} XenGrantCopySegment;
-int xen_be_copy_grant_refs(struct XenDevice *xendev,
+int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
bool to_domain, XenGrantCopySegment segs[],
unsigned int nr_segs);
-static inline void *xen_be_map_grant_ref(struct XenDevice *xendev,
+static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev,
uint32_t ref, int prot)
{
return xen_be_map_grant_refs(xendev, &ref, 1, prot);
}
-static inline void xen_be_unmap_grant_ref(struct XenDevice *xendev,
+static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev,
void *ptr)
{
return xen_be_unmap_grant_refs(xendev, ptr, 1);
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index 7efcdaa8fe..ba039c146d 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -15,8 +15,7 @@
/* xen-machine.c */
enum xen_mode {
XEN_EMULATE = 0, // xen emulation, using xenner (default)
- XEN_CREATE, // create xen domain
- XEN_ATTACH // attach to xen domain created by xend
+ XEN_ATTACH // attach to xen domain created by libxl
};
extern uint32_t xen_domid;
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 93f631e5bf..9a8155e172 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -32,6 +32,7 @@ extern xc_interface *xen_xc;
typedef xc_interface xenforeignmemory_handle;
typedef xc_evtchn xenevtchn_handle;
typedef xc_gnttab xengnttab_handle;
+typedef evtchn_port_or_error_t xenevtchn_port_or_error_t;
#define xenevtchn_open(l, f) xc_evtchn_open(l, f);
#define xenevtchn_close(h) xc_evtchn_close(h)
@@ -661,24 +662,6 @@ static inline int xen_set_ioreq_server_state(domid_t dom,
#endif
-#ifdef CONFIG_XEN_PV_DOMAIN_BUILD
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40700
-static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
- xen_domain_handle_t handle, uint32_t flags,
- uint32_t *pdomid)
-{
- return xc_domain_create(xc, ssidref, handle, flags, pdomid);
-}
-#else
-static inline int xen_domain_create(xc_interface *xc, uint32_t ssidref,
- xen_domain_handle_t handle, uint32_t flags,
- uint32_t *pdomid)
-{
- return xc_domain_create(xc, ssidref, handle, flags, pdomid, NULL);
-}
-#endif
-#endif
-
/* Xen before 4.8 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 40800
diff --git a/include/hw/xen/xen_pvdev.h b/include/hw/xen/xen_pvdev.h
index d473e9b34d..83e5174d90 100644
--- a/include/hw/xen/xen_pvdev.h
+++ b/include/hw/xen/xen_pvdev.h
@@ -6,7 +6,7 @@
#define XEN_BUFSIZE 1024
-struct XenDevice;
+struct XenLegacyDevice;
/* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */
#define DEVOPS_FLAG_NEED_GNTDEV 1
@@ -16,19 +16,21 @@ struct XenDevice;
struct XenDevOps {
size_t size;
uint32_t flags;
- void (*alloc)(struct XenDevice *xendev);
- int (*init)(struct XenDevice *xendev);
- int (*initialise)(struct XenDevice *xendev);
- void (*connected)(struct XenDevice *xendev);
- void (*event)(struct XenDevice *xendev);
- void (*disconnect)(struct XenDevice *xendev);
- int (*free)(struct XenDevice *xendev);
- void (*backend_changed)(struct XenDevice *xendev, const char *node);
- void (*frontend_changed)(struct XenDevice *xendev, const char *node);
+ void (*alloc)(struct XenLegacyDevice *xendev);
+ int (*init)(struct XenLegacyDevice *xendev);
+ int (*initialise)(struct XenLegacyDevice *xendev);
+ void (*connected)(struct XenLegacyDevice *xendev);
+ void (*event)(struct XenLegacyDevice *xendev);
+ void (*disconnect)(struct XenLegacyDevice *xendev);
+ int (*free)(struct XenLegacyDevice *xendev);
+ void (*backend_changed)(struct XenLegacyDevice *xendev,
+ const char *node);
+ void (*frontend_changed)(struct XenLegacyDevice *xendev,
+ const char *node);
int (*backend_register)(void);
};
-struct XenDevice {
+struct XenLegacyDevice {
DeviceState qdev;
const char *type;
int dom;
@@ -49,7 +51,7 @@ struct XenDevice {
xengnttab_handle *gnttabdev;
struct XenDevOps *ops;
- QTAILQ_ENTRY(XenDevice) next;
+ QTAILQ_ENTRY(XenLegacyDevice) next;
};
/* ------------------------------------------------------------- */
@@ -66,14 +68,14 @@ void xenstore_update(void *unused);
const char *xenbus_strstate(enum xenbus_state state);
void xen_pv_evtchn_event(void *opaque);
-void xen_pv_insert_xendev(struct XenDevice *xendev);
-void xen_pv_del_xendev(struct XenDevice *xendev);
-struct XenDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
+void xen_pv_insert_xendev(struct XenLegacyDevice *xendev);
+void xen_pv_del_xendev(struct XenLegacyDevice *xendev);
+struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev);
-void xen_pv_unbind_evtchn(struct XenDevice *xendev);
-int xen_pv_send_notify(struct XenDevice *xendev);
+void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev);
+int xen_pv_send_notify(struct XenLegacyDevice *xendev);
-void xen_pv_printf(struct XenDevice *xendev, int msg_level,
+void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
const char *fmt, ...) GCC_FMT_ATTR(3, 4);
#endif /* QEMU_HW_XEN_PVDEV_H */
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 61bef3ef5c..067b126cf1 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -185,6 +185,7 @@ struct VMStateDescription {
int (*pre_load)(void *opaque);
int (*post_load)(void *opaque, int version_id);
int (*pre_save)(void *opaque);
+ int (*post_save)(void *opaque);
bool (*needed)(void *opaque);
const VMStateField *fields;
const VMStateDescription **subsections;
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 6fd2c53b09..c1b40a9cac 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -13,7 +13,8 @@ extern __thread Monitor *cur_mon;
#define MONITOR_USE_READLINE 0x02
#define MONITOR_USE_CONTROL 0x04
#define MONITOR_USE_PRETTY 0x08
-#define MONITOR_USE_OOB 0x10
+
+#define QMP_REQ_QUEUE_LEN_MAX 8
bool monitor_cur_is_qmp(void);
diff --git a/include/net/eth.h b/include/net/eth.h
index e6dc8a7ba0..7f45c678e7 100644
--- a/include/net/eth.h
+++ b/include/net/eth.h
@@ -177,6 +177,8 @@ struct tcp_hdr {
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
+#define TH_ECE 0x40
+#define TH_CWR 0x80
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
diff --git a/include/net/net.h b/include/net/net.h
index ec13702dbf..643295d163 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -97,7 +97,7 @@ struct NetClientState {
unsigned rxfilter_notify_enabled:1;
int vring_enable;
int vnet_hdr_len;
- QTAILQ_HEAD(NetFilterHead, NetFilterState) filters;
+ QTAILQ_HEAD(, NetFilterState) filters;
};
typedef struct NICState {
diff --git a/include/qapi/string-input-visitor.h b/include/qapi/string-input-visitor.h
index 33551340e3..921f3875b9 100644
--- a/include/qapi/string-input-visitor.h
+++ b/include/qapi/string-input-visitor.h
@@ -19,8 +19,8 @@ typedef struct StringInputVisitor StringInputVisitor;
/*
* The string input visitor does not implement support for visiting
- * QAPI structs, alternates, null, or arbitrary QTypes. It also
- * requires a non-null list argument to visit_start_list().
+ * QAPI structs, alternates, null, or arbitrary QTypes. Only flat lists
+ * of integers (except type "size") are supported.
*/
Visitor *string_input_visitor_new(const char *str);
diff --git a/include/qemu/acl.h b/include/qemu/acl.h
index 7c44119a47..73d2a71c8d 100644
--- a/include/qemu/acl.h
+++ b/include/qemu/acl.h
@@ -49,18 +49,18 @@ qemu_acl *qemu_acl_init(const char *aclname);
qemu_acl *qemu_acl_find(const char *aclname);
int qemu_acl_party_is_allowed(qemu_acl *acl,
- const char *party);
+ const char *party);
void qemu_acl_reset(qemu_acl *acl);
int qemu_acl_append(qemu_acl *acl,
- int deny,
- const char *match);
+ int deny,
+ const char *match);
int qemu_acl_insert(qemu_acl *acl,
- int deny,
- const char *match,
- int index);
+ int deny,
+ const char *match,
+ int index);
int qemu_acl_remove(qemu_acl *acl,
- const char *match);
+ const char *match);
#endif /* QEMU_ACL_H */
diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index f6993a8fb1..a6ac188188 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -99,9 +99,10 @@
* those few cases by hand.
*
* Note that x32 is fully detected with __x86_64__ + _ILP32, and that for
- * Sparc we always force the use of sparcv9 in configure.
+ * Sparc we always force the use of sparcv9 in configure. MIPS n32 (ILP32) &
+ * n64 (LP64) ABIs are both detected using __mips64.
*/
-#if defined(__x86_64__) || defined(__sparc__)
+#if defined(__x86_64__) || defined(__sparc__) || defined(__mips64)
# define ATOMIC_REG_SIZE 8
#else
# define ATOMIC_REG_SIZE sizeof(void *)
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 6b92710487..296b2fd572 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -28,12 +28,6 @@
#define QEMU_SENTINEL __attribute__((sentinel))
-#if QEMU_GNUC_PREREQ(4, 3)
-#define QEMU_ARTIFICIAL __attribute__((always_inline, artificial))
-#else
-#define QEMU_ARTIFICIAL
-#endif
-
#if defined(_WIN32)
# define QEMU_PACKED __attribute__((gcc_struct, packed))
#else
@@ -119,6 +113,10 @@
#define GCC_FMT_ATTR(n, m)
#endif
+#ifndef __has_warning
+#define __has_warning(x) 0 /* compatibility with non-clang compilers */
+#endif
+
#ifndef __has_feature
#define __has_feature(x) 0 /* compatibility with non-clang compilers */
#endif
@@ -127,7 +125,7 @@
#define __has_builtin(x) 0 /* compatibility with non-clang compilers */
#endif
-#if __has_builtin(__builtin_assume_aligned) || QEMU_GNUC_PREREQ(4, 7)
+#if __has_builtin(__builtin_assume_aligned) || !defined(__clang__)
#define HAS_ASSUME_ALIGNED
#endif
@@ -157,6 +155,21 @@
# define QEMU_ERROR(X)
#endif
+/*
+ * The nonstring variable attribute specifies that an object or member
+ * declaration with type array of char or pointer to char is intended
+ * to store character arrays that do not necessarily contain a terminating
+ * NUL character. This is useful in detecting uses of such arrays or pointers
+ * with functions that expect NUL-terminated strings, and to avoid warnings
+ * when such an array or pointer is used as an argument to a bounded string
+ * manipulation function such as strncpy.
+ */
+#if __has_attribute(nonstring)
+# define QEMU_NONSTRING __attribute__((nonstring))
+#else
+# define QEMU_NONSTRING
+#endif
+
/* Implement C11 _Generic via GCC builtins. Example:
*
* QEMU_GENERIC(x, (float, sinf), (long double, sinl), sin) (x)
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index 7071bfe2d4..d2dad3057c 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -146,14 +146,16 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base,
int64_t *result);
int qemu_strtou64(const char *nptr, const char **endptr, int base,
uint64_t *result);
+int qemu_strtod(const char *nptr, const char **endptr, double *result);
+int qemu_strtod_finite(const char *nptr, const char **endptr, double *result);
int parse_uint(const char *s, unsigned long long *value, char **endptr,
int base);
int parse_uint_full(const char *s, unsigned long long *value, int base);
-int qemu_strtosz(const char *nptr, char **end, uint64_t *result);
-int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result);
-int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result);
+int qemu_strtosz(const char *nptr, const char **end, uint64_t *result);
+int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result);
+int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result);
/* used to print char* safely */
#define STR_OR_NULL(str) ((str) ? (str) : "null")
diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index a7cb780592..4afbe6292e 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -300,12 +300,32 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);
/* hbitmap_next_zero:
+ *
+ * Find next not dirty bit within selected range. If not found, return -1.
+ *
* @hb: The HBitmap to operate on
* @start: The bit to start from.
- *
- * Find next not dirty bit.
+ * @count: Number of bits to proceed. If @start+@count > bitmap size, the whole
+ * bitmap is looked through. You can use UINT64_MAX as @count to search up to
+ * the bitmap end.
+ */
+int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count);
+
+/* hbitmap_next_dirty_area:
+ * @hb: The HBitmap to operate on
+ * @start: in-out parameter.
+ * in: the offset to start from
+ * out: (if area found) start of found area
+ * @count: in-out parameter.
+ * in: length of requested region
+ * out: length of found area
+ *
+ * If dirty area found within [@start, @start + @count), returns true and sets
+ * @offset and @bytes appropriately. Otherwise returns false and leaves @offset
+ * and @bytes unchanged.
*/
-int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start);
+bool hbitmap_next_dirty_area(const HBitmap *hb, uint64_t *start,
+ uint64_t *count);
/* hbitmap_create_meta:
* Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap.
@@ -331,14 +351,11 @@ void hbitmap_free_meta(HBitmap *hb);
/**
* hbitmap_iter_next:
* @hbi: HBitmapIter to operate on.
- * @advance: If true, advance the iterator. Otherwise, the next call
- * of this function will return the same result (if that
- * position is still dirty).
*
* Return the next bit that is set in @hbi's associated HBitmap,
* or -1 if all remaining bits are zero.
*/
-int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance);
+int64_t hbitmap_iter_next(HBitmapIter *hbi);
/**
* hbitmap_iter_next_word:
diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index 38da849be9..4cd170e6cd 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -207,7 +207,7 @@ static inline int cto64(uint64_t val)
*/
static inline int clrsb32(uint32_t val)
{
-#if QEMU_GNUC_PREREQ(4, 7)
+#if __has_builtin(__builtin_clrsb) || !defined(__clang__)
return __builtin_clrsb(val);
#else
return clz32(val ^ ((int32_t)val >> 1)) - 1;
@@ -223,7 +223,7 @@ static inline int clrsb32(uint32_t val)
*/
static inline int clrsb64(uint64_t val)
{
-#if QEMU_GNUC_PREREQ(4, 7)
+#if __has_builtin(__builtin_clrsbll) || !defined(__clang__)
return __builtin_clrsbll(val);
#else
return clz64(val ^ ((int64_t)val >> 1)) - 1;
diff --git a/include/qemu/iov.h b/include/qemu/iov.h
index 72d4c559b4..5f433c7768 100644
--- a/include/qemu/iov.h
+++ b/include/qemu/iov.h
@@ -35,7 +35,7 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
size_t offset, const void *buf, size_t bytes);
size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
- size_t offset, void *buf, size_t bytes);
+ size_t offset, void *buf, size_t bytes);
static inline size_t
iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
diff --git a/include/qemu/module.h b/include/qemu/module.h
index 54300ab6e5..55dd2beea8 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -44,6 +44,7 @@ typedef enum {
MODULE_INIT_OPTS,
MODULE_INIT_QOM,
MODULE_INIT_TRACE,
+ MODULE_INIT_XEN_BACKEND,
MODULE_INIT_MAX
} module_init_type;
@@ -51,6 +52,8 @@ typedef enum {
#define opts_init(function) module_init(function, MODULE_INIT_OPTS)
#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define trace_init(function) module_init(function, MODULE_INIT_TRACE)
+#define xen_backend_init(function) module_init(function, \
+ MODULE_INIT_XEN_BACKEND)
#define block_module_load_one(lib) module_load_one("block-", lib)
#define ui_module_load_one(lib) module_load_one("ui-", lib)
diff --git a/include/qemu/option_int.h b/include/qemu/option_int.h
index 26b1d9e4d6..5dd9a5162d 100644
--- a/include/qemu/option_int.h
+++ b/include/qemu/option_int.h
@@ -47,7 +47,7 @@ struct QemuOpts {
char *id;
QemuOptsList *list;
Location loc;
- QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
+ QTAILQ_HEAD(, QemuOpt) head;
QTAILQ_ENTRY(QemuOpts) next;
};
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 3bf48bcdec..80df7253db 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -74,13 +74,30 @@ typedef __float128 _Float128;
extern int daemon(int, int);
#endif
+#ifdef _WIN32
+/* as defined in sdkddkver.h */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600 /* Vista */
+#endif
+/* reduces the number of implicitly included headers */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#endif
+
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
+
+/* enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later) */
+#ifdef __MINGW32__
+#define __USE_MINGW_ANSI_STDIO 1
+#endif
#include <stdio.h>
+
#include <string.h>
#include <strings.h>
#include <inttypes.h>
diff --git a/include/qemu/queue.h b/include/qemu/queue.h
index ac418efc43..1f8e219412 100644
--- a/include/qemu/queue.h
+++ b/include/qemu/queue.h
@@ -346,77 +346,80 @@ struct { \
#define QSIMPLEQ_FIRST(head) ((head)->sqh_first)
#define QSIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+typedef struct QTailQLink {
+ void *tql_next;
+ struct QTailQLink *tql_prev;
+} QTailQLink;
/*
- * Tail queue definitions.
+ * Tail queue definitions. The union acts as a poor man template, as if
+ * it were QTailQLink<type>.
*/
-#define Q_TAILQ_HEAD(name, type, qual) \
-struct name { \
- qual type *tqh_first; /* first element */ \
- qual type *qual *tqh_last; /* addr of last next element */ \
+#define QTAILQ_HEAD(name, type) \
+union name { \
+ struct type *tqh_first; /* first element */ \
+ QTailQLink tqh_circ; /* link for circular backwards list */ \
}
-#define QTAILQ_HEAD(name, type) Q_TAILQ_HEAD(name, struct type,)
#define QTAILQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).tqh_first }
+ { .tqh_circ = { NULL, &(head).tqh_circ } }
-#define Q_TAILQ_ENTRY(type, qual) \
-struct { \
- qual type *tqe_next; /* next element */ \
- qual type *qual *tqe_prev; /* address of previous next element */\
+#define QTAILQ_ENTRY(type) \
+union { \
+ struct type *tqe_next; /* next element */ \
+ QTailQLink tqe_circ; /* link for circular backwards list */ \
}
-#define QTAILQ_ENTRY(type) Q_TAILQ_ENTRY(struct type,)
/*
* Tail queue functions.
*/
#define QTAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
- (head)->tqh_last = &(head)->tqh_first; \
+ (head)->tqh_circ.tql_prev = &(head)->tqh_circ; \
} while (/*CONSTCOND*/0)
#define QTAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
- (head)->tqh_first->field.tqe_prev = \
- &(elm)->field.tqe_next; \
+ (head)->tqh_first->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
(head)->tqh_first = (elm); \
- (elm)->field.tqe_prev = &(head)->tqh_first; \
+ (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ; \
} while (/*CONSTCOND*/0)
#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- *(head)->tqh_last = (elm); \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+ (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \
+ (head)->tqh_circ.tql_prev->tql_next = (elm); \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
- (elm)->field.tqe_next->field.tqe_prev = \
- &(elm)->field.tqe_next; \
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
else \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
(listelm)->field.tqe_next = (elm); \
- (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+ (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
-#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
- (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
- (elm)->field.tqe_next = (listelm); \
- *(listelm)->field.tqe_prev = (elm); \
- (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ (listelm)->field.tqe_circ.tql_prev->tql_next = (elm); \
+ (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
#define QTAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
- (elm)->field.tqe_next->field.tqe_prev = \
- (elm)->field.tqe_prev; \
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ (elm)->field.tqe_circ.tql_prev; \
else \
- (head)->tqh_last = (elm)->field.tqe_prev; \
- *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
- (elm)->field.tqe_prev = NULL; \
+ (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \
+ (elm)->field.tqe_circ.tql_prev->tql_next = (elm)->field.tqe_next; \
+ (elm)->field.tqe_circ.tql_prev = NULL; \
} while (/*CONSTCOND*/0)
#define QTAILQ_FOREACH(var, head, field) \
@@ -429,14 +432,14 @@ struct { \
(var) && ((next_var) = ((var)->field.tqe_next), 1); \
(var) = (next_var))
-#define QTAILQ_FOREACH_REVERSE(var, head, headname, field) \
- for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
+#define QTAILQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = QTAILQ_LAST(head); \
(var); \
- (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+ (var) = QTAILQ_PREV(var, field))
-#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev_var) \
- for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
- (var) && ((prev_var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)), 1); \
+#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, field, prev_var) \
+ for ((var) = QTAILQ_LAST(head); \
+ (var) && ((prev_var) = QTAILQ_PREV(var, field)); \
(var) = (prev_var))
/*
@@ -445,71 +448,49 @@ struct { \
#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define QTAILQ_FIRST(head) ((head)->tqh_first)
#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-#define QTAILQ_IN_USE(elm, field) ((elm)->field.tqe_prev != NULL)
+#define QTAILQ_IN_USE(elm, field) ((elm)->field.tqe_circ.tql_prev != NULL)
-#define QTAILQ_LAST(head, headname) \
- (*(((struct headname *)((head)->tqh_last))->tqh_last))
-#define QTAILQ_PREV(elm, headname, field) \
- (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define QTAILQ_LINK_PREV(link) \
+ ((link).tql_prev->tql_prev->tql_next)
+#define QTAILQ_LAST(head) \
+ ((typeof((head)->tqh_first)) QTAILQ_LINK_PREV((head)->tqh_circ))
+#define QTAILQ_PREV(elm, field) \
+ ((typeof((elm)->field.tqe_next)) QTAILQ_LINK_PREV((elm)->field.tqe_circ))
#define field_at_offset(base, offset, type) \
- ((type) (((char *) (base)) + (offset)))
-
-typedef struct DUMMY_Q_ENTRY DUMMY_Q_ENTRY;
-typedef struct DUMMY_Q DUMMY_Q;
-
-struct DUMMY_Q_ENTRY {
- QTAILQ_ENTRY(DUMMY_Q_ENTRY) next;
-};
-
-struct DUMMY_Q {
- QTAILQ_HEAD(DUMMY_Q_HEAD, DUMMY_Q_ENTRY) head;
-};
-
-#define dummy_q ((DUMMY_Q *) 0)
-#define dummy_qe ((DUMMY_Q_ENTRY *) 0)
+ ((type *) (((char *) (base)) + (offset)))
/*
- * Offsets of layout of a tail queue head.
- */
-#define QTAILQ_FIRST_OFFSET (offsetof(typeof(dummy_q->head), tqh_first))
-#define QTAILQ_LAST_OFFSET (offsetof(typeof(dummy_q->head), tqh_last))
-/*
- * Raw access of elements of a tail queue
+ * Raw access of elements of a tail queue head. Offsets are all zero
+ * because it's a union.
*/
#define QTAILQ_RAW_FIRST(head) \
- (*field_at_offset(head, QTAILQ_FIRST_OFFSET, void **))
-#define QTAILQ_RAW_TQH_LAST(head) \
- (*field_at_offset(head, QTAILQ_LAST_OFFSET, void ***))
-
-/*
- * Offsets of layout of a tail queue element.
- */
-#define QTAILQ_NEXT_OFFSET (offsetof(typeof(dummy_qe->next), tqe_next))
-#define QTAILQ_PREV_OFFSET (offsetof(typeof(dummy_qe->next), tqe_prev))
+ field_at_offset(head, 0, void *)
+#define QTAILQ_RAW_TQH_CIRC(head) \
+ field_at_offset(head, 0, QTailQLink)
/*
* Raw access of elements of a tail entry
*/
#define QTAILQ_RAW_NEXT(elm, entry) \
- (*field_at_offset(elm, entry + QTAILQ_NEXT_OFFSET, void **))
-#define QTAILQ_RAW_TQE_PREV(elm, entry) \
- (*field_at_offset(elm, entry + QTAILQ_PREV_OFFSET, void ***))
+ field_at_offset(elm, entry, void *)
+#define QTAILQ_RAW_TQE_CIRC(elm, entry) \
+ field_at_offset(elm, entry, QTailQLink)
/*
- * Tail queue tranversal using pointer arithmetic.
+ * Tail queue traversal using pointer arithmetic.
*/
#define QTAILQ_RAW_FOREACH(elm, head, entry) \
- for ((elm) = QTAILQ_RAW_FIRST(head); \
+ for ((elm) = *QTAILQ_RAW_FIRST(head); \
(elm); \
- (elm) = QTAILQ_RAW_NEXT(elm, entry))
+ (elm) = *QTAILQ_RAW_NEXT(elm, entry))
/*
* Tail queue insertion using pointer arithmetic.
*/
-#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do { \
- QTAILQ_RAW_NEXT(elm, entry) = NULL; \
- QTAILQ_RAW_TQE_PREV(elm, entry) = QTAILQ_RAW_TQH_LAST(head); \
- *QTAILQ_RAW_TQH_LAST(head) = (elm); \
- QTAILQ_RAW_TQH_LAST(head) = &QTAILQ_RAW_NEXT(elm, entry); \
+#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do { \
+ *QTAILQ_RAW_NEXT(elm, entry) = NULL; \
+ QTAILQ_RAW_TQE_CIRC(elm, entry)->tql_prev = QTAILQ_RAW_TQH_CIRC(head)->tql_prev; \
+ QTAILQ_RAW_TQH_CIRC(head)->tql_prev->tql_next = (elm); \
+ QTAILQ_RAW_TQH_CIRC(head)->tql_prev = QTAILQ_RAW_TQE_CIRC(elm, entry); \
} while (/*CONSTCOND*/0)
#endif /* QEMU_SYS_QUEUE_H */
diff --git a/include/qemu/range.h b/include/qemu/range.h
index f28f0c1825..ba606c6bc0 100644
--- a/include/qemu/range.h
+++ b/include/qemu/range.h
@@ -39,7 +39,7 @@ struct Range {
uint64_t upb; /* inclusive upper bound */
};
-static inline void range_invariant(Range *range)
+static inline void range_invariant(const Range *range)
{
assert(range->lob <= range->upb || range->lob == range->upb + 1);
}
@@ -48,14 +48,14 @@ static inline void range_invariant(Range *range)
#define range_empty ((Range){ .lob = 1, .upb = 0 })
/* Is @range empty? */
-static inline bool range_is_empty(Range *range)
+static inline bool range_is_empty(const Range *range)
{
range_invariant(range);
return range->lob > range->upb;
}
/* Does @range contain @val? */
-static inline bool range_contains(Range *range, uint64_t val)
+static inline bool range_contains(const Range *range, uint64_t val)
{
return val >= range->lob && val <= range->upb;
}
@@ -113,6 +113,68 @@ static inline uint64_t range_upb(Range *range)
}
/*
+ * Initialize @range to span the interval [@lob,@lob + @size - 1].
+ * @size may be 0. If the range would overflow, returns -ERANGE, otherwise
+ * 0.
+ */
+static inline int QEMU_WARN_UNUSED_RESULT range_init(Range *range, uint64_t lob,
+ uint64_t size)
+{
+ if (lob + size < lob) {
+ return -ERANGE;
+ }
+ range->lob = lob;
+ range->upb = lob + size - 1;
+ range_invariant(range);
+ return 0;
+}
+
+/*
+ * Initialize @range to span the interval [@lob,@lob + @size - 1].
+ * @size may be 0. Range must not overflow.
+ */
+static inline void range_init_nofail(Range *range, uint64_t lob, uint64_t size)
+{
+ range->lob = lob;
+ range->upb = lob + size - 1;
+ range_invariant(range);
+}
+
+/*
+ * Get the size of @range.
+ */
+static inline uint64_t range_size(const Range *range)
+{
+ return range->upb - range->lob + 1;
+}
+
+/*
+ * Check if @range1 overlaps with @range2. If one of the ranges is empty,
+ * the result is always "false".
+ */
+static inline bool range_overlaps_range(const Range *range1,
+ const Range *range2)
+{
+ if (range_is_empty(range1) || range_is_empty(range2)) {
+ return false;
+ }
+ return !(range2->upb < range1->lob || range1->upb < range2->lob);
+}
+
+/*
+ * Check if @range1 contains @range2. If one of the ranges is empty,
+ * the result is always "false".
+ */
+static inline bool range_contains_range(const Range *range1,
+ const Range *range2)
+{
+ if (range_is_empty(range1) || range_is_empty(range2)) {
+ return false;
+ }
+ return range1->lob <= range2->lob && range1->upb >= range2->upb;
+}
+
+/*
* Extend @range to the smallest interval that includes @extend_by, too.
*/
static inline void range_extend(Range *range, Range *extend_by)
diff --git a/include/qemu/rcu_queue.h b/include/qemu/rcu_queue.h
index 904b3372dc..2d386f303e 100644
--- a/include/qemu/rcu_queue.h
+++ b/include/qemu/rcu_queue.h
@@ -206,47 +206,50 @@ extern "C" {
#define QTAILQ_INSERT_HEAD_RCU(head, elm, field) do { \
(elm)->field.tqe_next = (head)->tqh_first; \
if ((elm)->field.tqe_next != NULL) { \
- (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next; \
+ (head)->tqh_first->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
} else { \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
} \
atomic_rcu_set(&(head)->tqh_first, (elm)); \
- (elm)->field.tqe_prev = &(head)->tqh_first; \
+ (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ; \
} while (/*CONSTCOND*/0)
-#define QTAILQ_INSERT_TAIL_RCU(head, elm, field) do { \
- (elm)->field.tqe_next = NULL; \
- (elm)->field.tqe_prev = (head)->tqh_last; \
- atomic_rcu_set((head)->tqh_last, (elm)); \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+#define QTAILQ_INSERT_TAIL_RCU(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \
+ atomic_rcu_set(&(head)->tqh_circ.tql_prev->tql_next, (elm)); \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
#define QTAILQ_INSERT_AFTER_RCU(head, listelm, elm, field) do { \
(elm)->field.tqe_next = (listelm)->field.tqe_next; \
if ((elm)->field.tqe_next != NULL) { \
- (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next; \
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
} else { \
- (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
} \
atomic_rcu_set(&(listelm)->field.tqe_next, (elm)); \
- (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+ (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ; \
} while (/*CONSTCOND*/0)
-#define QTAILQ_INSERT_BEFORE_RCU(listelm, elm, field) do { \
- (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
- (elm)->field.tqe_next = (listelm); \
- atomic_rcu_set((listelm)->field.tqe_prev, (elm)); \
- (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
- } while (/*CONSTCOND*/0)
+#define QTAILQ_INSERT_BEFORE_RCU(listelm, elm, field) do { \
+ (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ atomic_rcu_set(&(listelm)->field.tqe_circ.tql_prev->tql_next, (elm)); \
+ (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ; \
+} while (/*CONSTCOND*/0)
#define QTAILQ_REMOVE_RCU(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) { \
- (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev; \
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ (elm)->field.tqe_circ.tql_prev; \
} else { \
- (head)->tqh_last = (elm)->field.tqe_prev; \
+ (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \
} \
- atomic_set((elm)->field.tqe_prev, (elm)->field.tqe_next); \
- (elm)->field.tqe_prev = NULL; \
+ atomic_set(&(elm)->field.tqe_circ.tql_prev->tql_next, (elm)->field.tqe_next); \
+ (elm)->field.tqe_circ.tql_prev = NULL; \
} while (/*CONSTCOND*/0)
#define QTAILQ_FOREACH_RCU(var, head, field) \
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 3ec0e13a96..5d1a2d8329 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -4,12 +4,10 @@
/* A load of opaque types so that device init declarations don't have to
pull in all the real definitions. */
-/* Please keep this list in alphabetical order */
+/* Please keep this list in case-insensitive alphabetical order */
typedef struct AdapterInfo AdapterInfo;
typedef struct AddressSpace AddressSpace;
typedef struct AioContext AioContext;
-typedef struct AllwinnerAHCIState AllwinnerAHCIState;
-typedef struct AudioState AudioState;
typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
typedef struct BlockBackend BlockBackend;
@@ -26,8 +24,6 @@ typedef struct DeviceListener DeviceListener;
typedef struct DeviceState DeviceState;
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
typedef struct DisplayChangeListener DisplayChangeListener;
-typedef struct DisplayState DisplayState;
-typedef struct DisplaySurface DisplaySurface;
typedef struct DriveInfo DriveInfo;
typedef struct Error Error;
typedef struct EventNotifier EventNotifier;
@@ -36,10 +32,10 @@ typedef struct FWCfgEntry FWCfgEntry;
typedef struct FWCfgIoState FWCfgIoState;
typedef struct FWCfgMemState FWCfgMemState;
typedef struct FWCfgState FWCfgState;
-typedef struct HCIInfo HCIInfo;
typedef struct HVFX86EmulatorState HVFX86EmulatorState;
typedef struct I2CBus I2CBus;
typedef struct I2SCodec I2SCodec;
+typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct ISABus ISABus;
typedef struct ISADevice ISADevice;
typedef struct IsaDma IsaDma;
@@ -49,19 +45,19 @@ typedef struct MachineState MachineState;
typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList;
typedef struct MemoryRegion MemoryRegion;
-typedef struct IOMMUMemoryRegion IOMMUMemoryRegion;
typedef struct MemoryRegionCache MemoryRegionCache;
typedef struct MemoryRegionSection MemoryRegionSection;
typedef struct MigrationIncomingState MigrationIncomingState;
typedef struct MigrationState MigrationState;
typedef struct Monitor Monitor;
typedef struct MonitorDef MonitorDef;
-typedef struct MouseTransformInfo MouseTransformInfo;
typedef struct MSIMessage MSIMessage;
typedef struct NetClientState NetClientState;
typedef struct NetFilterState NetFilterState;
typedef struct NICInfo NICInfo;
+typedef struct NodeInfo NodeInfo;
typedef struct NumaNodeMem NumaNodeMem;
+typedef struct ObjectClass ObjectClass;
typedef struct PCIBridge PCIBridge;
typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice;
@@ -74,29 +70,24 @@ typedef struct PCIExpressDevice PCIExpressDevice;
typedef struct PCIExpressHost PCIExpressHost;
typedef struct PCIHostDeviceAddress PCIHostDeviceAddress;
typedef struct PCIHostState PCIHostState;
-typedef struct PCMachineClass PCMachineClass;
typedef struct PCMachineState PCMachineState;
-typedef struct PCMCIACardState PCMCIACardState;
-typedef struct PixelFormat PixelFormat;
typedef struct PostcopyDiscardState PostcopyDiscardState;
typedef struct Property Property;
typedef struct PropertyInfo PropertyInfo;
-typedef struct PS2State PS2State;
+typedef struct QBool QBool;
+typedef struct QDict QDict;
typedef struct QEMUBH QEMUBH;
typedef struct QemuConsole QemuConsole;
-typedef struct QemuDmaBuf QemuDmaBuf;
typedef struct QEMUFile QEMUFile;
typedef struct QemuLockable QemuLockable;
typedef struct QemuMutex QemuMutex;
typedef struct QemuOpt QemuOpt;
typedef struct QemuOpts QemuOpts;
typedef struct QemuOptsList QemuOptsList;
-typedef struct QemuSpin QemuSpin;
typedef struct QEMUSGList QEMUSGList;
+typedef struct QemuSpin QemuSpin;
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUTimerListGroup QEMUTimerListGroup;
-typedef struct QBool QBool;
-typedef struct QDict QDict;
typedef struct QJSON QJSON;
typedef struct QList QList;
typedef struct QNull QNull;
@@ -105,14 +96,11 @@ typedef struct QObject QObject;
typedef struct QString QString;
typedef struct RAMBlock RAMBlock;
typedef struct Range Range;
-typedef struct SerialState SerialState;
typedef struct SHPCDevice SHPCDevice;
-typedef struct SMBusDevice SMBusDevice;
typedef struct SSIBus SSIBus;
typedef struct uWireSlave uWireSlave;
typedef struct VirtIODevice VirtIODevice;
typedef struct Visitor Visitor;
-typedef struct node_info NodeInfo;
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
diff --git a/include/qemu/vfio-helpers.h b/include/qemu/vfio-helpers.h
index ce7e7b057f..1f057c2b9e 100644
--- a/include/qemu/vfio-helpers.h
+++ b/include/qemu/vfio-helpers.h
@@ -12,7 +12,6 @@
#ifndef QEMU_VFIO_HELPERS_H
#define QEMU_VFIO_HELPERS_H
-#include "qemu/typedefs.h"
typedef struct QEMUVFIOState QEMUVFIOState;
diff --git a/include/exec/tb-hash-xx.h b/include/qemu/xxhash.h
index 747a9a612c..076f1f6054 100644
--- a/include/exec/tb-hash-xx.h
+++ b/include/qemu/xxhash.h
@@ -31,8 +31,8 @@
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*/
-#ifndef EXEC_TB_HASH_XX_H
-#define EXEC_TB_HASH_XX_H
+#ifndef QEMU_XXHASH_H
+#define QEMU_XXHASH_H
#include "qemu/bitops.h"
@@ -42,23 +42,23 @@
#define PRIME32_4 668265263U
#define PRIME32_5 374761393U
-#define TB_HASH_XX_SEED 1
+#define QEMU_XXHASH_SEED 1
/*
* xxhash32, customized for input variables that are not guaranteed to be
* contiguous in memory.
*/
static inline uint32_t
-tb_hash_func7(uint64_t a0, uint64_t b0, uint32_t e, uint32_t f, uint32_t g)
+qemu_xxhash7(uint64_t ab, uint64_t cd, uint32_t e, uint32_t f, uint32_t g)
{
- uint32_t v1 = TB_HASH_XX_SEED + PRIME32_1 + PRIME32_2;
- uint32_t v2 = TB_HASH_XX_SEED + PRIME32_2;
- uint32_t v3 = TB_HASH_XX_SEED + 0;
- uint32_t v4 = TB_HASH_XX_SEED - PRIME32_1;
- uint32_t a = a0 >> 32;
- uint32_t b = a0;
- uint32_t c = b0 >> 32;
- uint32_t d = b0;
+ uint32_t v1 = QEMU_XXHASH_SEED + PRIME32_1 + PRIME32_2;
+ uint32_t v2 = QEMU_XXHASH_SEED + PRIME32_2;
+ uint32_t v3 = QEMU_XXHASH_SEED + 0;
+ uint32_t v4 = QEMU_XXHASH_SEED - PRIME32_1;
+ uint32_t a = ab;
+ uint32_t b = ab >> 32;
+ uint32_t c = cd;
+ uint32_t d = cd >> 32;
uint32_t h32;
v1 += a * PRIME32_2;
@@ -98,4 +98,25 @@ tb_hash_func7(uint64_t a0, uint64_t b0, uint32_t e, uint32_t f, uint32_t g)
return h32;
}
-#endif /* EXEC_TB_HASH_XX_H */
+static inline uint32_t qemu_xxhash2(uint64_t ab)
+{
+ return qemu_xxhash7(ab, 0, 0, 0, 0);
+}
+
+static inline uint32_t qemu_xxhash4(uint64_t ab, uint64_t cd)
+{
+ return qemu_xxhash7(ab, cd, 0, 0, 0);
+}
+
+static inline uint32_t qemu_xxhash5(uint64_t ab, uint64_t cd, uint32_t e)
+{
+ return qemu_xxhash7(ab, cd, e, 0, 0);
+}
+
+static inline uint32_t qemu_xxhash6(uint64_t ab, uint64_t cd, uint32_t e,
+ uint32_t f)
+{
+ return qemu_xxhash7(ab, cd, e, f, 0);
+}
+
+#endif /* QEMU_XXHASH_H */
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 1396f53e5b..16bbed1ae0 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -26,6 +26,7 @@
#include "exec/memattrs.h"
#include "qapi/qapi-types-run-state.h"
#include "qemu/bitmap.h"
+#include "qemu/fprintf-fn.h"
#include "qemu/rcu_queue.h"
#include "qemu/queue.h"
#include "qemu/thread.h"
@@ -375,9 +376,9 @@ struct CPUState {
QTAILQ_ENTRY(CPUState) node;
/* ice debug support */
- QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints;
+ QTAILQ_HEAD(, CPUBreakpoint) breakpoints;
- QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints;
+ QTAILQ_HEAD(, CPUWatchpoint) watchpoints;
CPUWatchpoint *watchpoint_hit;
void *opaque;
@@ -435,8 +436,9 @@ struct CPUState {
GArray *iommu_notifiers;
};
-QTAILQ_HEAD(CPUTailQ, CPUState);
-extern struct CPUTailQ cpus;
+typedef QTAILQ_HEAD(CPUTailQ, CPUState) CPUTailQ;
+extern CPUTailQ cpus;
+
#define first_cpu QTAILQ_FIRST_RCU(&cpus)
#define CPU_NEXT(cpu) QTAILQ_NEXT_RCU(cpu, node)
#define CPU_FOREACH(cpu) QTAILQ_FOREACH_RCU(cpu, &cpus, node)
diff --git a/include/qom/object.h b/include/qom/object.h
index f0b0bf39cc..e0262962b5 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -20,7 +20,6 @@
struct TypeImpl;
typedef struct TypeImpl *Type;
-typedef struct ObjectClass ObjectClass;
typedef struct Object Object;
typedef struct TypeInfo TypeInfo;
@@ -455,10 +454,8 @@ struct Object
* parent class initialization has occurred, but before the class itself
* is initialized. This is the function to use to undo the effects of
* memcpy from the parent class to the descendants.
- * @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, @class_base_init and
- * @class_finalize functions. This can be useful when building dynamic
+ * @class_data: Data to pass to the @class_init,
+ * @class_base_init. 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
@@ -479,7 +476,6 @@ struct TypeInfo
void (*class_init)(ObjectClass *klass, void *data);
void (*class_base_init)(ObjectClass *klass, void *data);
- void (*class_finalize)(ObjectClass *klass, void *data);
void *class_data;
InterfaceInfo *interfaces;
@@ -679,6 +675,9 @@ Object *object_new_with_propv(const char *typename,
Error **errp,
va_list vargs);
+void object_apply_global_props(Object *obj, const GPtrArray *props,
+ Error **errp);
+
/**
* object_set_props:
* @obj: the object instance to set properties on
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
index 4d513fb329..682ba1d9b0 100644
--- a/include/qom/object_interfaces.h
+++ b/include/qom/object_interfaces.h
@@ -16,11 +16,7 @@
INTERFACE_CHECK(UserCreatable, (obj), \
TYPE_USER_CREATABLE)
-
-typedef struct UserCreatable {
- /* <private> */
- Object Parent;
-} UserCreatable;
+typedef struct UserCreatable UserCreatable;
/**
* UserCreatableClass:
@@ -55,14 +51,14 @@ typedef struct UserCreatableClass {
/**
* user_creatable_complete:
- * @obj: the object whose complete() method is called if defined
+ * @uc: the user-creatable object whose complete() method is called if defined
* @errp: if an error occurs, a pointer to an area to store the error
*
* Wrapper to call complete() method if one of types it's inherited
* from implements USER_CREATABLE interface, otherwise the call does
* nothing.
*/
-void user_creatable_complete(Object *obj, Error **errp);
+void user_creatable_complete(UserCreatable *uc, Error **errp);
/**
* user_creatable_can_be_deleted:
diff --git a/include/scsi/constants.h b/include/scsi/constants.h
index 083a8e887a..0dc550732d 100644
--- a/include/scsi/constants.h
+++ b/include/scsi/constants.h
@@ -212,7 +212,7 @@
#define TYPE_ROM 0x05
#define TYPE_SCANNER 0x06
#define TYPE_MOD 0x07 /* Magneto-optical disk -
- * - treated as TYPE_DISK */
+ * - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 0x08
#define TYPE_STORAGE_ARRAY 0x0c /* Storage array device */
#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
diff --git a/include/scsi/pr-manager.h b/include/scsi/pr-manager.h
index 50a77b08fc..6ad5fd1ff7 100644
--- a/include/scsi/pr-manager.h
+++ b/include/scsi/pr-manager.h
@@ -5,6 +5,7 @@
#include "qapi/visitor.h"
#include "qom/object_interfaces.h"
#include "block/aio.h"
+#include "qemu/coroutine.h"
#define TYPE_PR_MANAGER "pr-manager"
@@ -37,11 +38,8 @@ typedef struct PRManagerClass {
} PRManagerClass;
bool pr_manager_is_connected(PRManager *pr_mgr);
-BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
- AioContext *ctx, int fd,
- struct sg_io_hdr *hdr,
- BlockCompletionFunc *complete,
- void *opaque);
+int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
+ struct sg_io_hdr *hdr);
PRManager *pr_manager_lookup(const char *id, Error **errp);
diff --git a/include/sysemu/accel.h b/include/sysemu/accel.h
index 637358f430..5565e00a96 100644
--- a/include/sysemu/accel.h
+++ b/include/sysemu/accel.h
@@ -49,7 +49,7 @@ typedef struct AccelClass {
* global properties may be overridden by machine-type
* compat_props or user-provided global properties.
*/
- GlobalProperty *global_props;
+ GPtrArray *compat_props;
} AccelClass;
#define TYPE_ACCEL "accel"
@@ -66,9 +66,7 @@ typedef struct AccelClass {
extern unsigned long tcg_tb_size;
-void configure_accelerator(MachineState *ms);
-/* Register accelerator specific global properties */
-void accel_register_compat_props(AccelState *accel);
+void configure_accelerator(MachineState *ms, const char *progname);
/* Called just before os_setup_post (ie just before drop OS privs) */
void accel_setup_post(MachineState *ms);
diff --git a/include/sysemu/balloon.h b/include/sysemu/balloon.h
index 66543ae8f4..c8f6145257 100644
--- a/include/sysemu/balloon.h
+++ b/include/sysemu/balloon.h
@@ -20,7 +20,7 @@ typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonStatus)(void *opaque, BalloonInfo *info);
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
- QEMUBalloonStatus *stat_func, void *opaque);
+ QEMUBalloonStatus *stat_func, void *opaque);
void qemu_remove_balloon_handler(void *opaque);
bool qemu_balloon_is_inhibited(void);
void qemu_balloon_inhibit(bool state);
diff --git a/include/sysemu/bt.h b/include/sysemu/bt.h
index ddb05cd109..2fd8c0f14b 100644
--- a/include/sysemu/bt.h
+++ b/include/sysemu/bt.h
@@ -3,7 +3,7 @@
/* BT HCI info */
-struct HCIInfo {
+typedef struct HCIInfo {
int (*bdaddr_set)(struct HCIInfo *hci, const uint8_t *bd_addr);
void (*cmd_send)(struct HCIInfo *hci, const uint8_t *data, int len);
void (*sco_send)(struct HCIInfo *hci, const uint8_t *data, int len);
@@ -11,7 +11,7 @@ struct HCIInfo {
void *opaque;
void (*evt_recv)(void *opaque, const uint8_t *data, int len);
void (*acl_recv)(void *opaque, const uint8_t *data, int len);
-};
+} HCIInfo;
/* bt-host.c */
struct HCIInfo *bt_host_hci(const char *id);
diff --git a/include/sysemu/hostmem.h b/include/sysemu/hostmem.h
index 6e6bd2c1cb..a023b372a4 100644
--- a/include/sysemu/hostmem.h
+++ b/include/sysemu/hostmem.h
@@ -53,7 +53,7 @@ struct HostMemoryBackend {
/* protected */
uint64_t size;
- bool merge, dump;
+ bool merge, dump, use_canonical_path;
bool prealloc, force_prealloc, is_mapped, share;
DECLARE_BITMAP(host_nodes, MAX_NODES + 1);
HostMemPolicy policy;
@@ -67,5 +67,6 @@ MemoryRegion *host_memory_backend_get_memory(HostMemoryBackend *backend);
void host_memory_backend_set_mapped(HostMemoryBackend *backend, bool mapped);
bool host_memory_backend_is_mapped(HostMemoryBackend *backend);
size_t host_memory_backend_pagesize(HostMemoryBackend *memdev);
+char *host_memory_backend_get_name(HostMemoryBackend *backend);
#endif
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 97d8d9d0d5..a6d1cd190f 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -412,8 +412,6 @@ struct kvm_sw_breakpoint {
QTAILQ_ENTRY(kvm_sw_breakpoint) entry;
};
-QTAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint);
-
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
target_ulong pc);
diff --git a/include/sysemu/memory_mapping.h b/include/sysemu/memory_mapping.h
index 706152d533..58452457ce 100644
--- a/include/sysemu/memory_mapping.h
+++ b/include/sysemu/memory_mapping.h
@@ -36,7 +36,7 @@ typedef struct GuestPhysBlock {
/* point-in-time snapshot of guest-visible physical mappings */
typedef struct GuestPhysBlockList {
unsigned num;
- QTAILQ_HEAD(GuestPhysBlockHead, GuestPhysBlock) head;
+ QTAILQ_HEAD(, GuestPhysBlock) head;
} GuestPhysBlockList;
/* The physical and virtual address in the memory mapping are contiguous. */
diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h
index 21713b7e2f..b6ac7de43e 100644
--- a/include/sysemu/numa.h
+++ b/include/sysemu/numa.h
@@ -9,7 +9,7 @@
extern int nb_numa_nodes; /* Number of NUMA nodes */
extern bool have_numa_distance;
-struct node_info {
+struct NodeInfo {
uint64_t node_mem;
struct HostMemoryBackend *node_memdev;
bool present;
diff --git a/include/sysemu/rng.h b/include/sysemu/rng.h
index 45629c4c53..27b37da05d 100644
--- a/include/sysemu/rng.h
+++ b/include/sysemu/rng.h
@@ -57,7 +57,7 @@ struct RngBackend
/*< protected >*/
bool opened;
- QSIMPLEQ_HEAD(requests, RngRequest) requests;
+ QSIMPLEQ_HEAD(, RngRequest) requests;
};
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 8d6095d98b..85877b7e43 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -31,26 +31,6 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
void vm_state_notify(int running, RunState state);
-/* Enumeration of various causes for shutdown. */
-typedef enum ShutdownCause {
- SHUTDOWN_CAUSE_NONE, /* No shutdown request pending */
- SHUTDOWN_CAUSE_HOST_ERROR, /* An error prevents further use of guest */
- SHUTDOWN_CAUSE_HOST_QMP, /* Reaction to a QMP command, like 'quit' */
- SHUTDOWN_CAUSE_HOST_SIGNAL, /* Reaction to a signal, such as SIGINT */
- SHUTDOWN_CAUSE_HOST_UI, /* Reaction to UI event, like window close */
- SHUTDOWN_CAUSE_GUEST_SHUTDOWN,/* Guest shutdown/suspend request, via
- ACPI or other hardware-specific means */
- SHUTDOWN_CAUSE_GUEST_RESET, /* Guest reset request, and command line
- turns that into a shutdown */
- SHUTDOWN_CAUSE_GUEST_PANIC, /* Guest panicked, and command line turns
- that into a shutdown */
- SHUTDOWN_CAUSE_SUBSYSTEM_RESET,/* Partial guest reset that does not trigger
- QMP events and ignores --no-reboot. This
- is useful for sanitize hypercalls on s390
- that are used during kexec/kdump/boot */
- SHUTDOWN_CAUSE__MAX,
-} ShutdownCause;
-
static inline bool shutdown_caused_by_guest(ShutdownCause cause)
{
return cause >= SHUTDOWN_CAUSE_GUEST_SHUTDOWN;
@@ -74,12 +54,15 @@ void qemu_exit_preconfig_request(void);
void qemu_system_reset_request(ShutdownCause reason);
void qemu_system_suspend_request(void);
void qemu_register_suspend_notifier(Notifier *notifier);
-void qemu_system_wakeup_request(WakeupReason reason);
+bool qemu_wakeup_suspend_enabled(void);
+void qemu_system_wakeup_request(WakeupReason reason, Error **errp);
void qemu_system_wakeup_enable(WakeupReason reason, bool enabled);
void qemu_register_wakeup_notifier(Notifier *notifier);
+void qemu_register_wakeup_support(void);
void qemu_system_shutdown_request(ShutdownCause reason);
void qemu_system_powerdown_request(void);
void qemu_register_powerdown_notifier(Notifier *notifier);
+void qemu_register_shutdown_notifier(Notifier *notifier);
void qemu_system_debug_request(void);
void qemu_system_vmstop_request(RunState reason);
void qemu_system_vmstop_request_prepare(void);
@@ -133,7 +116,6 @@ extern uint8_t *boot_splash_filedata;
extern size_t boot_splash_filedata_size;
extern bool enable_mlock;
extern bool enable_cpu_pm;
-extern uint8_t qemu_extra_params_fw[2];
extern QEMUClockType rtc_clock;
extern const char *mem_path;
extern int mem_prealloc;
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 17a97ed77a..5b541a71c8 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -33,9 +33,7 @@ typedef enum TPMVersion {
#define TPM_IF(obj) \
INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF)
-typedef struct TPMIf {
- Object parent_obj;
-} TPMIf;
+typedef struct TPMIf TPMIf;
typedef struct TPMIfClass {
InterfaceClass parent_class;
diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h
index 89592ae4fa..d200ee01d0 100644
--- a/include/sysemu/whpx.h
+++ b/include/sysemu/whpx.h
@@ -13,7 +13,6 @@
#ifndef QEMU_WHPX_H
#define QEMU_WHPX_H
-#include "config-host.h"
#include "qemu-common.h"
int whpx_init_vcpu(CPUState *cpu);
diff --git a/include/ui/console.h b/include/ui/console.h
index c17803c530..fef900db76 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -65,13 +65,13 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
void kbd_put_ledstate(int ledstate);
-struct MouseTransformInfo {
+typedef struct MouseTransformInfo {
/* Touchscreen resolution */
int x;
int y;
/* Calibration values as used/generated by tslib */
int a[7];
-};
+} MouseTransformInfo;
void hmp_mouse_set(Monitor *mon, const QDict *qdict);
@@ -121,17 +121,7 @@ struct QemuConsoleClass {
#define QEMU_ALLOCATED_FLAG 0x01
-struct PixelFormat {
- uint8_t bits_per_pixel;
- uint8_t bytes_per_pixel;
- uint8_t depth; /* color depth in bits */
- uint32_t rmask, gmask, bmask, amask;
- uint8_t rshift, gshift, bshift, ashift;
- uint8_t rmax, gmax, bmax, amax;
- uint8_t rbits, gbits, bbits, abits;
-};
-
-struct DisplaySurface {
+typedef struct DisplaySurface {
pixman_format_code_t format;
pixman_image_t *image;
uint8_t flags;
@@ -140,7 +130,7 @@ struct DisplaySurface {
GLenum gltype;
GLuint texture;
#endif
-};
+} DisplaySurface;
typedef struct QemuUIInfo {
/* geometry */
@@ -179,7 +169,7 @@ struct QEMUGLParams {
int minor_ver;
};
-struct QemuDmaBuf {
+typedef struct QemuDmaBuf {
int fd;
uint32_t width;
uint32_t height;
@@ -187,7 +177,9 @@ struct QemuDmaBuf {
uint32_t fourcc;
uint32_t texture;
bool y0_top;
-};
+} QemuDmaBuf;
+
+typedef struct DisplayState DisplayState;
typedef struct DisplayChangeListenerOps {
const char *dpy_name;
@@ -257,10 +249,6 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
pixman_format_code_t format,
int linesize, uint8_t *data);
DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
-DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
- pixman_format_code_t format,
- int linesize,
- uint64_t addr);
DisplaySurface *qemu_create_message_surface(int w, int h,
const char *msg);
PixelFormat qemu_default_pixelformat(int bpp);
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 9db7293bdb..3fc656a7ba 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -43,7 +43,7 @@ void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf);
#endif
-EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win);
+EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win);
int qemu_egl_init_dpy_x11(EGLNativeDisplayType dpy, DisplayGLMode mode);
int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode);
diff --git a/include/ui/input.h b/include/ui/input.h
index 34ebc67c5a..8c8ccb999f 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -49,7 +49,6 @@ int qemu_input_key_value_to_scancode(const KeyValue *value, bool down,
int *codes);
int qemu_input_linux_to_qcode(unsigned int lnx);
-InputEvent *qemu_input_event_new_btn(InputButton btn, bool down);
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
uint32_t button_old, uint32_t button_new);
@@ -58,8 +57,6 @@ bool qemu_input_is_absolute(void);
int qemu_input_scale_axis(int value,
int min_in, int max_in,
int min_out, int max_out);
-InputEvent *qemu_input_event_new_move(InputEventKind kind,
- InputAxis axis, int value);
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value);
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
int min_in, int max_in);
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index b7c82d17fc..0668109305 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -53,6 +53,16 @@
/* -------------------------------------------------------------------- */
+typedef struct PixelFormat {
+ uint8_t bits_per_pixel;
+ uint8_t bytes_per_pixel;
+ uint8_t depth; /* color depth in bits */
+ uint32_t rmask, gmask, bmask, amask;
+ uint8_t rshift, gshift, bshift, ashift;
+ uint8_t rmax, gmax, bmax, amax;
+ uint8_t rbits, gbits, bbits, abits;
+} PixelFormat;
+
PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format);
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index c6d50eb87a..8c23dfe717 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -46,13 +46,7 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port,
#else
#define SPICE_NEEDS_SET_MM_TIME 0
#endif
-
-#if SPICE_SERVER_VERSION >= 0x000c02
void qemu_spice_register_ports(void);
-#else
-static inline Chardev *qemu_chr_open_spice_port(const char *name)
-{ return NULL; }
-#endif
#else /* CONFIG_SPICE */
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index f43eecdbd6..f6db642b65 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -6,6 +6,9 @@
#include <SDL.h>
#include <SDL_syswm.h>
+#ifdef CONFIG_SDL_IMAGE
+# include <SDL_image.h>
+#endif
#ifdef CONFIG_OPENGL
# include "ui/egl-helpers.h"
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5bccd2e243..4cff9e1a31 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -2844,7 +2844,7 @@ struct elf_note_info {
struct target_elf_prstatus *prstatus; /* NT_PRSTATUS */
struct target_elf_prpsinfo *psinfo; /* NT_PRPSINFO */
- QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list;
+ QTAILQ_HEAD(, elf_thread_status) thread_list;
#if 0
/*
* Current version of ELF coredump doesn't support
diff --git a/linux-user/host/riscv32/hostdep.h b/linux-user/host/riscv32/hostdep.h
new file mode 100644
index 0000000000..adf9edbf2d
--- /dev/null
+++ b/linux-user/host/riscv32/hostdep.h
@@ -0,0 +1,11 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * 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 RISCV32_HOSTDEP_H
+#define RISCV32_HOSTDEP_H
+
+#endif
diff --git a/linux-user/host/riscv64/hostdep.h b/linux-user/host/riscv64/hostdep.h
new file mode 100644
index 0000000000..865f0fb9ff
--- /dev/null
+++ b/linux-user/host/riscv64/hostdep.h
@@ -0,0 +1,34 @@
+/*
+ * hostdep.h : things which are dependent on the host architecture
+ *
+ * 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 RISCV64_HOSTDEP_H
+#define RISCV64_HOSTDEP_H
+
+/* We have a safe-syscall.inc.S */
+#define HAVE_SAFE_SYSCALL
+
+#ifndef __ASSEMBLER__
+
+/* These are defined by the safe-syscall.inc.S file */
+extern char safe_syscall_start[];
+extern char safe_syscall_end[];
+
+/* Adjust the signal context to rewind out of safe-syscall if we're in it */
+static inline void rewind_if_in_safe_syscall(void *puc)
+{
+ ucontext_t *uc = puc;
+ unsigned long *pcreg = &uc->uc_mcontext.__gregs[REG_PC];
+
+ if (*pcreg > (uintptr_t)safe_syscall_start
+ && *pcreg < (uintptr_t)safe_syscall_end) {
+ *pcreg = (uintptr_t)safe_syscall_start;
+ }
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/linux-user/host/riscv64/safe-syscall.inc.S b/linux-user/host/riscv64/safe-syscall.inc.S
new file mode 100644
index 0000000000..9ca3fbfd1e
--- /dev/null
+++ b/linux-user/host/riscv64/safe-syscall.inc.S
@@ -0,0 +1,77 @@
+/*
+ * safe-syscall.inc.S : host-specific assembly fragment
+ * to handle signals occurring at the same time as system calls.
+ * This is intended to be included by linux-user/safe-syscall.S
+ *
+ * Written by Richard Henderson <rth@twiddle.net>
+ * Copyright (C) 2018 Linaro, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+ .global safe_syscall_base
+ .global safe_syscall_start
+ .global safe_syscall_end
+ .type safe_syscall_base, @function
+ .type safe_syscall_start, @function
+ .type safe_syscall_end, @function
+
+ /*
+ * This is the entry point for making a system call. The calling
+ * convention here is that of a C varargs function with the
+ * first argument an 'int *' to the signal_pending flag, the
+ * second one the system call number (as a 'long'), and all further
+ * arguments being syscall arguments (also 'long').
+ * We return a long which is the syscall's return value, which
+ * may be negative-errno on failure. Conversion to the
+ * -1-and-errno-set convention is done by the calling wrapper.
+ */
+safe_syscall_base:
+ .cfi_startproc
+ /*
+ * The syscall calling convention is nearly the same as C:
+ * we enter with a0 == *signal_pending
+ * a1 == syscall number
+ * a2 ... a7 == syscall arguments
+ * and return the result in a0
+ * and the syscall instruction needs
+ * a7 == syscall number
+ * a0 ... a5 == syscall arguments
+ * and returns the result in a0
+ * Shuffle everything around appropriately.
+ */
+ mv t0, a0 /* signal_pending pointer */
+ mv t1, a1 /* syscall number */
+ mv a0, a2 /* syscall arguments */
+ mv a1, a3
+ mv a2, a4
+ mv a3, a5
+ mv a4, a6
+ mv a5, a7
+ mv a7, t1
+
+ /*
+ * This next sequence of code works in conjunction with the
+ * rewind_if_safe_syscall_function(). If a signal is taken
+ * and the interrupted PC is anywhere between 'safe_syscall_start'
+ * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
+ * The code sequence must therefore be able to cope with this, and
+ * the syscall instruction must be the final one in the sequence.
+ */
+safe_syscall_start:
+ /* If signal_pending is non-zero, don't do the call */
+ lw t1, 0(t0)
+ bnez t1, 0f
+ scall
+safe_syscall_end:
+ /* code path for having successfully executed the syscall */
+ ret
+
+0:
+ /* code path when we didn't execute the syscall */
+ li a0, -TARGET_ERESTARTSYS
+ ret
+ .cfi_endproc
+
+ .size safe_syscall_base, .-safe_syscall_base
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 6f0d6054ce..a27e1d0d8b 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -38,15 +38,15 @@ static int prepare_binprm(struct linux_binprm *bprm)
int retval;
if(fstat(bprm->fd, &st) < 0) {
- return(-errno);
+ return(-errno);
}
mode = st.st_mode;
if(!S_ISREG(mode)) { /* Must be regular file */
- return(-EACCES);
+ return(-EACCES);
}
if(!(mode & 0111)) { /* Must have at least one execute bit set */
- return(-EACCES);
+ return(-EACCES);
}
bprm->e_uid = geteuid();
@@ -54,7 +54,7 @@ static int prepare_binprm(struct linux_binprm *bprm)
/* Set-uid? */
if(mode & S_ISUID) {
- bprm->e_uid = st.st_uid;
+ bprm->e_uid = st.st_uid;
}
/* Set-gid? */
@@ -64,13 +64,13 @@ static int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- bprm->e_gid = st.st_gid;
+ bprm->e_gid = st.st_gid;
}
retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE);
if (retval < 0) {
- perror("prepare_binprm");
- exit(-1);
+ perror("prepare_binprm");
+ exit(-1);
}
if (retval < BPRM_BUF_SIZE) {
/* Make sure the rest of the loader won't read garbage. */
diff --git a/linux-user/main.c b/linux-user/main.c
index 923cbb753a..a0aba9cb1e 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -740,8 +740,8 @@ int main(int argc, char **argv, char **envp)
target_argc = argc - optind;
target_argv = calloc(target_argc + 1, sizeof (char *));
if (target_argv == NULL) {
- (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
- exit(EXIT_FAILURE);
+ (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+ exit(EXIT_FAILURE);
}
/*
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 41e0983ce8..e0249efe4f 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -485,11 +485,11 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
end = start + len;
real_end = HOST_PAGE_ALIGN(end);
- /*
- * Test if requested memory area fits target address space
- * It can fail only on 64-bit host with 32-bit target.
- * On any other target/host host mmap() handles this error correctly.
- */
+ /*
+ * Test if requested memory area fits target address space
+ * It can fail only on 64-bit host with 32-bit target.
+ * On any other target/host host mmap() handles this error correctly.
+ */
if (!guest_range_valid(start, len)) {
errno = ENOMEM;
goto fail;
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 2ae120a2bc..619a56950d 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -258,8 +258,8 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
/* Save Altivec registers if necessary. */
if (env->insns_flags & PPC_ALTIVEC) {
uint32_t *vrsave;
- for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
- ppc_avr_t *avr = &env->avr[i];
+ for (i = 0; i < 32; i++) {
+ ppc_avr_t *avr = cpu_avr_ptr(env, i);
ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
__put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
@@ -281,15 +281,17 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
/* Save VSX second halves */
if (env->insns_flags2 & PPC2_VSX) {
uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
- for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
- __put_user(env->vsr[i], &vsregs[i]);
+ for (i = 0; i < 32; i++) {
+ uint64_t *vsrl = cpu_vsrl_ptr(env, i);
+ __put_user(*vsrl, &vsregs[i]);
}
}
/* Save floating point registers. */
if (env->insns_flags & PPC_FLOAT) {
- for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
- __put_user(env->fpr[i], &frame->mc_fregs[i]);
+ for (i = 0; i < 32; i++) {
+ uint64_t *fpr = cpu_fpr_ptr(env, i);
+ __put_user(*fpr, &frame->mc_fregs[i]);
}
__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
}
@@ -373,8 +375,8 @@ static void restore_user_regs(CPUPPCState *env,
#else
v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
#endif
- for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
- ppc_avr_t *avr = &env->avr[i];
+ for (i = 0; i < 32; i++) {
+ ppc_avr_t *avr = cpu_avr_ptr(env, i);
ppc_avr_t *vreg = &v_regs[i];
__get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
@@ -393,16 +395,18 @@ static void restore_user_regs(CPUPPCState *env,
/* Restore VSX second halves */
if (env->insns_flags2 & PPC2_VSX) {
uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
- for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
- __get_user(env->vsr[i], &vsregs[i]);
+ for (i = 0; i < 32; i++) {
+ uint64_t *vsrl = cpu_vsrl_ptr(env, i);
+ __get_user(*vsrl, &vsregs[i]);
}
}
/* Restore floating point registers. */
if (env->insns_flags & PPC_FLOAT) {
uint64_t fpscr;
- for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
- __get_user(env->fpr[i], &frame->mc_fregs[i]);
+ for (i = 0; i < 32; i++) {
+ uint64_t *fpr = cpu_fpr_ptr(env, i);
+ __get_user(*fpr, &frame->mc_fregs[i]);
}
__get_user(fpscr, &frame->mc_fregs[32]);
env->fpscr = (uint32_t) fpscr;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dd5771ce0c..ef400cb78a 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -50,7 +50,7 @@ struct image_info {
abi_ulong env_strings;
abi_ulong file_string;
uint32_t elf_flags;
- int personality;
+ int personality;
abi_ulong alignment;
/* The fields below are used in FDPIC mode. */
@@ -174,7 +174,7 @@ extern unsigned long mmap_min_addr;
struct linux_binprm {
char buf[BPRM_BUF_SIZE] __attribute__((aligned));
abi_ulong p;
- int fd;
+ int fd;
int e_uid, e_gid;
int argc, envc;
char **argv;
@@ -474,17 +474,13 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
* functions than host-endian unaligned load/store plus tswapN.
* - The pragmas are necessary only to silence a clang false-positive
* warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 .
- * - We have to disable -Wpragmas warnings to avoid a complaint about
- * an unknown warning type from older compilers that don't know about
- * -Waddress-of-packed-member.
* - gcc has bugs in its _Pragma() support in some versions, eg
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only
* include the warning-suppression pragmas for clang
*/
-#ifdef __clang__
+#if defined(__clang__) && __has_warning("-Waddress-of-packed-member")
#define PRAGMA_DISABLE_PACKED_WARNING \
_Pragma("GCC diagnostic push"); \
- _Pragma("GCC diagnostic ignored \"-Wpragmas\""); \
_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"")
#define PRAGMA_REENABLE_PACKED_WARNING \
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 602b631b92..e2c0b37173 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -727,7 +727,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
}
#endif
- ret = -TARGET_EFAULT;
+ ret = -TARGET_EFAULT;
if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
goto out;
}
@@ -736,25 +736,25 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
__get_user(ss.ss_flags, &uss->ss_flags);
unlock_user_struct(uss, uss_addr, 0);
- ret = -TARGET_EPERM;
- if (on_sig_stack(sp))
+ ret = -TARGET_EPERM;
+ if (on_sig_stack(sp))
goto out;
- ret = -TARGET_EINVAL;
- if (ss.ss_flags != TARGET_SS_DISABLE
+ ret = -TARGET_EINVAL;
+ if (ss.ss_flags != TARGET_SS_DISABLE
&& ss.ss_flags != TARGET_SS_ONSTACK
&& ss.ss_flags != 0)
goto out;
- if (ss.ss_flags == TARGET_SS_DISABLE) {
+ if (ss.ss_flags == TARGET_SS_DISABLE) {
ss.ss_size = 0;
ss.ss_sp = 0;
- } else {
+ } else {
ret = -TARGET_ENOMEM;
if (ss.ss_size < minstacksize) {
goto out;
}
- }
+ }
target_sigaltstack_used.ss_sp = ss.ss_sp;
target_sigaltstack_used.ss_size = ss.ss_size;
diff --git a/linux-user/strace.c b/linux-user/strace.c
index d1d14945f9..7318392e57 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -647,11 +647,11 @@ print_execve(const struct syscallname *name,
for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
abi_ulong *arg_ptr, arg_addr;
- arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
+ arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
if (!arg_ptr)
return;
arg_addr = tswapal(*arg_ptr);
- unlock_user(arg_ptr, arg_ptr_addr, 0);
+ unlock_user(arg_ptr, arg_ptr_addr, 0);
if (!arg_addr)
break;
if ((s = lock_user_string(arg_addr))) {
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 280137da8c..b5786d4fc1 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -902,7 +902,7 @@ abi_long do_brk(abi_ulong new_brk)
}
target_brk = new_brk;
DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk);
- return target_brk;
+ return target_brk;
}
/* We need to allocate more memory after the brk... Note that
@@ -2352,6 +2352,45 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
break;
}
break;
+ case SOL_IPV6:
+ switch (optname) {
+ case IPV6_MTU_DISCOVER:
+ case IPV6_MTU:
+ case IPV6_V6ONLY:
+ case IPV6_RECVPKTINFO:
+ case IPV6_UNICAST_HOPS:
+ case IPV6_MULTICAST_HOPS:
+ case IPV6_MULTICAST_LOOP:
+ case IPV6_RECVERR:
+ case IPV6_RECVHOPLIMIT:
+ case IPV6_2292HOPLIMIT:
+ case IPV6_CHECKSUM:
+ if (get_user_u32(len, optlen))
+ return -TARGET_EFAULT;
+ if (len < 0)
+ return -TARGET_EINVAL;
+ lv = sizeof(lv);
+ ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
+ len = 1;
+ if (put_user_u32(len, optlen)
+ || put_user_u8(val, optval_addr))
+ return -TARGET_EFAULT;
+ } else {
+ if (len > sizeof(int))
+ len = sizeof(int);
+ if (put_user_u32(len, optlen)
+ || put_user_u32(val, optval_addr))
+ return -TARGET_EFAULT;
+ }
+ break;
+ default:
+ ret = -TARGET_ENOPROTOOPT;
+ break;
+ }
+ break;
default:
unimplemented:
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
@@ -9677,8 +9716,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
arg4 = arg5;
arg5 = arg6;
}
- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- return -TARGET_EFAULT;
+ if (arg2 == 0 && arg3 == 0) {
+ /* Special-case NULL buffer and zero length, which should succeed */
+ p = 0;
+ } else {
+ p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ }
ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, ret);
return ret;
@@ -9687,8 +9733,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
arg4 = arg5;
arg5 = arg6;
}
- if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
- return -TARGET_EFAULT;
+ if (arg2 == 0 && arg3 == 0) {
+ /* Special-case NULL buffer and zero length, which should succeed */
+ p = 0;
+ } else {
+ p = lock_user(VERIFY_READ, arg2, arg3, 1);
+ if (!p) {
+ return -TARGET_EFAULT;
+ }
+ }
ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, 0);
return ret;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 99bbce083c..12c8407144 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1807,7 +1807,7 @@ struct target_stat {
abi_ulong st_rdev;
abi_long st_size;
abi_long st_blksize;
- abi_long st_blocks; /* Number 512-byte blocks allocated. */
+ abi_long st_blocks; /* Number 512-byte blocks allocated. */
abi_ulong target_st_atime;
abi_ulong target_st_atime_nsec;
@@ -1816,7 +1816,7 @@ struct target_stat {
abi_ulong target_st_ctime;
abi_ulong target_st_ctime_nsec;
- abi_long __unused[3];
+ abi_long __unused[3];
};
#elif defined(TARGET_S390X)
struct target_stat {
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
index 0a5c0b0b29..e215ecc2a6 100644
--- a/linux-user/uaccess.c
+++ b/linux-user/uaccess.c
@@ -30,7 +30,7 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
memcpy(ghptr, hptr, len);
- unlock_user(ghptr, gaddr, len);
+ unlock_user(ghptr, gaddr, len);
} else
ret = -TARGET_EFAULT;
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index 3829b9a677..9c393df424 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -257,7 +257,7 @@ void handle_vm86_trap(CPUX86State *env, int trapno)
#define CHECK_IF_IN_TRAP() \
if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
(ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
- newflags |= TF_MASK
+ newflags |= TF_MASK
#define VM86_FAULT_RETURN \
if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
diff --git a/linux-user/x86_64/target_syscall.h b/linux-user/x86_64/target_syscall.h
index 983fb23d9b..5e221e1d9d 100644
--- a/linux-user/x86_64/target_syscall.h
+++ b/linux-user/x86_64/target_syscall.h
@@ -12,7 +12,7 @@ struct target_pt_regs {
abi_ulong rbp;
abi_ulong rbx;
/* arguments: non interrupts/non tracing syscalls only save up to here */
- abi_ulong r11;
+ abi_ulong r11;
abi_ulong r10;
abi_ulong r9;
abi_ulong r8;
diff --git a/memory.c b/memory.c
index d14c6dec1d..61d66e4441 100644
--- a/memory.c
+++ b/memory.c
@@ -39,7 +39,7 @@ static bool memory_region_update_pending;
static bool ioeventfd_update_pending;
static bool global_dirty_log = false;
-static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
+static QTAILQ_HEAD(, MemoryListener) memory_listeners
= QTAILQ_HEAD_INITIALIZER(memory_listeners);
static QTAILQ_HEAD(, AddressSpace) address_spaces
@@ -113,8 +113,7 @@ enum ListenerDirection { Forward, Reverse };
} \
break; \
case Reverse: \
- QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, \
- memory_listeners, link) { \
+ QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners, link) { \
if (_listener->_callback) { \
_listener->_callback(_listener, ##_args); \
} \
@@ -128,19 +127,17 @@ enum ListenerDirection { Forward, Reverse };
#define MEMORY_LISTENER_CALL(_as, _callback, _direction, _section, _args...) \
do { \
MemoryListener *_listener; \
- struct memory_listeners_as *list = &(_as)->listeners; \
\
switch (_direction) { \
case Forward: \
- QTAILQ_FOREACH(_listener, list, link_as) { \
+ QTAILQ_FOREACH(_listener, &(_as)->listeners, link_as) { \
if (_listener->_callback) { \
_listener->_callback(_listener, _section, ##_args); \
} \
} \
break; \
case Reverse: \
- QTAILQ_FOREACH_REVERSE(_listener, list, memory_listeners_as, \
- link_as) { \
+ QTAILQ_FOREACH_REVERSE(_listener, &(_as)->listeners, link_as) { \
if (_listener->_callback) { \
_listener->_callback(_listener, _section, ##_args); \
} \
@@ -217,6 +214,7 @@ struct FlatRange {
bool romd_mode;
bool readonly;
bool nonvolatile;
+ int has_coalesced_range;
};
#define FOR_EACH_FLAT_RANGE(var, view) \
@@ -650,6 +648,7 @@ static void render_memory_region(FlatView *view,
fr.romd_mode = mr->romd_mode;
fr.readonly = readonly;
fr.nonvolatile = nonvolatile;
+ fr.has_coalesced_range = 0;
/* Render the region itself into any gaps left by the current view. */
for (i = 0; i < view->nr && int128_nz(remain); ++i) {
@@ -850,6 +849,49 @@ static void address_space_update_ioeventfds(AddressSpace *as)
flatview_unref(view);
}
+static void flat_range_coalesced_io_del(FlatRange *fr, AddressSpace *as)
+{
+ if (!fr->has_coalesced_range) {
+ return;
+ }
+
+ if (--fr->has_coalesced_range > 0) {
+ return;
+ }
+
+ MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del,
+ int128_get64(fr->addr.start),
+ int128_get64(fr->addr.size));
+}
+
+static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as)
+{
+ MemoryRegion *mr = fr->mr;
+ CoalescedMemoryRange *cmr;
+ AddrRange tmp;
+
+ if (QTAILQ_EMPTY(&mr->coalesced)) {
+ return;
+ }
+
+ if (fr->has_coalesced_range++) {
+ return;
+ }
+
+ QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
+ tmp = addrrange_shift(cmr->addr,
+ int128_sub(fr->addr.start,
+ int128_make64(fr->offset_in_region)));
+ if (!addrrange_intersects(tmp, fr->addr)) {
+ continue;
+ }
+ tmp = addrrange_intersection(tmp, fr->addr);
+ MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add,
+ int128_get64(tmp.start),
+ int128_get64(tmp.size));
+ }
+}
+
static void address_space_update_topology_pass(AddressSpace *as,
const FlatView *old_view,
const FlatView *new_view,
@@ -882,6 +924,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
/* In old but not in new, or in both but attributes changed. */
if (!adding) {
+ flat_range_coalesced_io_del(frold, as);
MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del);
}
@@ -889,7 +932,9 @@ static void address_space_update_topology_pass(AddressSpace *as,
} else if (frold && frnew && flatrange_equal(frold, frnew)) {
/* In both and unchanged (except logging may have changed) */
- if (adding) {
+ if (!adding) {
+ flat_range_coalesced_io_del(frold, as);
+ } else {
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop);
if (frnew->dirty_log_mask & ~frold->dirty_log_mask) {
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start,
@@ -901,6 +946,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
frold->dirty_log_mask,
frnew->dirty_log_mask);
}
+ flat_range_coalesced_io_add(frnew, as);
}
++iold;
@@ -910,6 +956,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
if (adding) {
MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add);
+ flat_range_coalesced_io_add(frnew, as);
}
++inew;
@@ -2136,34 +2183,12 @@ static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpa
{
FlatView *view;
FlatRange *fr;
- CoalescedMemoryRange *cmr;
- AddrRange tmp;
- MemoryRegionSection section;
view = address_space_get_flatview(as);
FOR_EACH_FLAT_RANGE(fr, view) {
if (fr->mr == mr) {
- section = (MemoryRegionSection) {
- .fv = view,
- .offset_within_address_space = int128_get64(fr->addr.start),
- .size = fr->addr.size,
- };
-
- MEMORY_LISTENER_CALL(as, coalesced_io_del, Reverse, &section,
- int128_get64(fr->addr.start),
- int128_get64(fr->addr.size));
- QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
- tmp = addrrange_shift(cmr->addr,
- int128_sub(fr->addr.start,
- int128_make64(fr->offset_in_region)));
- if (!addrrange_intersects(tmp, fr->addr)) {
- continue;
- }
- tmp = addrrange_intersection(tmp, fr->addr);
- MEMORY_LISTENER_CALL(as, coalesced_io_add, Forward, &section,
- int128_get64(tmp.start),
- int128_get64(tmp.size));
- }
+ flat_range_coalesced_io_del(fr, as);
+ flat_range_coalesced_io_add(fr, as);
}
}
flatview_unref(view);
@@ -2663,8 +2688,7 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *as)
listener->address_space = as;
if (QTAILQ_EMPTY(&memory_listeners)
- || listener->priority >= QTAILQ_LAST(&memory_listeners,
- memory_listeners)->priority) {
+ || listener->priority >= QTAILQ_LAST(&memory_listeners)->priority) {
QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
} else {
QTAILQ_FOREACH(other, &memory_listeners, link) {
@@ -2676,8 +2700,7 @@ void memory_listener_register(MemoryListener *listener, AddressSpace *as)
}
if (QTAILQ_EMPTY(&as->listeners)
- || listener->priority >= QTAILQ_LAST(&as->listeners,
- memory_listeners)->priority) {
+ || listener->priority >= QTAILQ_LAST(&as->listeners)->priority) {
QTAILQ_INSERT_TAIL(&as->listeners, listener, link_as);
} else {
QTAILQ_FOREACH(other, &as->listeners, link_as) {
@@ -2767,7 +2790,7 @@ struct MemoryRegionList {
QTAILQ_ENTRY(MemoryRegionList) mrqueue;
};
-typedef QTAILQ_HEAD(mrqueue, MemoryRegionList) MemoryRegionListHead;
+typedef QTAILQ_HEAD(, MemoryRegionList) MemoryRegionListHead;
#define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \
int128_sub((size), int128_one())) : 0)
diff --git a/memory_mapping.c b/memory_mapping.c
index 724dd0b417..e3ec70624f 100644
--- a/memory_mapping.c
+++ b/memory_mapping.c
@@ -223,7 +223,7 @@ static void guest_phys_blocks_region_add(MemoryListener *listener,
if (!QTAILQ_EMPTY(&g->list->head)) {
hwaddr predecessor_size;
- predecessor = QTAILQ_LAST(&g->list->head, GuestPhysBlockHead);
+ predecessor = QTAILQ_LAST(&g->list->head);
predecessor_size = predecessor->target_end - predecessor->target_start;
/* the memory API guarantees monotonically increasing traversal */
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 5e90f44c2f..6426151e4f 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -116,7 +116,7 @@ typedef struct DirtyBitmapMigBitmapState {
} DirtyBitmapMigBitmapState;
typedef struct DirtyBitmapMigState {
- QSIMPLEQ_HEAD(dbms_list, DirtyBitmapMigBitmapState) dbms_list;
+ QSIMPLEQ_HEAD(, DirtyBitmapMigBitmapState) dbms_list;
bool bulk_completed;
bool no_bitmaps;
diff --git a/migration/block.c b/migration/block.c
index 4c04d937b1..0e24e18d13 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -93,12 +93,12 @@ typedef struct BlkMigBlock {
} BlkMigBlock;
typedef struct BlkMigState {
- QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
+ QSIMPLEQ_HEAD(, BlkMigDevState) bmds_list;
int64_t total_sector_sum;
bool zero_blocks;
/* Protected by lock. */
- QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
+ QSIMPLEQ_HEAD(, BlkMigBlock) blk_list;
int submitted;
int read_done;
diff --git a/migration/colo.c b/migration/colo.c
index fcff04c78c..398b239d1c 100644
--- a/migration/colo.c
+++ b/migration/colo.c
@@ -24,7 +24,9 @@
#include "trace.h"
#include "qemu/error-report.h"
#include "migration/failover.h"
+#ifdef CONFIG_REPLICATION
#include "replication.h"
+#endif
#include "net/colo-compare.h"
#include "net/colo.h"
#include "block/block.h"
@@ -201,11 +203,11 @@ void colo_do_failover(MigrationState *s)
}
}
+#ifdef CONFIG_REPLICATION
void qmp_xen_set_replication(bool enable, bool primary,
bool has_failover, bool failover,
Error **errp)
{
-#ifdef CONFIG_REPLICATION
ReplicationMode mode = primary ?
REPLICATION_MODE_PRIMARY :
REPLICATION_MODE_SECONDARY;
@@ -224,14 +226,10 @@ void qmp_xen_set_replication(bool enable, bool primary,
}
replication_stop_all(failover, failover ? NULL : errp);
}
-#else
- abort();
-#endif
}
ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
{
-#ifdef CONFIG_REPLICATION
Error *err = NULL;
ReplicationStatus *s = g_new0(ReplicationStatus, 1);
@@ -246,19 +244,13 @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp)
error_free(err);
return s;
-#else
- abort();
-#endif
}
void qmp_xen_colo_do_checkpoint(Error **errp)
{
-#ifdef CONFIG_REPLICATION
replication_do_checkpoint_all(errp);
-#else
- abort();
-#endif
}
+#endif
COLOStatus *qmp_query_colo_status(Error **errp)
{
diff --git a/migration/global_state.c b/migration/global_state.c
index 8e8ab5c51e..2c8c447239 100644
--- a/migration/global_state.c
+++ b/migration/global_state.c
@@ -42,6 +42,7 @@ int global_state_store(void)
void global_state_store_running(void)
{
const char *state = RunState_str(RUN_STATE_RUNNING);
+ assert(strlen(state) < sizeof(global_state.runstate));
strncpy((char *)global_state.runstate,
state, sizeof(global_state.runstate));
}
@@ -88,6 +89,17 @@ static int global_state_post_load(void *opaque, int version_id)
s->received = true;
trace_migrate_global_state_post_load(runstate);
+ if (strnlen((char *)s->runstate,
+ sizeof(s->runstate)) == sizeof(s->runstate)) {
+ /*
+ * This condition should never happen during migration, because
+ * all runstate names are shorter than 100 bytes (the size of
+ * s->runstate). However, a malicious stream could overflow
+ * the qapi_enum_parse() call, so we force the last character
+ * to a NUL byte.
+ */
+ s->runstate[sizeof(s->runstate) - 1] = '\0';
+ }
r = qapi_enum_parse(&RunState_lookup, runstate, -1, &local_err);
if (r == -1) {
@@ -106,7 +118,8 @@ static int global_state_pre_save(void *opaque)
GlobalState *s = opaque;
trace_migrate_global_state_pre_save((char *)s->runstate);
- s->size = strlen((char *)s->runstate) + 1;
+ s->size = strnlen((char *)s->runstate, sizeof(s->runstate)) + 1;
+ assert(s->size <= sizeof(s->runstate));
return 0;
}
diff --git a/migration/migration.c b/migration/migration.c
index 49ffb9997a..ffc4d9e556 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2408,7 +2408,7 @@ static int postcopy_start(MigrationState *ms)
qemu_mutex_lock_iothread();
trace_postcopy_start_set_run();
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
global_state_store();
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
if (ret < 0) {
@@ -2612,7 +2612,7 @@ static void migration_completion(MigrationState *s)
if (s->state == MIGRATION_STATUS_ACTIVE) {
qemu_mutex_lock_iothread();
s->downtime_start = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
s->vm_was_running = runstate_is_running();
ret = global_state_store();
diff --git a/migration/ram.c b/migration/ram.c
index 7e7deec4d8..1849979fed 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -322,7 +322,7 @@ struct RAMState {
RAMBlock *last_req_rb;
/* Queue of outstanding page requests from the destination */
QemuMutex src_page_req_mutex;
- QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
+ QSIMPLEQ_HEAD(, RAMSrcPageRequest) src_page_requests;
};
typedef struct RAMState RAMState;
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 80b59009aa..e2bbb7b5f7 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -390,6 +390,9 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
if (ret) {
error_report("Save of field %s/%s failed",
vmsd->name, field->name);
+ if (vmsd->post_save) {
+ vmsd->post_save(opaque);
+ }
return ret;
}
@@ -415,7 +418,15 @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
json_end_array(vmdesc);
}
- return vmstate_subsection_save(f, vmsd, opaque, vmdesc);
+ ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc);
+
+ if (vmsd->post_save) {
+ int ps_ret = vmsd->post_save(opaque);
+ if (!ret) {
+ ret = ps_ret;
+ }
+ }
+ return ret;
}
static const VMStateDescription *
diff --git a/monitor.c b/monitor.c
index d39390c2f2..eb39fb015b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -263,14 +263,15 @@ typedef struct QMPRequest QMPRequest;
/* QMP checker flags */
#define QMP_ACCEPT_UNKNOWNS 1
-/* Protects mon_list, monitor_qapi_event_state. */
+/* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */
static QemuMutex monitor_lock;
static GHashTable *monitor_qapi_event_state;
-static QTAILQ_HEAD(mon_list, Monitor) mon_list;
+static QTAILQ_HEAD(, Monitor) mon_list;
+static bool monitor_destroyed;
/* Protects mon_fdsets */
static QemuMutex mon_fdsets_lock;
-static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets;
+static QLIST_HEAD(, MonFdset) mon_fdsets;
static int mon_refcount;
@@ -1146,11 +1147,6 @@ static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
*/
static void qmp_unregister_commands_hack(void)
{
-#ifndef CONFIG_REPLICATION
- qmp_unregister_command(&qmp_commands, "xen-set-replication");
- qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
- qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
-#endif
#ifndef TARGET_I386
qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
qmp_unregister_command(&qmp_commands, "query-sev");
@@ -1604,7 +1600,13 @@ static void memory_dump(Monitor *mon, int count, int format, int wsize,
if (l > line_size)
l = line_size;
if (is_physical) {
- cpu_physical_memory_read(addr, buf, l);
+ AddressSpace *as = cs ? cs->as : &address_space_memory;
+ MemTxResult r = address_space_read(as, addr,
+ MEMTXATTRS_UNSPECIFIED, buf, l);
+ if (r != MEMTX_OK) {
+ monitor_printf(mon, " Cannot access memory\n");
+ break;
+ }
} else {
if (cpu_memory_rw_debug(cs, addr, buf, l, 0) < 0) {
monitor_printf(mon, " Cannot access memory\n");
@@ -3231,7 +3233,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
{
int ret;
uint64_t val;
- char *end;
+ const char *end;
while (qemu_isspace(*p)) {
p++;
@@ -4109,8 +4111,12 @@ static void monitor_qmp_dispatch(Monitor *mon, QObject *req, QObject *id)
* processing commands only on a very busy monitor. To achieve that,
* when we process one request on a specific monitor, we put that
* monitor to the end of mon_list queue.
+ *
+ * Note: if the function returned with non-NULL, then the caller will
+ * be with mon->qmp.qmp_queue_lock held, and the caller is responsible
+ * to release it.
*/
-static QMPRequest *monitor_qmp_requests_pop_any(void)
+static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void)
{
QMPRequest *req_obj = NULL;
Monitor *mon;
@@ -4120,10 +4126,11 @@ static QMPRequest *monitor_qmp_requests_pop_any(void)
QTAILQ_FOREACH(mon, &mon_list, entry) {
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
req_obj = g_queue_pop_head(mon->qmp.qmp_requests);
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
if (req_obj) {
+ /* With the lock of corresponding queue held */
break;
}
+ qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
}
if (req_obj) {
@@ -4142,30 +4149,34 @@ static QMPRequest *monitor_qmp_requests_pop_any(void)
static void monitor_qmp_bh_dispatcher(void *data)
{
- QMPRequest *req_obj = monitor_qmp_requests_pop_any();
+ QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
QDict *rsp;
bool need_resume;
+ Monitor *mon;
if (!req_obj) {
return;
}
+ mon = req_obj->mon;
/* qmp_oob_enabled() might change after "qmp_capabilities" */
- need_resume = !qmp_oob_enabled(req_obj->mon);
+ need_resume = !qmp_oob_enabled(mon) ||
+ mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+ qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
if (req_obj->req) {
trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
- monitor_qmp_dispatch(req_obj->mon, req_obj->req, req_obj->id);
+ monitor_qmp_dispatch(mon, req_obj->req, req_obj->id);
} else {
assert(req_obj->err);
rsp = qmp_error_response(req_obj->err);
req_obj->err = NULL;
- monitor_qmp_respond(req_obj->mon, rsp, NULL);
+ monitor_qmp_respond(mon, rsp, NULL);
qobject_unref(rsp);
}
if (need_resume) {
/* Pairs with the monitor_suspend() in handle_qmp_command() */
- monitor_resume(req_obj->mon);
+ monitor_resume(mon);
}
qmp_request_free(req_obj);
@@ -4173,8 +4184,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
qemu_bh_schedule(qmp_dispatcher_bh);
}
-#define QMP_REQ_QUEUE_LEN_MAX (8)
-
static void handle_qmp_command(void *opaque, QObject *req, Error *err)
{
Monitor *mon = opaque;
@@ -4216,28 +4225,14 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
qemu_mutex_lock(&mon->qmp.qmp_queue_lock);
/*
- * If OOB is not enabled on the current monitor, we'll emulate the
- * old behavior that we won't process the current monitor any more
- * until it has responded. This helps make sure that as long as
- * OOB is not enabled, the server will never drop any command.
+ * Suspend the monitor when we can't queue more requests after
+ * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume
+ * it. Note that when OOB is disabled, we queue at most one
+ * command, for backward compatibility.
*/
- if (!qmp_oob_enabled(mon)) {
+ if (!qmp_oob_enabled(mon) ||
+ mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
monitor_suspend(mon);
- } else {
- /* Drop the request if queue is full. */
- if (mon->qmp.qmp_requests->length >= QMP_REQ_QUEUE_LEN_MAX) {
- qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
- /*
- * FIXME @id's scope is just @mon, and broadcasting it is
- * wrong. If another monitor's client has a command with
- * the same ID in flight, the event will incorrectly claim
- * that command was dropped.
- */
- qapi_event_send_command_dropped(id,
- COMMAND_DROP_REASON_QUEUE_FULL);
- qmp_request_free(req_obj);
- return;
- }
}
/*
@@ -4245,6 +4240,7 @@ static void handle_qmp_command(void *opaque, QObject *req, Error *err)
* handled in time order. Ownership for req_obj, req, id,
* etc. will be delivered to the handler side.
*/
+ assert(mon->qmp.qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX);
g_queue_push_tail(mon->qmp.qmp_requests, req_obj);
qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
@@ -4297,7 +4293,7 @@ int monitor_suspend(Monitor *mon)
atomic_inc(&mon->suspend_cnt);
- if (monitor_is_qmp(mon) && mon->use_io_thread) {
+ if (mon->use_io_thread) {
/*
* Kick I/O thread to make sure this takes effect. It'll be
* evaluated again in prepare() of the watch object.
@@ -4309,6 +4305,13 @@ int monitor_suspend(Monitor *mon)
return 0;
}
+static void monitor_accept_input(void *opaque)
+{
+ Monitor *mon = opaque;
+
+ qemu_chr_fe_accept_input(&mon->chr);
+}
+
void monitor_resume(Monitor *mon)
{
if (monitor_is_hmp_non_interactive(mon)) {
@@ -4316,20 +4319,22 @@ void monitor_resume(Monitor *mon)
}
if (atomic_dec_fetch(&mon->suspend_cnt) == 0) {
- if (monitor_is_qmp(mon)) {
- /*
- * For QMP monitors that are running in the I/O thread,
- * let's kick the thread in case it's sleeping.
- */
- if (mon->use_io_thread) {
- aio_notify(iothread_get_aio_context(mon_iothread));
- }
+ AioContext *ctx;
+
+ if (mon->use_io_thread) {
+ ctx = iothread_get_aio_context(mon_iothread);
} else {
+ ctx = qemu_get_aio_context();
+ }
+
+ if (!monitor_is_qmp(mon)) {
assert(mon->rs);
readline_show_prompt(mon->rs);
}
- qemu_chr_fe_accept_input(&mon->chr);
+
+ aio_bh_schedule_oneshot(ctx, monitor_accept_input, mon);
}
+
trace_monitor_suspend(mon, -1);
}
@@ -4453,16 +4458,6 @@ static void sortcmdlist(void)
qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd);
}
-static GMainContext *monitor_get_io_context(void)
-{
- return iothread_get_g_main_context(mon_iothread);
-}
-
-static AioContext *monitor_get_aio_context(void)
-{
- return iothread_get_aio_context(mon_iothread);
-}
-
static void monitor_iothread_init(void)
{
mon_iothread = iothread_create("mon_iothread", &error_abort);
@@ -4539,8 +4534,21 @@ void error_vprintf_unless_qmp(const char *fmt, va_list ap)
static void monitor_list_append(Monitor *mon)
{
qemu_mutex_lock(&monitor_lock);
- QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
+ /*
+ * This prevents inserting new monitors during monitor_cleanup().
+ * A cleaner solution would involve the main thread telling other
+ * threads to terminate, waiting for their termination.
+ */
+ if (!monitor_destroyed) {
+ QTAILQ_INSERT_HEAD(&mon_list, mon, entry);
+ mon = NULL;
+ }
qemu_mutex_unlock(&monitor_lock);
+
+ if (mon) {
+ monitor_data_destroy(mon);
+ g_free(mon);
+ }
}
static void monitor_qmp_setup_handlers_bh(void *opaque)
@@ -4549,7 +4557,7 @@ static void monitor_qmp_setup_handlers_bh(void *opaque)
GMainContext *context;
assert(mon->use_io_thread);
- context = monitor_get_io_context();
+ context = iothread_get_g_main_context(mon_iothread);
assert(context);
qemu_chr_fe_set_handlers(&mon->chr, monitor_can_read, monitor_qmp_read,
monitor_qmp_event, NULL, mon, context, true);
@@ -4560,21 +4568,12 @@ void monitor_init(Chardev *chr, int flags)
{
Monitor *mon = g_malloc(sizeof(*mon));
bool use_readline = flags & MONITOR_USE_READLINE;
- bool use_oob = flags & MONITOR_USE_OOB;
- if (use_oob) {
- if (CHARDEV_IS_MUX(chr)) {
- error_report("Monitor out-of-band is not supported with "
- "MUX typed chardev backend");
- exit(1);
- }
- if (use_readline) {
- error_report("Monitor out-of-band is only supported by QMP");
- exit(1);
- }
- }
-
- monitor_data_init(mon, false, use_oob);
+ /* Note: we run QMP monitor in I/O thread when @chr supports that */
+ monitor_data_init(mon, false,
+ (flags & MONITOR_USE_CONTROL)
+ && qemu_chr_has_feature(chr,
+ QEMU_CHAR_FEATURE_GCONTEXT));
qemu_chr_fe_init(&mon->chr, chr, &error_abort);
mon->flags = flags;
@@ -4601,7 +4600,7 @@ void monitor_init(Chardev *chr, int flags)
* since chardev might be running in the monitor I/O
* thread. Schedule a bottom half.
*/
- aio_bh_schedule_oneshot(monitor_get_aio_context(),
+ aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread),
monitor_qmp_setup_handlers_bh, mon);
/* The bottom half will add @mon to @mon_list */
return;
@@ -4634,10 +4633,14 @@ void monitor_cleanup(void)
/* Flush output buffers and destroy monitors */
qemu_mutex_lock(&monitor_lock);
+ monitor_destroyed = true;
QTAILQ_FOREACH_SAFE(mon, &mon_list, entry, next) {
QTAILQ_REMOVE(&mon_list, mon, entry);
+ /* Permit QAPI event emission from character frontend release */
+ qemu_mutex_unlock(&monitor_lock);
monitor_flush(mon);
monitor_data_destroy(mon);
+ qemu_mutex_lock(&monitor_lock);
g_free(mon);
}
qemu_mutex_unlock(&monitor_lock);
@@ -4665,9 +4668,6 @@ QemuOptsList qemu_mon_opts = {
},{
.name = "pretty",
.type = QEMU_OPT_BOOL,
- },{
- .name = "x-oob",
- .type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
diff --git a/nbd/client.c b/nbd/client.c
index b4d457a19a..8a083c2f42 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -21,6 +21,7 @@
#include "qapi/error.h"
#include "trace.h"
#include "nbd-internal.h"
+#include "qemu/cutils.h"
/* Definitions for opaque data types */
@@ -132,8 +133,9 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
return -1;
}
if (reply->option != opt) {
- error_setg(errp, "Unexpected option type %x expected %x",
- reply->option, opt);
+ error_setg(errp, "Unexpected option type %u (%s), expected %u (%s)",
+ reply->option, nbd_opt_lookup(reply->option),
+ opt, nbd_opt_lookup(opt));
nbd_send_opt_abort(ioc);
return -1;
}
@@ -171,6 +173,8 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
goto cleanup;
}
msg[reply->length] = '\0';
+ trace_nbd_server_error_msg(reply->type,
+ nbd_reply_type_lookup(reply->type), msg);
}
switch (reply->type) {
@@ -231,18 +235,24 @@ static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
return result;
}
-/* Process another portion of the NBD_OPT_LIST reply. Set *@match if
- * the current reply matches @want or if the server does not support
- * NBD_OPT_LIST, otherwise leave @match alone. Return 0 if iteration
- * is complete, positive if more replies are expected, or negative
- * with @errp set if an unrecoverable error occurred. */
-static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
+/* nbd_receive_list:
+ * Process another portion of the NBD_OPT_LIST reply, populating any
+ * name received into *@name. If @description is non-NULL, and the
+ * server provided a description, that is also populated. The caller
+ * must eventually call g_free() on success.
+ * Returns 1 if name and description were set and iteration must continue,
+ * 0 if iteration is complete (including if OPT_LIST unsupported),
+ * -1 with @errp set if an unrecoverable error occurred.
+ */
+static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
Error **errp)
{
+ int ret = -1;
NBDOptionReply reply;
uint32_t len;
uint32_t namelen;
- char name[NBD_MAX_NAME_SIZE + 1];
+ char *local_name = NULL;
+ char *local_desc = NULL;
int error;
if (nbd_receive_option_reply(ioc, NBD_OPT_LIST, &reply, errp) < 0) {
@@ -250,9 +260,6 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
}
error = nbd_handle_reply_err(ioc, &reply, errp);
if (error <= 0) {
- /* The server did not support NBD_OPT_LIST, so set *match on
- * the assumption that any name will be accepted. */
- *match = true;
return error;
}
len = reply.length;
@@ -265,8 +272,9 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
}
return 0;
} else if (reply.type != NBD_REP_SERVER) {
- error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x",
- reply.type, NBD_REP_SERVER);
+ error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)",
+ reply.type, nbd_rep_lookup(reply.type),
+ NBD_REP_SERVER, nbd_rep_lookup(NBD_REP_SERVER));
nbd_send_opt_abort(ioc);
return -1;
}
@@ -288,45 +296,54 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
nbd_send_opt_abort(ioc);
return -1;
}
- if (namelen != strlen(want)) {
- if (nbd_drop(ioc, len, errp) < 0) {
- error_prepend(errp,
- "failed to skip export name with wrong length: ");
- nbd_send_opt_abort(ioc);
- return -1;
- }
- return 1;
- }
- assert(namelen < sizeof(name));
- if (nbd_read(ioc, name, namelen, errp) < 0) {
+ local_name = g_malloc(namelen + 1);
+ if (nbd_read(ioc, local_name, namelen, errp) < 0) {
error_prepend(errp, "failed to read export name: ");
nbd_send_opt_abort(ioc);
- return -1;
+ goto out;
}
- name[namelen] = '\0';
+ local_name[namelen] = '\0';
len -= namelen;
- if (nbd_drop(ioc, len, errp) < 0) {
- error_prepend(errp, "failed to read export description: ");
- nbd_send_opt_abort(ioc);
- return -1;
+ if (len) {
+ local_desc = g_malloc(len + 1);
+ if (nbd_read(ioc, local_desc, len, errp) < 0) {
+ error_prepend(errp, "failed to read export description: ");
+ nbd_send_opt_abort(ioc);
+ goto out;
+ }
+ local_desc[len] = '\0';
}
- if (!strcmp(name, want)) {
- *match = true;
+
+ trace_nbd_receive_list(local_name, local_desc ?: "");
+ *name = local_name;
+ local_name = NULL;
+ if (description) {
+ *description = local_desc;
+ local_desc = NULL;
}
- return 1;
+ ret = 1;
+
+ out:
+ g_free(local_name);
+ g_free(local_desc);
+ return ret;
}
-/* Returns -1 if NBD_OPT_GO proves the export @wantname cannot be
- * used, 0 if NBD_OPT_GO is unsupported (fall back to NBD_OPT_LIST and
+/*
+ * nbd_opt_info_or_go:
+ * Send option for NBD_OPT_INFO or NBD_OPT_GO and parse the reply.
+ * Returns -1 if the option proves the export @info->name cannot be
+ * used, 0 if the option is unsupported (fall back to NBD_OPT_LIST and
* NBD_OPT_EXPORT_NAME in that case), and > 0 if the export is good to
- * go (with @info populated). */
-static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
- NBDExportInfo *info, Error **errp)
+ * go (with the rest of @info populated).
+ */
+static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
+ NBDExportInfo *info, Error **errp)
{
NBDOptionReply reply;
- uint32_t len = strlen(wantname);
+ uint32_t len = strlen(info->name);
uint16_t type;
int error;
char *buf;
@@ -336,16 +353,17 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
* flags still 0 is a witness of a broken server. */
info->flags = 0;
- trace_nbd_opt_go_start(wantname);
+ assert(opt == NBD_OPT_GO || opt == NBD_OPT_INFO);
+ trace_nbd_opt_info_go_start(nbd_opt_lookup(opt), info->name);
buf = g_malloc(4 + len + 2 + 2 * info->request_sizes + 1);
stl_be_p(buf, len);
- memcpy(buf + 4, wantname, len);
+ memcpy(buf + 4, info->name, len);
/* At most one request, everything else up to server */
stw_be_p(buf + 4 + len, info->request_sizes);
if (info->request_sizes) {
stw_be_p(buf + 4 + len + 2, NBD_INFO_BLOCK_SIZE);
}
- error = nbd_send_option_request(ioc, NBD_OPT_GO,
+ error = nbd_send_option_request(ioc, opt,
4 + len + 2 + 2 * info->request_sizes,
buf, errp);
g_free(buf);
@@ -354,7 +372,7 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
}
while (1) {
- if (nbd_receive_option_reply(ioc, NBD_OPT_GO, &reply, errp) < 0) {
+ if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
error = nbd_handle_reply_err(ioc, &reply, errp);
@@ -364,8 +382,10 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
len = reply.length;
if (reply.type == NBD_REP_ACK) {
- /* Server is done sending info and moved into transmission
- phase, but make sure it sent flags */
+ /*
+ * Server is done sending info, and moved into transmission
+ * phase for NBD_OPT_GO, but make sure it sent flags
+ */
if (len) {
error_setg(errp, "server sent invalid NBD_REP_ACK");
return -1;
@@ -374,13 +394,13 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
error_setg(errp, "broken server omitted NBD_INFO_EXPORT");
return -1;
}
- trace_nbd_opt_go_success();
+ trace_nbd_opt_info_go_success(nbd_opt_lookup(opt));
return 1;
}
if (reply.type != NBD_REP_INFO) {
- error_setg(errp, "unexpected reply type %" PRIu32
- " (%s), expected %u",
- reply.type, nbd_rep_lookup(reply.type), NBD_REP_INFO);
+ error_setg(errp, "unexpected reply type %u (%s), expected %u (%s)",
+ reply.type, nbd_rep_lookup(reply.type),
+ NBD_REP_INFO, nbd_rep_lookup(NBD_REP_INFO));
nbd_send_opt_abort(ioc);
return -1;
}
@@ -468,12 +488,12 @@ static int nbd_opt_go(QIOChannel *ioc, const char *wantname,
nbd_send_opt_abort(ioc);
return -1;
}
- trace_nbd_opt_go_info_block_size(info->min_block, info->opt_block,
- info->max_block);
+ trace_nbd_opt_info_block_size(info->min_block, info->opt_block,
+ info->max_block);
break;
default:
- trace_nbd_opt_go_info_unknown(type, nbd_info_lookup(type));
+ trace_nbd_opt_info_unknown(type, nbd_info_lookup(type));
if (nbd_drop(ioc, len, errp) < 0) {
error_prepend(errp, "Failed to read info payload: ");
nbd_send_opt_abort(ioc);
@@ -489,7 +509,8 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
const char *wantname,
Error **errp)
{
- bool foundExport = false;
+ bool list_empty = true;
+ bool found_export = false;
trace_nbd_receive_query_exports_start(wantname);
if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) {
@@ -497,14 +518,25 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
}
while (1) {
- int ret = nbd_receive_list(ioc, wantname, &foundExport, errp);
+ char *name;
+ int ret = nbd_receive_list(ioc, &name, NULL, errp);
if (ret < 0) {
/* Server gave unexpected reply */
return -1;
} else if (ret == 0) {
/* Done iterating. */
- if (!foundExport) {
+ if (list_empty) {
+ /*
+ * We don't have enough context to tell a server that
+ * sent an empty list apart from a server that does
+ * not support the list command; but as this function
+ * is just used to trigger a nicer error message
+ * before trying NBD_OPT_EXPORT_NAME, assume the
+ * export is available.
+ */
+ return 0;
+ } else if (!found_export) {
error_setg(errp, "No export with name '%s' available",
wantname);
nbd_send_opt_abort(ioc);
@@ -513,6 +545,11 @@ static int nbd_receive_query_exports(QIOChannel *ioc,
trace_nbd_receive_query_exports_success(wantname);
return 0;
}
+ list_empty = false;
+ if (!strcmp(name, wantname)) {
+ found_export = true;
+ }
+ g_free(name);
}
}
@@ -601,51 +638,67 @@ static QIOChannel *nbd_receive_starttls(QIOChannel *ioc,
return QIO_CHANNEL(tioc);
}
-/* nbd_negotiate_simple_meta_context:
- * Set one meta context. Simple means that reply must contain zero (not
- * negotiated) or one (negotiated) contexts. More contexts would be considered
- * as a protocol error. It's also implied that meta-data query equals queried
- * context name, so, if server replies with something different than @context,
- * it is considered an error too.
- * return 1 for successful negotiation, context_id is set
- * 0 if operation is unsupported,
- * -1 with errp set for any other error
+/*
+ * nbd_send_meta_query:
+ * Send 0 or 1 set/list meta context queries.
+ * Return 0 on success, -1 with errp set for any error
*/
-static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
- const char *export,
- const char *context,
- uint32_t *context_id,
- Error **errp)
+static int nbd_send_meta_query(QIOChannel *ioc, uint32_t opt,
+ const char *export, const char *query,
+ Error **errp)
{
int ret;
- NBDOptionReply reply;
- uint32_t received_id = 0;
- bool received = false;
uint32_t export_len = strlen(export);
- uint32_t context_len = strlen(context);
- uint32_t data_len = sizeof(export_len) + export_len +
- sizeof(uint32_t) + /* number of queries */
- sizeof(context_len) + context_len;
- char *data = g_malloc(data_len);
- char *p = data;
-
- trace_nbd_opt_meta_request(context, export);
+ uint32_t queries = !!query;
+ uint32_t query_len = 0;
+ uint32_t data_len;
+ char *data;
+ char *p;
+
+ data_len = sizeof(export_len) + export_len + sizeof(queries);
+ if (query) {
+ query_len = strlen(query);
+ data_len += sizeof(query_len) + query_len;
+ } else {
+ assert(opt == NBD_OPT_LIST_META_CONTEXT);
+ }
+ p = data = g_malloc(data_len);
+
+ trace_nbd_opt_meta_request(nbd_opt_lookup(opt), query ?: "(all)", export);
stl_be_p(p, export_len);
memcpy(p += sizeof(export_len), export, export_len);
- stl_be_p(p += export_len, 1);
- stl_be_p(p += sizeof(uint32_t), context_len);
- memcpy(p += sizeof(context_len), context, context_len);
+ stl_be_p(p += export_len, queries);
+ if (query) {
+ stl_be_p(p += sizeof(queries), query_len);
+ memcpy(p += sizeof(query_len), query, query_len);
+ }
- ret = nbd_send_option_request(ioc, NBD_OPT_SET_META_CONTEXT, data_len, data,
- errp);
+ ret = nbd_send_option_request(ioc, opt, data_len, data, errp);
g_free(data);
- if (ret < 0) {
- return ret;
- }
+ return ret;
+}
+
+/*
+ * nbd_receive_one_meta_context:
+ * Called in a loop to receive and trace one set/list meta context reply.
+ * Pass non-NULL @name or @id to collect results back to the caller, which
+ * must eventually call g_free().
+ * return 1 if name is set and iteration must continue,
+ * 0 if iteration is complete (including if option is unsupported),
+ * -1 with errp set for any error
+ */
+static int nbd_receive_one_meta_context(QIOChannel *ioc,
+ uint32_t opt,
+ char **name,
+ uint32_t *id,
+ Error **errp)
+{
+ int ret;
+ NBDOptionReply reply;
+ char *local_name = NULL;
+ uint32_t local_id;
- if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply,
- errp) < 0)
- {
+ if (nbd_receive_option_reply(ioc, opt, &reply, errp) < 0) {
return -1;
}
@@ -654,29 +707,92 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
return ret;
}
- if (reply.type == NBD_REP_META_CONTEXT) {
- char *name;
-
- if (reply.length != sizeof(received_id) + context_len) {
- error_setg(errp, "Failed to negotiate meta context '%s', server "
- "answered with unexpected length %" PRIu32, context,
- reply.length);
+ if (reply.type == NBD_REP_ACK) {
+ if (reply.length != 0) {
+ error_setg(errp, "Unexpected length to ACK response");
nbd_send_opt_abort(ioc);
return -1;
}
+ return 0;
+ } else if (reply.type != NBD_REP_META_CONTEXT) {
+ error_setg(errp, "Unexpected reply type %u (%s), expected %u (%s)",
+ reply.type, nbd_rep_lookup(reply.type),
+ NBD_REP_META_CONTEXT, nbd_rep_lookup(NBD_REP_META_CONTEXT));
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
- if (nbd_read(ioc, &received_id, sizeof(received_id), errp) < 0) {
- return -1;
- }
- received_id = be32_to_cpu(received_id);
+ if (reply.length <= sizeof(local_id) ||
+ reply.length > NBD_MAX_BUFFER_SIZE) {
+ error_setg(errp, "Failed to negotiate meta context, server "
+ "answered with unexpected length %" PRIu32,
+ reply.length);
+ nbd_send_opt_abort(ioc);
+ return -1;
+ }
- reply.length -= sizeof(received_id);
- name = g_malloc(reply.length + 1);
- if (nbd_read(ioc, name, reply.length, errp) < 0) {
- g_free(name);
- return -1;
- }
- name[reply.length] = '\0';
+ if (nbd_read(ioc, &local_id, sizeof(local_id), errp) < 0) {
+ return -1;
+ }
+ local_id = be32_to_cpu(local_id);
+
+ reply.length -= sizeof(local_id);
+ local_name = g_malloc(reply.length + 1);
+ if (nbd_read(ioc, local_name, reply.length, errp) < 0) {
+ g_free(local_name);
+ return -1;
+ }
+ local_name[reply.length] = '\0';
+ trace_nbd_opt_meta_reply(nbd_opt_lookup(opt), local_name, local_id);
+
+ if (name) {
+ *name = local_name;
+ } else {
+ g_free(local_name);
+ }
+ if (id) {
+ *id = local_id;
+ }
+ return 1;
+}
+
+/*
+ * nbd_negotiate_simple_meta_context:
+ * Request the server to set the meta context for export @info->name
+ * using @info->x_dirty_bitmap with a fallback to "base:allocation",
+ * setting @info->context_id to the resulting id. Fail if the server
+ * responds with more than one context or with a context different
+ * than the query.
+ * return 1 for successful negotiation,
+ * 0 if operation is unsupported,
+ * -1 with errp set for any other error
+ */
+static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
+ NBDExportInfo *info,
+ Error **errp)
+{
+ /*
+ * TODO: Removing the x_dirty_bitmap hack will mean refactoring
+ * this function to request and store ids for multiple contexts
+ * (both base:allocation and a dirty bitmap), at which point this
+ * function should lose the term _simple.
+ */
+ int ret;
+ const char *context = info->x_dirty_bitmap ?: "base:allocation";
+ bool received = false;
+ char *name = NULL;
+
+ if (nbd_send_meta_query(ioc, NBD_OPT_SET_META_CONTEXT,
+ info->name, context, errp) < 0) {
+ return -1;
+ }
+
+ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT,
+ &name, &info->context_id, errp);
+ if (ret < 0) {
+ return -1;
+ }
+ if (ret == 1) {
if (strcmp(context, name)) {
error_setg(errp, "Failed to negotiate meta context '%s', server "
"answered with different context '%s'", context,
@@ -686,91 +802,115 @@ static int nbd_negotiate_simple_meta_context(QIOChannel *ioc,
return -1;
}
g_free(name);
-
- trace_nbd_opt_meta_reply(context, received_id);
received = true;
- /* receive NBD_REP_ACK */
- if (nbd_receive_option_reply(ioc, NBD_OPT_SET_META_CONTEXT, &reply,
- errp) < 0)
- {
+ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_SET_META_CONTEXT,
+ NULL, NULL, errp);
+ if (ret < 0) {
return -1;
}
-
- ret = nbd_handle_reply_err(ioc, &reply, errp);
- if (ret <= 0) {
- return ret;
- }
}
-
- if (reply.type != NBD_REP_ACK) {
- error_setg(errp, "Unexpected reply type %" PRIx32 " expected %x",
- reply.type, NBD_REP_ACK);
+ if (ret != 0) {
+ error_setg(errp, "Server answered with more than one context");
nbd_send_opt_abort(ioc);
return -1;
}
- if (reply.length) {
- error_setg(errp, "Unexpected length to ACK response");
- nbd_send_opt_abort(ioc);
+ return received;
+}
+
+/*
+ * nbd_list_meta_contexts:
+ * Request the server to list all meta contexts for export @info->name.
+ * return 0 if list is complete (even if empty),
+ * -1 with errp set for any error
+ */
+static int nbd_list_meta_contexts(QIOChannel *ioc,
+ NBDExportInfo *info,
+ Error **errp)
+{
+ int ret;
+ int seen_any = false;
+ int seen_qemu = false;
+
+ if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT,
+ info->name, NULL, errp) < 0) {
return -1;
}
- if (received) {
- *context_id = received_id;
- return 1;
+ while (1) {
+ char *context;
+
+ ret = nbd_receive_one_meta_context(ioc, NBD_OPT_LIST_META_CONTEXT,
+ &context, NULL, errp);
+ if (ret == 0 && seen_any && !seen_qemu) {
+ /*
+ * Work around qemu 3.0 bug: the server forgot to send
+ * "qemu:" replies to 0 queries. If we saw at least one
+ * reply (probably base:allocation), but none of them were
+ * qemu:, then run a more specific query to make sure.
+ */
+ seen_qemu = true;
+ if (nbd_send_meta_query(ioc, NBD_OPT_LIST_META_CONTEXT,
+ info->name, "qemu:", errp) < 0) {
+ return -1;
+ }
+ continue;
+ }
+ if (ret <= 0) {
+ return ret;
+ }
+ seen_any = true;
+ seen_qemu |= strstart(context, "qemu:", NULL);
+ info->contexts = g_renew(char *, info->contexts, ++info->n_contexts);
+ info->contexts[info->n_contexts - 1] = context;
}
-
- return 0;
}
-int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
- QCryptoTLSCreds *tlscreds, const char *hostname,
- QIOChannel **outioc, NBDExportInfo *info,
- Error **errp)
+/*
+ * nbd_start_negotiate:
+ * Start the handshake to the server. After a positive return, the server
+ * is ready to accept additional NBD_OPT requests.
+ * Returns: negative errno: failure talking to server
+ * 0: server is oldstyle, must call nbd_negotiate_finish_oldstyle
+ * 1: server is newstyle, but can only accept EXPORT_NAME
+ * 2: server is newstyle, but lacks structured replies
+ * 3: server is newstyle and set up for structured replies
+ */
+static int nbd_start_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
+ const char *hostname, QIOChannel **outioc,
+ bool structured_reply, bool *zeroes,
+ Error **errp)
{
- char buf[256];
uint64_t magic;
- int rc;
- bool zeroes = true;
- bool structured_reply = info->structured_reply;
- bool base_allocation = info->base_allocation;
-
- trace_nbd_receive_negotiate(tlscreds, hostname ? hostname : "<null>");
- info->structured_reply = false;
- info->base_allocation = false;
- rc = -EINVAL;
+ trace_nbd_start_negotiate(tlscreds, hostname ? hostname : "<null>");
+ if (zeroes) {
+ *zeroes = true;
+ }
if (outioc) {
*outioc = NULL;
}
if (tlscreds && !outioc) {
error_setg(errp, "Output I/O channel required for TLS");
- goto fail;
- }
-
- if (nbd_read(ioc, buf, 8, errp) < 0) {
- error_prepend(errp, "Failed to read data: ");
- goto fail;
+ return -EINVAL;
}
- buf[8] = '\0';
- if (strlen(buf) == 0) {
- error_setg(errp, "Server connection closed unexpectedly");
- goto fail;
+ if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) {
+ error_prepend(errp, "Failed to read initial magic: ");
+ return -EINVAL;
}
-
- magic = ldq_be_p(buf);
+ magic = be64_to_cpu(magic);
trace_nbd_receive_negotiate_magic(magic);
- if (memcmp(buf, "NBDMAGIC", 8) != 0) {
- error_setg(errp, "Invalid magic received");
- goto fail;
+ if (magic != NBD_INIT_MAGIC) {
+ error_setg(errp, "Bad initial magic received: 0x%" PRIx64, magic);
+ return -EINVAL;
}
if (nbd_read(ioc, &magic, sizeof(magic), errp) < 0) {
- error_prepend(errp, "Failed to read magic: ");
- goto fail;
+ error_prepend(errp, "Failed to read server magic: ");
+ return -EINVAL;
}
magic = be64_to_cpu(magic);
trace_nbd_receive_negotiate_magic(magic);
@@ -782,7 +922,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
if (nbd_read(ioc, &globalflags, sizeof(globalflags), errp) < 0) {
error_prepend(errp, "Failed to read server flags: ");
- goto fail;
+ return -EINVAL;
}
globalflags = be16_to_cpu(globalflags);
trace_nbd_receive_negotiate_server_flags(globalflags);
@@ -791,136 +931,316 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name,
clientflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
}
if (globalflags & NBD_FLAG_NO_ZEROES) {
- zeroes = false;
+ if (zeroes) {
+ *zeroes = false;
+ }
clientflags |= NBD_FLAG_C_NO_ZEROES;
}
/* client requested flags */
clientflags = cpu_to_be32(clientflags);
if (nbd_write(ioc, &clientflags, sizeof(clientflags), errp) < 0) {
error_prepend(errp, "Failed to send clientflags field: ");
- goto fail;
+ return -EINVAL;
}
if (tlscreds) {
if (fixedNewStyle) {
*outioc = nbd_receive_starttls(ioc, tlscreds, hostname, errp);
if (!*outioc) {
- goto fail;
+ return -EINVAL;
}
ioc = *outioc;
} else {
error_setg(errp, "Server does not support STARTTLS");
- goto fail;
+ return -EINVAL;
}
}
- if (!name) {
- trace_nbd_receive_negotiate_default_name();
- name = "";
- }
if (fixedNewStyle) {
- int result;
+ int result = 0;
if (structured_reply) {
result = nbd_request_simple_option(ioc,
NBD_OPT_STRUCTURED_REPLY,
errp);
if (result < 0) {
- goto fail;
+ return -EINVAL;
}
- info->structured_reply = result == 1;
}
+ return 2 + result;
+ } else {
+ return 1;
+ }
+ } else if (magic == NBD_CLIENT_MAGIC) {
+ if (tlscreds) {
+ error_setg(errp, "Server does not support STARTTLS");
+ return -EINVAL;
+ }
+ return 0;
+ } else {
+ error_setg(errp, "Bad server magic received: 0x%" PRIx64, magic);
+ return -EINVAL;
+ }
+}
- if (info->structured_reply && base_allocation) {
- result = nbd_negotiate_simple_meta_context(
- ioc, name, info->x_dirty_bitmap ?: "base:allocation",
- &info->meta_base_allocation_id, errp);
- if (result < 0) {
- goto fail;
- }
- info->base_allocation = result == 1;
- }
+/*
+ * nbd_negotiate_finish_oldstyle:
+ * Populate @info with the size and export flags from an oldstyle server,
+ * but does not consume 124 bytes of reserved zero padding.
+ * Returns 0 on success, -1 with @errp set on failure
+ */
+static int nbd_negotiate_finish_oldstyle(QIOChannel *ioc, NBDExportInfo *info,
+ Error **errp)
+{
+ uint32_t oldflags;
+
+ if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
+ error_prepend(errp, "Failed to read export length: ");
+ return -EINVAL;
+ }
+ info->size = be64_to_cpu(info->size);
+
+ if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) {
+ error_prepend(errp, "Failed to read export flags: ");
+ return -EINVAL;
+ }
+ oldflags = be32_to_cpu(oldflags);
+ if (oldflags & ~0xffff) {
+ error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags);
+ return -EINVAL;
+ }
+ info->flags = oldflags;
+ return 0;
+}
+
+/*
+ * nbd_receive_negotiate:
+ * Connect to server, complete negotiation, and move into transmission phase.
+ * Returns: negative errno: failure talking to server
+ * 0: server is connected
+ */
+int nbd_receive_negotiate(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
+ const char *hostname, QIOChannel **outioc,
+ NBDExportInfo *info, Error **errp)
+{
+ int result;
+ bool zeroes;
+ bool base_allocation = info->base_allocation;
- /* Try NBD_OPT_GO first - if it works, we are done (it
- * also gives us a good message if the server requires
- * TLS). If it is not available, fall back to
- * NBD_OPT_LIST for nicer error messages about a missing
- * export, then use NBD_OPT_EXPORT_NAME. */
- result = nbd_opt_go(ioc, name, info, errp);
+ assert(info->name);
+ trace_nbd_receive_negotiate_name(info->name);
+
+ result = nbd_start_negotiate(ioc, tlscreds, hostname, outioc,
+ info->structured_reply, &zeroes, errp);
+
+ info->structured_reply = false;
+ info->base_allocation = false;
+ if (tlscreds && *outioc) {
+ ioc = *outioc;
+ }
+
+ switch (result) {
+ case 3: /* newstyle, with structured replies */
+ info->structured_reply = true;
+ if (base_allocation) {
+ result = nbd_negotiate_simple_meta_context(ioc, info, errp);
if (result < 0) {
- goto fail;
- }
- if (result > 0) {
- return 0;
- }
- /* Check our desired export is present in the
- * server export list. Since NBD_OPT_EXPORT_NAME
- * cannot return an error message, running this
- * query gives us better error reporting if the
- * export name is not available.
- */
- if (nbd_receive_query_exports(ioc, name, errp) < 0) {
- goto fail;
+ return -EINVAL;
}
+ info->base_allocation = result == 1;
+ }
+ /* fall through */
+ case 2: /* newstyle, try OPT_GO */
+ /* Try NBD_OPT_GO first - if it works, we are done (it
+ * also gives us a good message if the server requires
+ * TLS). If it is not available, fall back to
+ * NBD_OPT_LIST for nicer error messages about a missing
+ * export, then use NBD_OPT_EXPORT_NAME. */
+ result = nbd_opt_info_or_go(ioc, NBD_OPT_GO, info, errp);
+ if (result < 0) {
+ return -EINVAL;
+ }
+ if (result > 0) {
+ return 0;
+ }
+ /* Check our desired export is present in the
+ * server export list. Since NBD_OPT_EXPORT_NAME
+ * cannot return an error message, running this
+ * query gives us better error reporting if the
+ * export name is not available.
+ */
+ if (nbd_receive_query_exports(ioc, info->name, errp) < 0) {
+ return -EINVAL;
}
+ /* fall through */
+ case 1: /* newstyle, but limited to EXPORT_NAME */
/* write the export name request */
- if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, name,
+ if (nbd_send_option_request(ioc, NBD_OPT_EXPORT_NAME, -1, info->name,
errp) < 0) {
- goto fail;
+ return -EINVAL;
}
/* Read the response */
if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
error_prepend(errp, "Failed to read export length: ");
- goto fail;
+ return -EINVAL;
}
info->size = be64_to_cpu(info->size);
if (nbd_read(ioc, &info->flags, sizeof(info->flags), errp) < 0) {
error_prepend(errp, "Failed to read export flags: ");
- goto fail;
+ return -EINVAL;
}
info->flags = be16_to_cpu(info->flags);
- } else if (magic == NBD_CLIENT_MAGIC) {
- uint32_t oldflags;
+ break;
+ case 0: /* oldstyle, parse length and flags */
+ if (*info->name) {
+ error_setg(errp, "Server does not support non-empty export names");
+ return -EINVAL;
+ }
+ if (nbd_negotiate_finish_oldstyle(ioc, info, errp) < 0) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return result;
+ }
+
+ trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
+ if (zeroes && nbd_drop(ioc, 124, errp) < 0) {
+ error_prepend(errp, "Failed to read reserved block: ");
+ return -EINVAL;
+ }
+ return 0;
+}
- if (name) {
- error_setg(errp, "Server does not support export names");
- goto fail;
+/* Clean up result of nbd_receive_export_list */
+void nbd_free_export_list(NBDExportInfo *info, int count)
+{
+ int i, j;
+
+ if (!info) {
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ g_free(info[i].name);
+ g_free(info[i].description);
+ for (j = 0; j < info[i].n_contexts; j++) {
+ g_free(info[i].contexts[j]);
}
- if (tlscreds) {
- error_setg(errp, "Server does not support STARTTLS");
- goto fail;
+ g_free(info[i].contexts);
+ }
+ g_free(info);
+}
+
+/*
+ * nbd_receive_export_list:
+ * Query details about a server's exports, then disconnect without
+ * going into transmission phase. Return a count of the exports listed
+ * in @info by the server, or -1 on error. Caller must free @info using
+ * nbd_free_export_list().
+ */
+int nbd_receive_export_list(QIOChannel *ioc, QCryptoTLSCreds *tlscreds,
+ const char *hostname, NBDExportInfo **info,
+ Error **errp)
+{
+ int result;
+ int count = 0;
+ int i;
+ int rc;
+ int ret = -1;
+ NBDExportInfo *array = NULL;
+ QIOChannel *sioc = NULL;
+
+ *info = NULL;
+ result = nbd_start_negotiate(ioc, tlscreds, hostname, &sioc, true, NULL,
+ errp);
+ if (tlscreds && sioc) {
+ ioc = sioc;
+ }
+
+ switch (result) {
+ case 2:
+ case 3:
+ /* newstyle - use NBD_OPT_LIST to populate array, then try
+ * NBD_OPT_INFO on each array member. If structured replies
+ * are enabled, also try NBD_OPT_LIST_META_CONTEXT. */
+ if (nbd_send_option_request(ioc, NBD_OPT_LIST, 0, NULL, errp) < 0) {
+ goto out;
+ }
+ while (1) {
+ char *name;
+ char *desc;
+
+ rc = nbd_receive_list(ioc, &name, &desc, errp);
+ if (rc < 0) {
+ goto out;
+ } else if (rc == 0) {
+ break;
+ }
+ array = g_renew(NBDExportInfo, array, ++count);
+ memset(&array[count - 1], 0, sizeof(*array));
+ array[count - 1].name = name;
+ array[count - 1].description = desc;
+ array[count - 1].structured_reply = result == 3;
}
- if (nbd_read(ioc, &info->size, sizeof(info->size), errp) < 0) {
- error_prepend(errp, "Failed to read export length: ");
- goto fail;
+ for (i = 0; i < count; i++) {
+ array[i].request_sizes = true;
+ rc = nbd_opt_info_or_go(ioc, NBD_OPT_INFO, &array[i], errp);
+ if (rc < 0) {
+ goto out;
+ } else if (rc == 0) {
+ /*
+ * Pointless to try rest of loop. If OPT_INFO doesn't work,
+ * it's unlikely that meta contexts work either
+ */
+ break;
+ }
+
+ if (result == 3 &&
+ nbd_list_meta_contexts(ioc, &array[i], errp) < 0) {
+ goto out;
+ }
}
- info->size = be64_to_cpu(info->size);
- if (nbd_read(ioc, &oldflags, sizeof(oldflags), errp) < 0) {
- error_prepend(errp, "Failed to read export flags: ");
- goto fail;
+ /* Send NBD_OPT_ABORT as a courtesy before hanging up */
+ nbd_send_opt_abort(ioc);
+ break;
+ case 1: /* newstyle, but limited to EXPORT_NAME */
+ error_setg(errp, "Server does not support export lists");
+ /* We can't even send NBD_OPT_ABORT, so merely hang up */
+ goto out;
+ case 0: /* oldstyle, parse length and flags */
+ array = g_new0(NBDExportInfo, 1);
+ array->name = g_strdup("");
+ count = 1;
+
+ if (nbd_negotiate_finish_oldstyle(ioc, array, errp) < 0) {
+ goto out;
}
- oldflags = be32_to_cpu(oldflags);
- if (oldflags & ~0xffff) {
- error_setg(errp, "Unexpected export flags %0x" PRIx32, oldflags);
- goto fail;
+
+ /* Send NBD_CMD_DISC as a courtesy to the server, but ignore all
+ * errors now that we have the information we wanted. */
+ if (nbd_drop(ioc, 124, NULL) == 0) {
+ NBDRequest request = { .type = NBD_CMD_DISC };
+
+ nbd_send_request(ioc, &request);
}
- info->flags = oldflags;
- } else {
- error_setg(errp, "Bad magic received");
- goto fail;
+ break;
+ default:
+ goto out;
}
- trace_nbd_receive_negotiate_size_flags(info->size, info->flags);
- if (zeroes && nbd_drop(ioc, 124, errp) < 0) {
- error_prepend(errp, "Failed to read reserved block: ");
- goto fail;
- }
- rc = 0;
+ *info = array;
+ array = NULL;
+ ret = count;
-fail:
- return rc;
+ out:
+ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
+ qio_channel_close(ioc, NULL);
+ object_unref(OBJECT(sioc));
+ nbd_free_export_list(array, count);
+ return ret;
}
#ifdef __linux__
@@ -1026,23 +1346,7 @@ int nbd_disconnect(int fd)
return 0;
}
-#else
-int nbd_init(int fd, QIOChannelSocket *ioc, NBDExportInfo *info,
- Error **errp)
-{
- error_setg(errp, "nbd_init is only supported on Linux");
- return -ENOTSUP;
-}
-
-int nbd_client(int fd)
-{
- return -ENOTSUP;
-}
-int nbd_disconnect(int fd)
-{
- return -ENOTSUP;
-}
-#endif
+#endif /* __linux__ */
int nbd_send_request(QIOChannel *ioc, NBDRequest *request)
{
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index eeff78d3c9..82aa221227 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -46,8 +46,9 @@
/* Size of oldstyle negotiation */
#define NBD_OLDSTYLE_NEGOTIATE_SIZE (8 + 8 + 8 + 4 + 124)
+#define NBD_INIT_MAGIC 0x4e42444d41474943LL /* ASCII "NBDMAGIC" */
#define NBD_REQUEST_MAGIC 0x25609513
-#define NBD_OPTS_MAGIC 0x49484156454F5054LL
+#define NBD_OPTS_MAGIC 0x49484156454F5054LL /* ASCII "IHAVEOPT" */
#define NBD_CLIENT_MAGIC 0x0000420281861253LL
#define NBD_REP_MAGIC 0x0003e889045565a9LL
@@ -100,11 +101,6 @@ struct NBDTLSHandshakeData {
void nbd_tls_handshake(QIOTask *task,
void *opaque);
-const char *nbd_opt_lookup(uint32_t opt);
-const char *nbd_rep_lookup(uint32_t rep);
-const char *nbd_info_lookup(uint16_t info);
-const char *nbd_cmd_lookup(uint16_t info);
-const char *nbd_err_lookup(int err);
int nbd_drop(QIOChannel *ioc, size_t size, Error **errp);
diff --git a/nbd/server.c b/nbd/server.c
index 7af0ddffb2..cb0d5634fa 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -77,8 +77,8 @@ struct NBDExport {
BlockBackend *blk;
char *name;
char *description;
- off_t dev_offset;
- off_t size;
+ uint64_t dev_offset;
+ uint64_t size;
uint16_t nbdflags;
QTAILQ_HEAD(, NBDClient) clients;
QTAILQ_ENTRY(NBDExport) next;
@@ -1455,10 +1455,11 @@ static void nbd_eject_notifier(Notifier *n, void *data)
nbd_export_close(exp);
}
-NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
- uint16_t nbdflags, void (*close)(NBDExport *),
- bool writethrough, BlockBackend *on_eject_blk,
- Error **errp)
+NBDExport *nbd_export_new(BlockDriverState *bs, uint64_t dev_offset,
+ uint64_t size, const char *name, const char *desc,
+ const char *bitmap, uint16_t nbdflags,
+ void (*close)(NBDExport *), bool writethrough,
+ BlockBackend *on_eject_blk, Error **errp)
{
AioContext *ctx;
BlockBackend *blk;
@@ -1471,6 +1472,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
* that BDRV_O_INACTIVE is cleared and the image is ready for write
* access since the export could be available before migration handover.
*/
+ assert(name);
ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
bdrv_invalidate_cache(bs, NULL);
@@ -1493,15 +1495,50 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
exp->refcount = 1;
QTAILQ_INIT(&exp->clients);
exp->blk = blk;
+ assert(dev_offset <= INT64_MAX);
exp->dev_offset = dev_offset;
+ exp->name = g_strdup(name);
+ exp->description = g_strdup(desc);
exp->nbdflags = nbdflags;
- exp->size = size < 0 ? blk_getlength(blk) : size;
- if (exp->size < 0) {
- error_setg_errno(errp, -exp->size,
- "Failed to determine the NBD export's length");
- goto fail;
+ assert(size <= INT64_MAX - dev_offset);
+ exp->size = QEMU_ALIGN_DOWN(size, BDRV_SECTOR_SIZE);
+
+ if (bitmap) {
+ BdrvDirtyBitmap *bm = NULL;
+ BlockDriverState *bs = blk_bs(blk);
+
+ while (true) {
+ bm = bdrv_find_dirty_bitmap(bs, bitmap);
+ if (bm != NULL || bs->backing == NULL) {
+ break;
+ }
+
+ bs = bs->backing->bs;
+ }
+
+ if (bm == NULL) {
+ error_setg(errp, "Bitmap '%s' is not found", bitmap);
+ goto fail;
+ }
+
+ if ((nbdflags & NBD_FLAG_READ_ONLY) && bdrv_is_writable(bs) &&
+ bdrv_dirty_bitmap_enabled(bm)) {
+ error_setg(errp,
+ "Enabled bitmap '%s' incompatible with readonly export",
+ bitmap);
+ goto fail;
+ }
+
+ if (bdrv_dirty_bitmap_user_locked(bm)) {
+ error_setg(errp, "Bitmap '%s' is in use", bitmap);
+ goto fail;
+ }
+
+ bdrv_dirty_bitmap_set_qmp_locked(bm, true);
+ exp->export_bitmap = bm;
+ exp->export_bitmap_context = g_strdup_printf("qemu:dirty-bitmap:%s",
+ bitmap);
}
- exp->size -= exp->size % BDRV_SECTOR_SIZE;
exp->close = close;
exp->ctx = blk_get_aio_context(blk);
@@ -1513,10 +1550,14 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, off_t size,
exp->eject_notifier.notify = nbd_eject_notifier;
blk_add_remove_bs_notifier(on_eject_blk, &exp->eject_notifier);
}
+ QTAILQ_INSERT_TAIL(&exports, exp, next);
+ nbd_export_get(exp);
return exp;
fail:
blk_unref(blk);
+ g_free(exp->name);
+ g_free(exp->description);
g_free(exp);
return NULL;
}
@@ -1533,43 +1574,29 @@ NBDExport *nbd_export_find(const char *name)
return NULL;
}
-void nbd_export_set_name(NBDExport *exp, const char *name)
-{
- if (exp->name == name) {
- return;
- }
-
- nbd_export_get(exp);
- if (exp->name != NULL) {
- g_free(exp->name);
- exp->name = NULL;
- QTAILQ_REMOVE(&exports, exp, next);
- nbd_export_put(exp);
- }
- if (name != NULL) {
- nbd_export_get(exp);
- exp->name = g_strdup(name);
- QTAILQ_INSERT_TAIL(&exports, exp, next);
- }
- nbd_export_put(exp);
-}
-
-void nbd_export_set_description(NBDExport *exp, const char *description)
-{
- g_free(exp->description);
- exp->description = g_strdup(description);
-}
-
void nbd_export_close(NBDExport *exp)
{
NBDClient *client, *next;
nbd_export_get(exp);
+ /*
+ * TODO: Should we expand QMP NbdServerRemoveNode enum to allow a
+ * close mode that stops advertising the export to new clients but
+ * still permits existing clients to run to completion? Because of
+ * that possibility, nbd_export_close() can be called more than
+ * once on an export.
+ */
QTAILQ_FOREACH_SAFE(client, &exp->clients, next, next) {
client_close(client, true);
}
- nbd_export_set_name(exp, NULL);
- nbd_export_set_description(exp, NULL);
+ if (exp->name) {
+ nbd_export_put(exp);
+ g_free(exp->name);
+ exp->name = NULL;
+ QTAILQ_REMOVE(&exports, exp, next);
+ }
+ g_free(exp->description);
+ exp->description = NULL;
nbd_export_put(exp);
}
@@ -1983,7 +2010,7 @@ static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset,
bool next_dirty = !dirty;
if (dirty) {
- end = bdrv_dirty_bitmap_next_zero(bitmap, begin);
+ end = bdrv_dirty_bitmap_next_zero(bitmap, begin, UINT64_MAX);
} else {
bdrv_set_dirty_iter(it, begin);
end = bdrv_dirty_iter_next(it);
@@ -2103,10 +2130,10 @@ static int nbd_co_receive_request(NBDRequestData *req, NBDRequest *request,
return -EROFS;
}
if (request->from > client->exp->size ||
- request->from + request->len > client->exp->size) {
+ request->len > client->exp->size - request->from) {
error_setg(errp, "operation past EOF; From: %" PRIu64 ", Len: %" PRIu32
", Size: %" PRIu64, request->from, request->len,
- (uint64_t)client->exp->size);
+ client->exp->size);
return (request->type == NBD_CMD_WRITE ||
request->type == NBD_CMD_WRITE_ZEROES) ? -ENOSPC : -EINVAL;
}
@@ -2430,44 +2457,3 @@ void nbd_client_new(QIOChannelSocket *sioc,
co = qemu_coroutine_create(nbd_co_client_start, client);
qemu_coroutine_enter(co);
}
-
-void nbd_export_bitmap(NBDExport *exp, const char *bitmap,
- const char *bitmap_export_name, Error **errp)
-{
- BdrvDirtyBitmap *bm = NULL;
- BlockDriverState *bs = blk_bs(exp->blk);
-
- if (exp->export_bitmap) {
- error_setg(errp, "Export bitmap is already set");
- return;
- }
-
- while (true) {
- bm = bdrv_find_dirty_bitmap(bs, bitmap);
- if (bm != NULL || bs->backing == NULL) {
- break;
- }
-
- bs = bs->backing->bs;
- }
-
- if (bm == NULL) {
- error_setg(errp, "Bitmap '%s' is not found", bitmap);
- return;
- }
-
- if (bdrv_dirty_bitmap_enabled(bm)) {
- error_setg(errp, "Bitmap '%s' is enabled", bitmap);
- return;
- }
-
- if (bdrv_dirty_bitmap_user_locked(bm)) {
- error_setg(errp, "Bitmap '%s' is in use", bitmap);
- return;
- }
-
- bdrv_dirty_bitmap_set_qmp_locked(bm, true);
- exp->export_bitmap = bm;
- exp->export_bitmap_context =
- g_strdup_printf("qemu:dirty-bitmap:%s", bitmap_export_name);
-}
diff --git a/nbd/trace-events b/nbd/trace-events
index 5e1d4afe8e..7f10ebd4e0 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -1,21 +1,23 @@
# nbd/client.c
nbd_send_option_request(uint32_t opt, const char *name, uint32_t len) "Sending option request %" PRIu32" (%s), len %" PRIu32
nbd_receive_option_reply(uint32_t option, const char *optname, uint32_t type, const char *typename, uint32_t length) "Received option reply %" PRIu32" (%s), type %" PRIu32" (%s), len %" PRIu32
+nbd_server_error_msg(uint32_t err, const char *type, const char *msg) "server reported error 0x%" PRIx32 " (%s) with additional message: %s"
nbd_reply_err_unsup(uint32_t option, const char *name) "server doesn't understand request %" PRIu32 " (%s), attempting fallback"
-nbd_opt_go_start(const char *name) "Attempting NBD_OPT_GO for export '%s'"
-nbd_opt_go_success(void) "Export is good to go"
-nbd_opt_go_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
-nbd_opt_go_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32
+nbd_receive_list(const char *name, const char *desc) "export list includes '%s', description '%s'"
+nbd_opt_info_go_start(const char *opt, const char *name) "Attempting %s for export '%s'"
+nbd_opt_info_go_success(const char *opt) "Export is ready after %s request"
+nbd_opt_info_unknown(int info, const char *name) "Ignoring unknown info %d (%s)"
+nbd_opt_info_block_size(uint32_t minimum, uint32_t preferred, uint32_t maximum) "Block sizes are 0x%" PRIx32 ", 0x%" PRIx32 ", 0x%" PRIx32
nbd_receive_query_exports_start(const char *wantname) "Querying export list for '%s'"
nbd_receive_query_exports_success(const char *wantname) "Found desired export name '%s'"
nbd_receive_starttls_new_client(void) "Setting up TLS"
nbd_receive_starttls_tls_handshake(void) "Starting TLS handshake"
-nbd_opt_meta_request(const char *context, const char *export) "Requesting to set meta context %s for export %s"
-nbd_opt_meta_reply(const char *context, uint32_t id) "Received mapping of context %s to id %" PRIu32
-nbd_receive_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
+nbd_opt_meta_request(const char *optname, const char *context, const char *export) "Requesting %s %s for export %s"
+nbd_opt_meta_reply(const char *optname, const char *context, uint32_t id) "Received %s mapping of %s to id %" PRIu32
+nbd_start_negotiate(void *tlscreds, const char *hostname) "Receiving negotiation tlscreds=%p hostname=%s"
nbd_receive_negotiate_magic(uint64_t magic) "Magic is 0x%" PRIx64
nbd_receive_negotiate_server_flags(uint32_t globalflags) "Global flags are 0x%" PRIx32
-nbd_receive_negotiate_default_name(void) "Using default NBD export name \"\""
+nbd_receive_negotiate_name(const char *name) "Requesting NBD export name '%s'"
nbd_receive_negotiate_size_flags(uint64_t size, uint16_t flags) "Size is %" PRIu64 ", export flags 0x%" PRIx16
nbd_init_set_socket(void) "Setting NBD socket"
nbd_init_set_block_size(unsigned long block_size) "Setting block size to %lu"
diff --git a/net/checksum.c b/net/checksum.c
index 4da72a6a6c..273bc9c6bc 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -43,7 +43,7 @@ uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq)
uint16_t net_checksum_finish(uint32_t sum)
{
while (sum>>16)
- sum = (sum & 0xFFFF)+(sum >> 16);
+ sum = (sum & 0xFFFF)+(sum >> 16);
return ~sum;
}
diff --git a/net/colo-compare.c b/net/colo-compare.c
index a39191d522..3e515f3023 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -30,6 +30,7 @@
#include "net/colo-compare.h"
#include "migration/colo.h"
#include "migration/migration.h"
+#include "util.h"
#define TYPE_COLO_COMPARE "colo-compare"
#define COLO_COMPARE(obj) \
@@ -129,19 +130,19 @@ static int compare_chr_send(CompareState *s,
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
- struct tcphdr *atcp, *btcp;
+ struct tcp_hdr *atcp, *btcp;
- atcp = (struct tcphdr *)(a->transport_header);
- btcp = (struct tcphdr *)(b->transport_header);
+ atcp = (struct tcp_hdr *)(a->transport_header);
+ btcp = (struct tcp_hdr *)(b->transport_header);
return ntohl(atcp->th_seq) - ntohl(btcp->th_seq);
}
static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
{
Packet *pkt = data;
- struct tcphdr *tcphd;
+ struct tcp_hdr *tcphd;
- tcphd = (struct tcphdr *)pkt->transport_header;
+ tcphd = (struct tcp_hdr *)pkt->transport_header;
pkt->tcp_seq = ntohl(tcphd->th_seq);
pkt->tcp_ack = ntohl(tcphd->th_ack);
@@ -957,6 +958,12 @@ static int find_and_check_chardev(Chardev **chr,
return 1;
}
+ if (!qemu_chr_has_feature(*chr, QEMU_CHAR_FEATURE_GCONTEXT)) {
+ error_setg(errp, "chardev \"%s\" cannot switch context",
+ chr_name);
+ return 1;
+ }
+
return 0;
}
diff --git a/net/colo.c b/net/colo.c
index 49176bf07b..8196b35837 100644
--- a/net/colo.c
+++ b/net/colo.c
@@ -15,6 +15,7 @@
#include "qemu/osdep.h"
#include "trace.h"
#include "colo.h"
+#include "util.h"
uint32_t connection_key_hash(const void *opaque)
{
diff --git a/net/colo.h b/net/colo.h
index 11c5226488..b21c6830b5 100644
--- a/net/colo.h
+++ b/net/colo.h
@@ -15,10 +15,9 @@
#ifndef QEMU_COLO_PROXY_H
#define QEMU_COLO_PROXY_H
-#include "slirp/slirp.h"
#include "qemu/jhash.h"
#include "qemu/timer.h"
-#include "slirp/tcp.h"
+#include "net/eth.h"
#define HASHTABLE_MAX_SIZE 16384
@@ -81,10 +80,10 @@ typedef struct Connection {
/* the maximum of acknowledgement number in secondary_list queue */
uint32_t sack;
/* offset = secondary_seq - primary_seq */
- tcp_seq offset;
+ uint32_t offset;
int tcp_state; /* TCP FSM state */
- tcp_seq fin_ack_seq; /* the seq of 'fin=1,ack=1' */
+ uint32_t fin_ack_seq; /* the seq of 'fin=1,ack=1' */
} Connection;
uint32_t connection_key_hash(const void *opaque);
diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c
index 2e26839bc2..b464abe5e8 100644
--- a/net/filter-rewriter.c
+++ b/net/filter-rewriter.c
@@ -22,6 +22,7 @@
#include "net/checksum.h"
#include "net/colo.h"
#include "migration/colo.h"
+#include "util.h"
#define FILTER_COLO_REWRITER(obj) \
OBJECT_CHECK(RewriterState, (obj), TYPE_FILTER_REWRITER)
@@ -73,9 +74,9 @@ static int handle_primary_tcp_pkt(RewriterState *rf,
Connection *conn,
Packet *pkt, ConnectionKey *key)
{
- struct tcphdr *tcp_pkt;
+ struct tcp_hdr *tcp_pkt;
- tcp_pkt = (struct tcphdr *)pkt->transport_header;
+ tcp_pkt = (struct tcp_hdr *)pkt->transport_header;
if (trace_event_get_state_backends(TRACE_COLO_FILTER_REWRITER_DEBUG)) {
trace_colo_filter_rewriter_pkt_info(__func__,
inet_ntoa(pkt->ip->ip_src), inet_ntoa(pkt->ip->ip_dst),
@@ -176,9 +177,9 @@ static int handle_secondary_tcp_pkt(RewriterState *rf,
Connection *conn,
Packet *pkt, ConnectionKey *key)
{
- struct tcphdr *tcp_pkt;
+ struct tcp_hdr *tcp_pkt;
- tcp_pkt = (struct tcphdr *)pkt->transport_header;
+ tcp_pkt = (struct tcp_hdr *)pkt->transport_header;
if (trace_event_get_state_backends(TRACE_COLO_FILTER_REWRITER_DEBUG)) {
trace_colo_filter_rewriter_pkt_info(__func__,
diff --git a/net/filter.c b/net/filter.c
index c9f9e5fa08..28d1930db7 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -55,7 +55,7 @@ static NetFilterState *netfilter_next(NetFilterState *nf,
next = QTAILQ_NEXT(nf, next);
} else {
/* reverse order */
- next = QTAILQ_PREV(nf, NetFilterHead, next);
+ next = QTAILQ_PREV(nf, next);
}
return next;
diff --git a/net/net.c b/net/net.c
index 1f7d626197..3acbdccd61 100644
--- a/net/net.c
+++ b/net/net.c
@@ -563,7 +563,7 @@ static ssize_t filter_receive_iov(NetClientState *nc,
}
}
} else {
- QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) {
+ QTAILQ_FOREACH_REVERSE(nf, &nc->filters, next) {
ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
iovcnt, sent_cb);
if (ret) {
diff --git a/net/queue.c b/net/queue.c
index 9c32abdb8f..61276ca4be 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -55,7 +55,7 @@ struct NetQueue {
uint32_t nq_count;
NetQueueDeliverFunc *deliver;
- QTAILQ_HEAD(packets, NetPacket) packets;
+ QTAILQ_HEAD(, NetPacket) packets;
unsigned delivering : 1;
};
diff --git a/net/slirp.c b/net/slirp.c
index f6dc03963a..f98425ee9f 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -23,6 +23,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "net/slirp.h"
@@ -37,12 +38,12 @@
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "slirp/libslirp.h"
-#include "slirp/ip6.h"
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"
+#include "util.h"
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
{
@@ -85,7 +86,7 @@ typedef struct SlirpState {
} SlirpState;
static struct slirp_config_str *slirp_configs;
-static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
+static QTAILQ_HEAD(, SlirpState) slirp_stacks =
QTAILQ_HEAD_INITIALIZER(slirp_stacks);
static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
@@ -99,7 +100,7 @@ static void slirp_smb_cleanup(SlirpState *s);
static inline void slirp_smb_cleanup(SlirpState *s) { }
#endif
-void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
+static void net_slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
{
SlirpState *s = opaque;
@@ -140,6 +141,22 @@ static NetClientInfo net_slirp_info = {
.cleanup = net_slirp_cleanup,
};
+static void net_slirp_guest_error(const char *msg)
+{
+ qemu_log_mask(LOG_GUEST_ERROR, "%s", msg);
+}
+
+static int64_t net_slirp_clock_get_ns(void)
+{
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+}
+
+static const SlirpCb slirp_cb = {
+ .output = net_slirp_output,
+ .guest_error = net_slirp_guest_error,
+ .clock_get_ns = net_slirp_clock_get_ns,
+};
+
static int net_slirp_init(NetClientState *peer, const char *model,
const char *name, int restricted,
bool ipv4, const char *vnetwork, const char *vhost,
@@ -279,17 +296,6 @@ static int net_slirp_init(NetClientState *peer, const char *model,
}
#endif
-#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
- /* No inet_pton helper before Vista... */
- if (vprefix6) {
- /* Unsupported */
- error_setg(errp, "IPv6 prefix not supported");
- return -1;
- }
- memset(&ip6_prefix, 0, sizeof(ip6_prefix));
- ip6_prefix.s6_addr[0] = 0xfe;
- ip6_prefix.s6_addr[1] = 0xc0;
-#else
if (!vprefix6) {
vprefix6 = "fec0::";
}
@@ -297,7 +303,6 @@ static int net_slirp_init(NetClientState *peer, const char *model,
error_setg(errp, "Failed to parse IPv6 prefix");
return -1;
}
-#endif
if (!vprefix6_len) {
vprefix6_len = 64;
@@ -309,10 +314,6 @@ static int net_slirp_init(NetClientState *peer, const char *model,
}
if (vhost6) {
-#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
- error_setg(errp, "IPv6 host not supported");
- return -1;
-#else
if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
error_setg(errp, "Failed to parse IPv6 host");
return -1;
@@ -321,17 +322,12 @@ static int net_slirp_init(NetClientState *peer, const char *model,
error_setg(errp, "IPv6 Host doesn't belong to network");
return -1;
}
-#endif
} else {
ip6_host = ip6_prefix;
ip6_host.s6_addr[15] |= 2;
}
if (vnameserver6) {
-#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
- error_setg(errp, "IPv6 DNS not supported");
- return -1;
-#else
if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
error_setg(errp, "Failed to parse IPv6 DNS");
return -1;
@@ -340,7 +336,6 @@ static int net_slirp_init(NetClientState *peer, const char *model,
error_setg(errp, "IPv6 DNS doesn't belong to network");
return -1;
}
-#endif
} else {
ip6_dns = ip6_prefix;
ip6_dns.s6_addr[15] |= 3;
@@ -378,7 +373,8 @@ static int net_slirp_init(NetClientState *peer, const char *model,
ipv6, ip6_prefix, vprefix6_len, ip6_host,
vhostname, tftp_server_name,
tftp_export, bootfile, dhcp,
- dns, ip6_dns, dnssearch, vdomainname, s);
+ dns, ip6_dns, dnssearch, vdomainname,
+ &slirp_cb, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
for (config = slirp_configs; config; config = config->next) {
@@ -708,8 +704,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf);
g_free(smb_conf);
- if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 ||
- slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) {
+ if (slirp_add_exec(s->slirp, NULL, smb_cmdline, &vserver_addr, 139) < 0 ||
+ slirp_add_exec(s->slirp, NULL, smb_cmdline, &vserver_addr, 445) < 0) {
slirp_smb_cleanup(s);
g_free(smb_cmdline);
error_setg(errp, "Conflicting/invalid smbserver address");
@@ -773,7 +769,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
if ((strlen(p) > 4) && !strncmp(p, "cmd:", 4)) {
- if (slirp_add_exec(s->slirp, 0, &p[4], &server, port) < 0) {
+ if (slirp_add_exec(s->slirp, NULL, &p[4], &server, port) < 0) {
error_setg(errp, "Conflicting/invalid host:port in guest "
"forwarding rule '%s'", config_str);
return -1;
@@ -800,7 +796,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
return -1;
}
- if (slirp_add_exec(s->slirp, 3, &fwd->hd, &server, port) < 0) {
+ if (slirp_add_exec(s->slirp, &fwd->hd, NULL, &server, port) < 0) {
error_setg(errp, "Conflicting/invalid host:port in guest "
"forwarding rule '%s'", config_str);
g_free(fwd);
@@ -827,10 +823,11 @@ void hmp_info_usernet(Monitor *mon, const QDict *qdict)
QTAILQ_FOREACH(s, &slirp_stacks, entry) {
int id;
bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0;
- monitor_printf(mon, "Hub %d (%s):\n",
+ char *info = slirp_connection_info(s->slirp);
+ monitor_printf(mon, "Hub %d (%s):\n%s",
got_hub_id ? id : -1,
- s->nc.name);
- slirp_connection_info(s->slirp, mon);
+ s->nc.name, info);
+ g_free(info);
}
}
diff --git a/net/util.h b/net/util.h
index 60b73d372d..358185fd50 100644
--- a/net/util.h
+++ b/net/util.h
@@ -26,6 +26,61 @@
#define QEMU_NET_UTIL_H
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip {
+#ifdef HOST_WORDS_BIGENDIAN
+ uint8_t ip_v:4, /* version */
+ ip_hl:4; /* header length */
+#else
+ uint8_t ip_hl:4, /* header length */
+ ip_v:4; /* version */
+#endif
+ uint8_t ip_tos; /* type of service */
+ uint16_t ip_len; /* total length */
+ uint16_t ip_id; /* identification */
+ uint16_t ip_off; /* fragment offset field */
+#define IP_DF 0x4000 /* don't fragment flag */
+#define IP_MF 0x2000 /* more fragments flag */
+#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
+ uint8_t ip_ttl; /* time to live */
+ uint8_t ip_p; /* protocol */
+ uint16_t ip_sum; /* checksum */
+ struct in_addr ip_src, ip_dst; /* source and dest address */
+} QEMU_PACKED;
+
+static inline bool in6_equal_net(const struct in6_addr *a,
+ const struct in6_addr *b,
+ int prefix_len)
+{
+ if (memcmp(a, b, prefix_len / 8) != 0) {
+ return 0;
+ }
+
+ if (prefix_len % 8 == 0) {
+ return 1;
+ }
+
+ return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8))
+ == b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
+}
+
+#define TCPS_CLOSED 0 /* closed */
+#define TCPS_LISTEN 1 /* listening for connection */
+#define TCPS_SYN_SENT 2 /* active, have sent syn */
+#define TCPS_SYN_RECEIVED 3 /* have send and received syn */
+/* states < TCPS_ESTABLISHED are those where connections not established */
+#define TCPS_ESTABLISHED 4 /* established */
+#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */
+/* states > TCPS_CLOSE_WAIT are those where user has closed */
+#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */
+#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */
+#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */
+/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */
+#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */
+#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */
+
int net_parse_macaddr(uint8_t *macaddr, const char *p);
#endif /* QEMU_NET_UTIL_H */
diff --git a/pc-bios/efi-e1000.rom b/pc-bios/efi-e1000.rom
index 4da9de33da..6f088d41dd 100644
--- a/pc-bios/efi-e1000.rom
+++ b/pc-bios/efi-e1000.rom
Binary files differ
diff --git a/pc-bios/efi-e1000e.rom b/pc-bios/efi-e1000e.rom
index c2474a8fab..f536bdbd45 100644
--- a/pc-bios/efi-e1000e.rom
+++ b/pc-bios/efi-e1000e.rom
Binary files differ
diff --git a/pc-bios/efi-eepro100.rom b/pc-bios/efi-eepro100.rom
index 7950faf7cd..64d8891485 100644
--- a/pc-bios/efi-eepro100.rom
+++ b/pc-bios/efi-eepro100.rom
Binary files differ
diff --git a/pc-bios/efi-ne2k_pci.rom b/pc-bios/efi-ne2k_pci.rom
index 30edb1392a..02ad0cb505 100644
--- a/pc-bios/efi-ne2k_pci.rom
+++ b/pc-bios/efi-ne2k_pci.rom
Binary files differ
diff --git a/pc-bios/efi-pcnet.rom b/pc-bios/efi-pcnet.rom
index 23057c5724..88d25fa625 100644
--- a/pc-bios/efi-pcnet.rom
+++ b/pc-bios/efi-pcnet.rom
Binary files differ
diff --git a/pc-bios/efi-rtl8139.rom b/pc-bios/efi-rtl8139.rom
index beb9301839..53f125e3bb 100644
--- a/pc-bios/efi-rtl8139.rom
+++ b/pc-bios/efi-rtl8139.rom
Binary files differ
diff --git a/pc-bios/efi-virtio.rom b/pc-bios/efi-virtio.rom
index f4de5957ec..a87321e928 100644
--- a/pc-bios/efi-virtio.rom
+++ b/pc-bios/efi-virtio.rom
Binary files differ
diff --git a/pc-bios/efi-vmxnet3.rom b/pc-bios/efi-vmxnet3.rom
index 7501477ea6..d017cafe22 100644
--- a/pc-bios/efi-vmxnet3.rom
+++ b/pc-bios/efi-vmxnet3.rom
Binary files differ
diff --git a/pc-bios/keymaps/common b/pc-bios/keymaps/common
deleted file mode 100644
index adc56c77d2..0000000000
--- a/pc-bios/keymaps/common
+++ /dev/null
@@ -1,157 +0,0 @@
-include modifiers
-
-#
-# Top row
-#
-1 0x2
-2 0x3
-3 0x4
-4 0x5
-5 0x6
-6 0x7
-7 0x8
-8 0x9
-9 0xa
-0 0xb
-BackSpace 0xe
-
-#
-# QWERTY first row
-#
-Tab 0xf localstate
-ISO_Left_Tab 0xf shift
-q 0x10 addupper
-w 0x11 addupper
-e 0x12 addupper
-r 0x13 addupper
-t 0x14 addupper
-y 0x15 addupper
-u 0x16 addupper
-i 0x17 addupper
-o 0x18 addupper
-p 0x19 addupper
-
-#
-# QWERTY second row
-#
-a 0x1e addupper
-s 0x1f addupper
-d 0x20 addupper
-f 0x21 addupper
-g 0x22 addupper
-h 0x23 addupper
-j 0x24 addupper
-k 0x25 addupper
-l 0x26 addupper
-Return 0x1c localstate
-
-#
-# QWERTY third row
-#
-z 0x2c addupper
-x 0x2d addupper
-c 0x2e addupper
-v 0x2f addupper
-b 0x30 addupper
-n 0x31 addupper
-m 0x32 addupper
-
-space 0x39 localstate
-
-less 0x56
-greater 0x56 shift
-bar 0x56 altgr
-brokenbar 0x56 shift altgr
-
-#
-# Esc and Function keys
-#
-Escape 0x1 localstate
-F1 0x3b localstate
-F2 0x3c localstate
-F3 0x3d localstate
-F4 0x3e localstate
-F5 0x3f localstate
-F6 0x40 localstate
-F7 0x41 localstate
-F8 0x42 localstate
-F9 0x43 localstate
-F10 0x44 localstate
-F11 0x57 localstate
-F12 0x58 localstate
-
-# Printscreen, Scrollock and Pause
-# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
-# but (0xe0, 0x37) seems to work.
-Print 0xb7 localstate
-Sys_Req 0xb7 localstate
-Execute 0xb7 localstate
-Scroll_Lock 0x46
-
-#
-# Insert - PgDown
-#
-Insert 0xd2 localstate
-Delete 0xd3 localstate
-Home 0xc7 localstate
-End 0xcf localstate
-Page_Up 0xc9 localstate
-Page_Down 0xd1 localstate
-
-#
-# Arrow keys
-#
-Left 0xcb localstate
-Up 0xc8 localstate
-Down 0xd0 localstate
-Right 0xcd localstate
-
-#
-# Numpad
-#
-Num_Lock 0x45
-KP_Divide 0xb5
-KP_Multiply 0x37
-KP_Subtract 0x4a
-KP_Add 0x4e
-KP_Enter 0x9c
-
-KP_Decimal 0x53 numlock
-KP_Separator 0x53 numlock
-KP_Delete 0x53
-
-KP_0 0x52 numlock
-KP_Insert 0x52
-
-KP_1 0x4f numlock
-KP_End 0x4f
-
-KP_2 0x50 numlock
-KP_Down 0x50
-
-KP_3 0x51 numlock
-KP_Next 0x51
-
-KP_4 0x4b numlock
-KP_Left 0x4b
-
-KP_5 0x4c numlock
-KP_Begin 0x4c
-
-KP_6 0x4d numlock
-KP_Right 0x4d
-
-KP_7 0x47 numlock
-KP_Home 0x47
-
-KP_8 0x48 numlock
-KP_Up 0x48
-
-KP_9 0x49 numlock
-KP_Prior 0x49
-
-Caps_Lock 0x3a
-#
-# Inhibited keys
-#
-Multi_key 0x0 inhibit
diff --git a/pc-bios/keymaps/modifiers b/pc-bios/keymaps/modifiers
deleted file mode 100644
index d73b7a6637..0000000000
--- a/pc-bios/keymaps/modifiers
+++ /dev/null
@@ -1,18 +0,0 @@
-Shift_R 0x36
-Shift_L 0x2a
-
-Alt_R 0xb8
-Mode_switch 0xb8
-ISO_Level3_Shift 0xb8
-Alt_L 0x38
-
-Control_R 0x9d
-Control_L 0x1d
-
-# Translate Super to Windows keys.
-# This is hardcoded. See documentation for details.
-Super_R 0xdc
-Super_L 0xdb
-
-# Translate Menu to the Windows Application key.
-Menu 0xdd
diff --git a/pc-bios/keymaps/nl-be b/pc-bios/keymaps/nl-be
deleted file mode 100644
index 34fc881ad0..0000000000
--- a/pc-bios/keymaps/nl-be
+++ /dev/null
@@ -1,3 +0,0 @@
-# Dutch (Belgium)
-map 0x813
-include common
diff --git a/pc-bios/keymaps/sl b/pc-bios/keymaps/sl
index 56835a92c3..73eb956d04 100644
--- a/pc-bios/keymaps/sl
+++ b/pc-bios/keymaps/sl
@@ -1,5 +1,180 @@
# generated from XKB map sl
-include common
+
+Shift_R 0x36
+Shift_L 0x2a
+
+Alt_R 0xb8
+Mode_switch 0xb8
+ISO_Level3_Shift 0xb8
+Alt_L 0x38
+
+Control_R 0x9d
+Control_L 0x1d
+
+# Translate Super to Windows keys.
+# This is hardcoded. See documentation for details.
+Super_R 0xdc
+Super_L 0xdb
+
+# Translate Menu to the Windows Application key.
+Menu 0xdd
+
+#
+# Top row
+#
+1 0x2
+2 0x3
+3 0x4
+4 0x5
+5 0x6
+6 0x7
+7 0x8
+8 0x9
+9 0xa
+0 0xb
+BackSpace 0xe
+
+#
+# QWERTY first row
+#
+Tab 0xf localstate
+ISO_Left_Tab 0xf shift
+q 0x10 addupper
+w 0x11 addupper
+e 0x12 addupper
+r 0x13 addupper
+t 0x14 addupper
+y 0x15 addupper
+u 0x16 addupper
+i 0x17 addupper
+o 0x18 addupper
+p 0x19 addupper
+
+#
+# QWERTY second row
+#
+a 0x1e addupper
+s 0x1f addupper
+d 0x20 addupper
+f 0x21 addupper
+g 0x22 addupper
+h 0x23 addupper
+j 0x24 addupper
+k 0x25 addupper
+l 0x26 addupper
+Return 0x1c localstate
+
+#
+# QWERTY third row
+#
+z 0x2c addupper
+x 0x2d addupper
+c 0x2e addupper
+v 0x2f addupper
+b 0x30 addupper
+n 0x31 addupper
+m 0x32 addupper
+
+space 0x39 localstate
+
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+brokenbar 0x56 shift altgr
+
+#
+# Esc and Function keys
+#
+Escape 0x1 localstate
+F1 0x3b localstate
+F2 0x3c localstate
+F3 0x3d localstate
+F4 0x3e localstate
+F5 0x3f localstate
+F6 0x40 localstate
+F7 0x41 localstate
+F8 0x42 localstate
+F9 0x43 localstate
+F10 0x44 localstate
+F11 0x57 localstate
+F12 0x58 localstate
+
+# Printscreen, Scrollock and Pause
+# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
+# but (0xe0, 0x37) seems to work.
+Print 0xb7 localstate
+Sys_Req 0xb7 localstate
+Execute 0xb7 localstate
+Scroll_Lock 0x46
+
+#
+# Insert - PgDown
+#
+Insert 0xd2 localstate
+Delete 0xd3 localstate
+Home 0xc7 localstate
+End 0xcf localstate
+Page_Up 0xc9 localstate
+Page_Down 0xd1 localstate
+
+#
+# Arrow keys
+#
+Left 0xcb localstate
+Up 0xc8 localstate
+Down 0xd0 localstate
+Right 0xcd localstate
+
+#
+# Numpad
+#
+Num_Lock 0x45
+KP_Divide 0xb5
+KP_Multiply 0x37
+KP_Subtract 0x4a
+KP_Add 0x4e
+KP_Enter 0x9c
+
+KP_Decimal 0x53 numlock
+KP_Separator 0x53 numlock
+KP_Delete 0x53
+
+KP_0 0x52 numlock
+KP_Insert 0x52
+
+KP_1 0x4f numlock
+KP_End 0x4f
+
+KP_2 0x50 numlock
+KP_Down 0x50
+
+KP_3 0x51 numlock
+KP_Next 0x51
+
+KP_4 0x4b numlock
+KP_Left 0x4b
+
+KP_5 0x4c numlock
+KP_Begin 0x4c
+
+KP_6 0x4d numlock
+KP_Right 0x4d
+
+KP_7 0x47 numlock
+KP_Home 0x47
+
+KP_8 0x48 numlock
+KP_Up 0x48
+
+KP_9 0x49 numlock
+KP_Prior 0x49
+
+Caps_Lock 0x3a
+#
+# Inhibited keys
+#
+Multi_key 0x0 inhibit
+
map 0x424
exclam 0x02 shift
asciitilde 0x02 altgr
diff --git a/pc-bios/keymaps/sv b/pc-bios/keymaps/sv
index 5d9080eff1..0717b7114f 100644
--- a/pc-bios/keymaps/sv
+++ b/pc-bios/keymaps/sv
@@ -1,5 +1,179 @@
map 0x0000041d
-include common
+
+Shift_R 0x36
+Shift_L 0x2a
+
+Alt_R 0xb8
+Mode_switch 0xb8
+ISO_Level3_Shift 0xb8
+Alt_L 0x38
+
+Control_R 0x9d
+Control_L 0x1d
+
+# Translate Super to Windows keys.
+# This is hardcoded. See documentation for details.
+Super_R 0xdc
+Super_L 0xdb
+
+# Translate Menu to the Windows Application key.
+Menu 0xdd
+
+#
+# Top row
+#
+1 0x2
+2 0x3
+3 0x4
+4 0x5
+5 0x6
+6 0x7
+7 0x8
+8 0x9
+9 0xa
+0 0xb
+BackSpace 0xe
+
+#
+# QWERTY first row
+#
+Tab 0xf localstate
+ISO_Left_Tab 0xf shift
+q 0x10 addupper
+w 0x11 addupper
+e 0x12 addupper
+r 0x13 addupper
+t 0x14 addupper
+y 0x15 addupper
+u 0x16 addupper
+i 0x17 addupper
+o 0x18 addupper
+p 0x19 addupper
+
+#
+# QWERTY second row
+#
+a 0x1e addupper
+s 0x1f addupper
+d 0x20 addupper
+f 0x21 addupper
+g 0x22 addupper
+h 0x23 addupper
+j 0x24 addupper
+k 0x25 addupper
+l 0x26 addupper
+Return 0x1c localstate
+
+#
+# QWERTY third row
+#
+z 0x2c addupper
+x 0x2d addupper
+c 0x2e addupper
+v 0x2f addupper
+b 0x30 addupper
+n 0x31 addupper
+m 0x32 addupper
+
+space 0x39 localstate
+
+less 0x56
+greater 0x56 shift
+bar 0x56 altgr
+brokenbar 0x56 shift altgr
+
+#
+# Esc and Function keys
+#
+Escape 0x1 localstate
+F1 0x3b localstate
+F2 0x3c localstate
+F3 0x3d localstate
+F4 0x3e localstate
+F5 0x3f localstate
+F6 0x40 localstate
+F7 0x41 localstate
+F8 0x42 localstate
+F9 0x43 localstate
+F10 0x44 localstate
+F11 0x57 localstate
+F12 0x58 localstate
+
+# Printscreen, Scrollock and Pause
+# Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
+# but (0xe0, 0x37) seems to work.
+Print 0xb7 localstate
+Sys_Req 0xb7 localstate
+Execute 0xb7 localstate
+Scroll_Lock 0x46
+
+#
+# Insert - PgDown
+#
+Insert 0xd2 localstate
+Delete 0xd3 localstate
+Home 0xc7 localstate
+End 0xcf localstate
+Page_Up 0xc9 localstate
+Page_Down 0xd1 localstate
+
+#
+# Arrow keys
+#
+Left 0xcb localstate
+Up 0xc8 localstate
+Down 0xd0 localstate
+Right 0xcd localstate
+
+#
+# Numpad
+#
+Num_Lock 0x45
+KP_Divide 0xb5
+KP_Multiply 0x37
+KP_Subtract 0x4a
+KP_Add 0x4e
+KP_Enter 0x9c
+
+KP_Decimal 0x53 numlock
+KP_Separator 0x53 numlock
+KP_Delete 0x53
+
+KP_0 0x52 numlock
+KP_Insert 0x52
+
+KP_1 0x4f numlock
+KP_End 0x4f
+
+KP_2 0x50 numlock
+KP_Down 0x50
+
+KP_3 0x51 numlock
+KP_Next 0x51
+
+KP_4 0x4b numlock
+KP_Left 0x4b
+
+KP_5 0x4c numlock
+KP_Begin 0x4c
+
+KP_6 0x4d numlock
+KP_Right 0x4d
+
+KP_7 0x47 numlock
+KP_Home 0x47
+
+KP_8 0x48 numlock
+KP_Up 0x48
+
+KP_9 0x49 numlock
+KP_Prior 0x49
+
+Caps_Lock 0x3a
+#
+# Inhibited keys
+#
+Multi_key 0x0 inhibit
#
# Top row
diff --git a/pc-bios/palcode-clipper b/pc-bios/palcode-clipper
index 1df377a0fd..fb9026ae64 100644
--- a/pc-bios/palcode-clipper
+++ b/pc-bios/palcode-clipper
Binary files differ
diff --git a/pc-bios/qemu-icon.bmp b/pc-bios/qemu-icon.bmp
deleted file mode 100644
index 72d9a2f561..0000000000
--- a/pc-bios/qemu-icon.bmp
+++ /dev/null
Binary files differ
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index eb8d024dbb..5c22cb0849 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -59,9 +59,9 @@ disabled_wait:
.globl consume_sclp_int
consume_sclp_int:
/* enable service interrupts in cr0 */
- stctg 0,0,0(15)
- oi 6(15), 0x2
- lctlg 0,0,0(15)
+ stctg %c0,%c0,0(%r15)
+ oi 6(%r15),0x2
+ lctlg %c0,%c0,0(%r15)
/* prepare external call handler */
larl %r1, external_new_code
stg %r1, 0x1b8
@@ -73,10 +73,10 @@ consume_sclp_int:
external_new_code:
/* disable service interrupts in cr0 */
- stctg 0,0,0(15)
- ni 6(15), 0xfd
- lctlg 0,0,0(15)
- br 14
+ stctg %c0,%c0,0(%r15)
+ ni 6(%r15),0xfd
+ lctlg %c0,%c0,0(%r15)
+ br %r14
.align 8
disabled_wait_psw:
diff --git a/qapi/block-core.json b/qapi/block-core.json
index d4fe710836..91685be6c2 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1143,8 +1143,10 @@
# This command is now obsolete and will always return an error since 2.10
#
##
-{ 'command': 'block_passwd', 'data': {'*device': 'str',
- '*node-name': 'str', 'password': 'str'} }
+{ 'command': 'block_passwd',
+ 'data': { '*device': 'str',
+ '*node-name': 'str',
+ 'password': 'str' } }
##
# @block_resize:
@@ -1171,9 +1173,10 @@
# <- { "return": {} }
#
##
-{ 'command': 'block_resize', 'data': { '*device': 'str',
- '*node-name': 'str',
- 'size': 'int' }}
+{ 'command': 'block_resize',
+ 'data': { '*device': 'str',
+ '*node-name': 'str',
+ 'size': 'int' } }
##
# @NewImageMode:
@@ -1803,29 +1806,29 @@
# Currently, all dirty tracking bitmaps are loaded from Qcow2 on
# open.
#
-# @x-disabled: the bitmap is created in the disabled state, which means that
-# it will not track drive changes. The bitmap may be enabled with
-# x-block-dirty-bitmap-enable. Default is false. (Since: 3.0)
+# @disabled: the bitmap is created in the disabled state, which means that
+# it will not track drive changes. The bitmap may be enabled with
+# block-dirty-bitmap-enable. Default is false. (Since: 4.0)
#
# Since: 2.4
##
{ 'struct': 'BlockDirtyBitmapAdd',
'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32',
- '*persistent': 'bool', '*autoload': 'bool', '*x-disabled': 'bool' } }
+ '*persistent': 'bool', '*autoload': 'bool', '*disabled': 'bool' } }
##
# @BlockDirtyBitmapMerge:
#
# @node: name of device/node which the bitmap is tracking
#
-# @dst_name: name of the destination dirty bitmap
+# @target: name of the destination dirty bitmap
#
-# @src_name: name of the source dirty bitmap
+# @bitmaps: name(s) of the source dirty bitmap(s)
#
-# Since: 3.0
+# Since: 4.0
##
{ 'struct': 'BlockDirtyBitmapMerge',
- 'data': { 'node': 'str', 'dst_name': 'str', 'src_name': 'str' } }
+ 'data': { 'node': 'str', 'target': 'str', 'bitmaps': ['str'] } }
##
# @block-dirty-bitmap-add:
@@ -1896,7 +1899,7 @@
'data': 'BlockDirtyBitmap' }
##
-# @x-block-dirty-bitmap-enable:
+# @block-dirty-bitmap-enable:
#
# Enables a dirty bitmap so that it will begin tracking disk changes.
#
@@ -1904,20 +1907,20 @@
# If @node is not a valid block device, DeviceNotFound
# If @name is not found, GenericError with an explanation
#
-# Since: 3.0
+# Since: 4.0
#
# Example:
#
-# -> { "execute": "x-block-dirty-bitmap-enable",
+# -> { "execute": "block-dirty-bitmap-enable",
# "arguments": { "node": "drive0", "name": "bitmap0" } }
# <- { "return": {} }
#
##
- { 'command': 'x-block-dirty-bitmap-enable',
+ { 'command': 'block-dirty-bitmap-enable',
'data': 'BlockDirtyBitmap' }
##
-# @x-block-dirty-bitmap-disable:
+# @block-dirty-bitmap-disable:
#
# Disables a dirty bitmap so that it will stop tracking disk changes.
#
@@ -1925,42 +1928,42 @@
# If @node is not a valid block device, DeviceNotFound
# If @name is not found, GenericError with an explanation
#
-# Since: 3.0
+# Since: 4.0
#
# Example:
#
-# -> { "execute": "x-block-dirty-bitmap-disable",
+# -> { "execute": "block-dirty-bitmap-disable",
# "arguments": { "node": "drive0", "name": "bitmap0" } }
# <- { "return": {} }
#
##
- { 'command': 'x-block-dirty-bitmap-disable',
+ { 'command': 'block-dirty-bitmap-disable',
'data': 'BlockDirtyBitmap' }
##
-# @x-block-dirty-bitmap-merge:
+# @block-dirty-bitmap-merge:
#
-# FIXME: Rename @src_name and @dst_name to src-name and dst-name.
-#
-# Merge @src_name dirty bitmap to @dst_name dirty bitmap. @src_name dirty
-# bitmap is unchanged. On error, @dst_name is unchanged.
+# Merge dirty bitmaps listed in @bitmaps to the @target dirty bitmap.
+# The @bitmaps dirty bitmaps are unchanged.
+# On error, @target is unchanged.
#
# Returns: nothing on success
# If @node is not a valid block device, DeviceNotFound
-# If @dst_name or @src_name is not found, GenericError
-# If bitmaps has different sizes or granularities, GenericError
+# If any bitmap in @bitmaps or @target is not found, GenericError
+# If any of the bitmaps have different sizes or granularities,
+# GenericError
#
-# Since: 3.0
+# Since: 4.0
#
# Example:
#
-# -> { "execute": "x-block-dirty-bitmap-merge",
-# "arguments": { "node": "drive0", "dst_name": "bitmap0",
-# "src_name": "bitmap1" } }
+# -> { "execute": "block-dirty-bitmap-merge",
+# "arguments": { "node": "drive0", "target": "bitmap0",
+# "bitmaps": ["bitmap1"] } }
# <- { "return": {} }
#
##
- { 'command': 'x-block-dirty-bitmap-merge',
+ { 'command': 'block-dirty-bitmap-merge',
'data': 'BlockDirtyBitmapMerge' }
##
@@ -2620,7 +2623,9 @@
'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
- 'qcow2', 'qed', 'quorum', 'raw', 'rbd', 'replication', 'sheepdog',
+ 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
+ { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
+ 'sheepdog',
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
##
@@ -3377,7 +3382,8 @@
#
# Since: 2.9
##
-{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
+{ 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ],
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @BlockdevOptionsReplication:
@@ -3395,7 +3401,8 @@
{ 'struct': 'BlockdevOptionsReplication',
'base': 'BlockdevOptionsGenericFormat',
'data': { 'mode': 'ReplicationMode',
- '*top-id': 'str' } }
+ '*top-id': 'str' },
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @NFSTransport:
@@ -3711,7 +3718,8 @@
'quorum': 'BlockdevOptionsQuorum',
'raw': 'BlockdevOptionsRaw',
'rbd': 'BlockdevOptionsRbd',
- 'replication':'BlockdevOptionsReplication',
+ 'replication': { 'type': 'BlockdevOptionsReplication',
+ 'if': 'defined(CONFIG_REPLICATION)' },
'sheepdog': 'BlockdevOptionsSheepdog',
'ssh': 'BlockdevOptionsSsh',
'throttle': 'BlockdevOptionsThrottle',
diff --git a/qapi/block.json b/qapi/block.json
index 11f01f28ef..5a79d639e8 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -246,6 +246,10 @@
#
# @writable: Whether clients should be able to write to the device via the
# NBD connection (default false).
+
+# @bitmap: Also export the dirty bitmap reachable from @device, so the
+# NBD client can use NBD_OPT_SET_META_CONTEXT with
+# "qemu:dirty-bitmap:NAME" to inspect the bitmap. (since 4.0)
#
# Returns: error if the server is not running, or export with the same name
# already exists.
@@ -253,7 +257,8 @@
# Since: 1.3.0
##
{ 'command': 'nbd-server-add',
- 'data': {'device': 'str', '*name': 'str', '*writable': 'bool'} }
+ 'data': {'device': 'str', '*name': 'str', '*writable': 'bool',
+ '*bitmap': 'str' } }
##
# @NbdServerRemoveMode:
@@ -297,29 +302,6 @@
'data': {'name': 'str', '*mode': 'NbdServerRemoveMode'} }
##
-# @x-nbd-server-add-bitmap:
-#
-# Expose a dirty bitmap associated with the selected export. The bitmap search
-# starts at the device attached to the export, and includes all backing files.
-# The exported bitmap is then locked until the NBD export is removed.
-#
-# @name: Export name.
-#
-# @bitmap: Bitmap name to search for.
-#
-# @bitmap-export-name: How the bitmap will be seen by nbd clients
-# (default @bitmap)
-#
-# Note: the client must use NBD_OPT_SET_META_CONTEXT with a query of
-# "qemu:dirty-bitmap:NAME" (where NAME matches @bitmap-export-name) to access
-# the exposed bitmap.
-#
-# Since: 3.0
-##
- { 'command': 'x-nbd-server-add-bitmap',
- 'data': {'name': 'str', 'bitmap': 'str', '*bitmap-export-name': 'str'} }
-
-##
# @nbd-server-stop:
#
# Stop QEMU's embedded NBD server, and unregister all devices previously
diff --git a/qapi/char.json b/qapi/char.json
index 79bac598a0..77ed847972 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -25,9 +25,10 @@
#
# Since: 0.14.0
##
-{ 'struct': 'ChardevInfo', 'data': {'label': 'str',
- 'filename': 'str',
- 'frontend-open': 'bool'} }
+{ 'struct': 'ChardevInfo',
+ 'data': { 'label': 'str',
+ 'filename': 'str',
+ 'frontend-open': 'bool' } }
##
# @query-chardev:
@@ -152,7 +153,8 @@
#
##
{ 'command': 'ringbuf-write',
- 'data': {'device': 'str', 'data': 'str',
+ 'data': { 'device': 'str',
+ 'data': 'str',
'*format': 'DataFormat'} }
##
@@ -202,8 +204,9 @@
#
# Since: 2.6
##
-{ 'struct': 'ChardevCommon', 'data': { '*logfile': 'str',
- '*logappend': 'bool' } }
+{ 'struct': 'ChardevCommon',
+ 'data': { '*logfile': 'str',
+ '*logappend': 'bool' } }
##
# @ChardevFile:
@@ -217,9 +220,10 @@
#
# Since: 1.4
##
-{ 'struct': 'ChardevFile', 'data': { '*in' : 'str',
- 'out' : 'str',
- '*append': 'bool' },
+{ 'struct': 'ChardevFile',
+ 'data': { '*in': 'str',
+ 'out': 'str',
+ '*append': 'bool' },
'base': 'ChardevCommon' }
##
@@ -232,7 +236,8 @@
#
# Since: 1.4
##
-{ 'struct': 'ChardevHostdev', 'data': { 'device' : 'str' },
+{ 'struct': 'ChardevHostdev',
+ 'data': { 'device': 'str' },
'base': 'ChardevCommon' }
##
@@ -260,15 +265,16 @@
#
# Since: 1.4
##
-{ 'struct': 'ChardevSocket', 'data': { 'addr' : 'SocketAddressLegacy',
- '*tls-creds' : 'str',
- '*server' : 'bool',
- '*wait' : 'bool',
- '*nodelay' : 'bool',
- '*telnet' : 'bool',
- '*tn3270' : 'bool',
- '*websocket' : 'bool',
- '*reconnect' : 'int' },
+{ 'struct': 'ChardevSocket',
+ 'data': { 'addr': 'SocketAddressLegacy',
+ '*tls-creds': 'str',
+ '*server': 'bool',
+ '*wait': 'bool',
+ '*nodelay': 'bool',
+ '*telnet': 'bool',
+ '*tn3270': 'bool',
+ '*websocket': 'bool',
+ '*reconnect': 'int' },
'base': 'ChardevCommon' }
##
@@ -281,8 +287,9 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevUdp', 'data': { 'remote' : 'SocketAddressLegacy',
- '*local' : 'SocketAddressLegacy' },
+{ 'struct': 'ChardevUdp',
+ 'data': { 'remote': 'SocketAddressLegacy',
+ '*local': 'SocketAddressLegacy' },
'base': 'ChardevCommon' }
##
@@ -294,7 +301,8 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevMux', 'data': { 'chardev' : 'str' },
+{ 'struct': 'ChardevMux',
+ 'data': { 'chardev': 'str' },
'base': 'ChardevCommon' }
##
@@ -308,7 +316,8 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevStdio', 'data': { '*signal' : 'bool' },
+{ 'struct': 'ChardevStdio',
+ 'data': { '*signal': 'bool' },
'base': 'ChardevCommon' }
@@ -321,9 +330,10 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevSpiceChannel', 'data': { 'type' : 'str' },
- 'base': 'ChardevCommon' }
-# TODO: 'if': 'defined(CONFIG_SPICE)'
+{ 'struct': 'ChardevSpiceChannel',
+ 'data': { 'type': 'str' },
+ 'base': 'ChardevCommon',
+ 'if': 'defined(CONFIG_SPICE)' }
##
# @ChardevSpicePort:
@@ -334,9 +344,10 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevSpicePort', 'data': { 'fqdn' : 'str' },
- 'base': 'ChardevCommon' }
-# TODO: 'if': 'defined(CONFIG_SPICE)'
+{ 'struct': 'ChardevSpicePort',
+ 'data': { 'fqdn': 'str' },
+ 'base': 'ChardevCommon',
+ 'if': 'defined(CONFIG_SPICE)' }
##
# @ChardevVC:
@@ -350,10 +361,11 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevVC', 'data': { '*width' : 'int',
- '*height' : 'int',
- '*cols' : 'int',
- '*rows' : 'int' },
+{ 'struct': 'ChardevVC',
+ 'data': { '*width': 'int',
+ '*height': 'int',
+ '*cols': 'int',
+ '*rows': 'int' },
'base': 'ChardevCommon' }
##
@@ -365,7 +377,8 @@
#
# Since: 1.5
##
-{ 'struct': 'ChardevRingbuf', 'data': { '*size' : 'int' },
+{ 'struct': 'ChardevRingbuf',
+ 'data': { '*size': 'int' },
'base': 'ChardevCommon' }
##
@@ -375,29 +388,30 @@
#
# Since: 1.4 (testdev since 2.2, wctablet since 2.9)
##
-{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
- 'serial' : 'ChardevHostdev',
- 'parallel': 'ChardevHostdev',
- 'pipe' : 'ChardevHostdev',
- 'socket' : 'ChardevSocket',
- 'udp' : 'ChardevUdp',
- 'pty' : 'ChardevCommon',
- 'null' : 'ChardevCommon',
- 'mux' : 'ChardevMux',
- 'msmouse': 'ChardevCommon',
- 'wctablet' : 'ChardevCommon',
- 'braille': 'ChardevCommon',
- 'testdev': 'ChardevCommon',
- 'stdio' : 'ChardevStdio',
- 'console': 'ChardevCommon',
- 'spicevmc': 'ChardevSpiceChannel',
-# TODO: { 'type': 'ChardevSpiceChannel', 'if': 'defined(CONFIG_SPICE)' },
- 'spiceport': 'ChardevSpicePort',
-# TODO: { 'type': 'ChardevSpicePort', 'if': 'defined(CONFIG_SPICE)' },
- 'vc' : 'ChardevVC',
- 'ringbuf': 'ChardevRingbuf',
- # next one is just for compatibility
- 'memory' : 'ChardevRingbuf' } }
+{ 'union': 'ChardevBackend',
+ 'data': { 'file': 'ChardevFile',
+ 'serial': 'ChardevHostdev',
+ 'parallel': 'ChardevHostdev',
+ 'pipe': 'ChardevHostdev',
+ 'socket': 'ChardevSocket',
+ 'udp': 'ChardevUdp',
+ 'pty': 'ChardevCommon',
+ 'null': 'ChardevCommon',
+ 'mux': 'ChardevMux',
+ 'msmouse': 'ChardevCommon',
+ 'wctablet': 'ChardevCommon',
+ 'braille': 'ChardevCommon',
+ 'testdev': 'ChardevCommon',
+ 'stdio': 'ChardevStdio',
+ 'console': 'ChardevCommon',
+ 'spicevmc': { 'type': 'ChardevSpiceChannel',
+ 'if': 'defined(CONFIG_SPICE)' },
+ 'spiceport': { 'type': 'ChardevSpicePort',
+ 'if': 'defined(CONFIG_SPICE)' },
+ 'vc': 'ChardevVC',
+ 'ringbuf': 'ChardevRingbuf',
+ # next one is just for compatibility
+ 'memory': 'ChardevRingbuf' } }
##
# @ChardevReturn:
@@ -409,7 +423,8 @@
#
# Since: 1.4
##
-{ 'struct' : 'ChardevReturn', 'data': { '*pty' : 'str' } }
+{ 'struct' : 'ChardevReturn',
+ 'data': { '*pty': 'str' } }
##
# @chardev-add:
@@ -442,8 +457,9 @@
# <- { "return": { "pty" : "/dev/pty/42" } }
#
##
-{ 'command': 'chardev-add', 'data': {'id' : 'str',
- 'backend' : 'ChardevBackend' },
+{ 'command': 'chardev-add',
+ 'data': { 'id': 'str',
+ 'backend': 'ChardevBackend' },
'returns': 'ChardevReturn' }
##
@@ -482,8 +498,9 @@
# <- {"return": {}}
#
##
-{ 'command': 'chardev-change', 'data': {'id' : 'str',
- 'backend' : 'ChardevBackend' },
+{ 'command': 'chardev-change',
+ 'data': { 'id': 'str',
+ 'backend': 'ChardevBackend' },
'returns': 'ChardevReturn' }
##
@@ -503,7 +520,8 @@
# <- { "return": {} }
#
##
-{ 'command': 'chardev-remove', 'data': {'id': 'str'} }
+{ 'command': 'chardev-remove',
+ 'data': { 'id': 'str' } }
##
# @chardev-send-break:
@@ -522,7 +540,8 @@
# <- { "return": {} }
#
##
-{ 'command': 'chardev-send-break', 'data': {'id': 'str'} }
+{ 'command': 'chardev-send-break',
+ 'data': { 'id': 'str' } }
##
# @VSERPORT_CHANGE:
@@ -543,4 +562,5 @@
#
##
{ 'event': 'VSERPORT_CHANGE',
- 'data': { 'id': 'str', 'open': 'bool' } }
+ 'data': { 'id': 'str',
+ 'open': 'bool' } }
diff --git a/qapi/common.json b/qapi/common.json
index 021174f04e..99d313ef3b 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -128,6 +128,48 @@
'data': [ 'off', 'auto', 'bar0', 'bar1', 'bar2', 'bar3', 'bar4', 'bar5' ] }
##
+# @PCIELinkSpeed:
+#
+# An enumeration of PCIe link speeds in units of GT/s
+#
+# @2_5: 2.5GT/s
+#
+# @5: 5.0GT/s
+#
+# @8: 8.0GT/s
+#
+# @16: 16.0GT/s
+#
+# Since: 4.0
+##
+{ 'enum': 'PCIELinkSpeed',
+ 'data': [ '2_5', '5', '8', '16' ] }
+
+##
+# @PCIELinkWidth:
+#
+# An enumeration of PCIe link width
+#
+# @1: x1
+#
+# @2: x2
+#
+# @4: x4
+#
+# @8: x8
+#
+# @12: x12
+#
+# @16: x16
+#
+# @32: x32
+#
+# Since: 4.0
+##
+{ 'enum': 'PCIELinkWidth',
+ 'data': [ '1', '2', '4', '8', '12', '16', '32' ] }
+
+##
# @SysEmuTarget:
#
# The comprehensive enumeration of QEMU system emulation ("softmmu")
diff --git a/qapi/crypto.json b/qapi/crypto.json
index a51b434412..b2a4cff683 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -181,11 +181,11 @@
# The options that apply to LUKS encryption format initialization
#
# @cipher-alg: the cipher algorithm for data encryption
-# Currently defaults to 'aes'.
+# Currently defaults to 'aes-256'.
# @cipher-mode: the cipher mode for data encryption
-# Currently defaults to 'cbc'
+# Currently defaults to 'xts'
# @ivgen-alg: the initialization vector generator
-# Currently defaults to 'essiv'
+# Currently defaults to 'plain64'
# @ivgen-hash-alg: the initialization vector generator hash
# Currently defaults to 'sha256'
# @hash-alg: the master key hash algorithm
diff --git a/qapi/migration.json b/qapi/migration.json
index 38d4c41d88..31b589ec26 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1257,7 +1257,8 @@
# Since: 2.9
##
{ 'command': 'xen-set-replication',
- 'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' } }
+ 'data': { 'enable': 'bool', 'primary': 'bool', '*failover' : 'bool' },
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @ReplicationStatus:
@@ -1272,7 +1273,8 @@
# Since: 2.9
##
{ 'struct': 'ReplicationStatus',
- 'data': { 'error': 'bool', '*desc': 'str' } }
+ 'data': { 'error': 'bool', '*desc': 'str' },
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @query-xen-replication-status:
@@ -1289,7 +1291,8 @@
# Since: 2.9
##
{ 'command': 'query-xen-replication-status',
- 'returns': 'ReplicationStatus' }
+ 'returns': 'ReplicationStatus',
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @xen-colo-do-checkpoint:
@@ -1305,7 +1308,8 @@
#
# Since: 2.9
##
-{ 'command': 'xen-colo-do-checkpoint' }
+{ 'command': 'xen-colo-do-checkpoint',
+ 'if': 'defined(CONFIG_REPLICATION)' }
##
# @COLOStatus:
@@ -1356,7 +1360,8 @@
#
# Since: 3.0
##
-{ 'command': 'migrate-recover', 'data': { 'uri': 'str' },
+{ 'command': 'migrate-recover',
+ 'data': { 'uri': 'str' },
'allow-oob': true }
##
diff --git a/qapi/misc.json b/qapi/misc.json
index 6c1c5c0a37..24d20a880a 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1109,7 +1109,7 @@
##
# @cpu-add:
#
-# Adds CPU with specified ID
+# Adds CPU with specified ID.
#
# @id: ID of CPU to be created, valid values [0..max_cpus)
#
@@ -1117,6 +1117,10 @@
#
# Since: 1.5
#
+# Note: This command is deprecated. The `device_add` command should be
+# used instead. See the `query-hotpluggable-cpus` command for
+# details.
+#
# Example:
#
# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
@@ -1235,12 +1239,18 @@
##
# @system_wakeup:
#
-# Wakeup guest from suspend. Does nothing in case the guest isn't suspended.
+# Wake up guest from suspend. If the guest has wake-up from suspend
+# support enabled (wakeup-suspend-support flag from
+# query-current-machine), wake-up guest from suspend if the guest is
+# in SUSPENDED state. Return an error otherwise.
#
# Since: 1.1
#
# Returns: nothing.
#
+# Note: prior to 4.0, this command does nothing in case the guest
+# isn't suspended.
+#
# Example:
#
# -> { "execute": "system_wakeup" }
@@ -2009,6 +2019,30 @@
{ 'command': 'query-machines', 'returns': ['MachineInfo'] }
##
+# @CurrentMachineParams:
+#
+# Information describing the running machine parameters.
+#
+# @wakeup-suspend-support: true if the machine supports wake up from
+# suspend
+#
+# Since: 4.0
+##
+{ 'struct': 'CurrentMachineParams',
+ 'data': { 'wakeup-suspend-support': 'bool'} }
+
+##
+# @query-current-machine:
+#
+# Return information on the current virtual machine.
+#
+# Returns: CurrentMachineParams
+#
+# Since: 4.0
+##
+{ 'command': 'query-current-machine', 'returns': 'CurrentMachineParams' }
+
+##
# @CpuDefinitionInfo:
#
# Virtual CPU definition.
@@ -2381,7 +2415,9 @@
# <- { "return": { "fdset-id": 1, "fd": 3 } }
#
##
-{ 'command': 'add-fd', 'data': {'*fdset-id': 'int', '*opaque': 'str'},
+{ 'command': 'add-fd',
+ 'data': { '*fdset-id': 'int',
+ '*opaque': 'str' },
'returns': 'AddfdInfo' }
##
@@ -2653,7 +2689,8 @@
# }
#
##
-{'command': 'query-command-line-options', 'data': { '*option': 'str' },
+{'command': 'query-command-line-options',
+ 'data': { '*option': 'str' },
'returns': ['CommandLineOptionInfo'],
'allow-preconfig': true }
@@ -3219,6 +3256,8 @@
##
# @query-hotpluggable-cpus:
#
+# TODO: Better documentation; currently there is none.
+#
# Returns: a list of HotpluggableCPU objects.
#
# Since: 2.7
@@ -3439,46 +3478,6 @@
{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability' }
##
-# @CommandDropReason:
-#
-# Reasons that caused one command to be dropped.
-#
-# @queue-full: the command queue is full. This can only occur when
-# the client sends a new non-oob command before the
-# response to the previous non-oob command has been
-# received.
-#
-# Since: 2.12
-##
-{ 'enum': 'CommandDropReason',
- 'data': [ 'queue-full' ] }
-
-##
-# @COMMAND_DROPPED:
-#
-# Emitted when a command is dropped due to some reason. Commands can
-# only be dropped when the oob capability is enabled.
-#
-# @id: The dropped command's "id" field.
-# FIXME Broken by design. Events are broadcast to all monitors. If
-# another monitor's client has a command with the same ID in flight,
-# the event will incorrectly claim that command was dropped.
-#
-# @reason: The reason why the command is dropped.
-#
-# Since: 2.12
-#
-# Example:
-#
-# { "event": "COMMAND_DROPPED",
-# "data": {"result": {"id": "libvirt-102",
-# "reason": "queue-full" } } }
-#
-##
-{ 'event': 'COMMAND_DROPPED' ,
- 'data': { 'id': 'any', 'reason': 'CommandDropReason' } }
-
-##
# @set-numa-node:
#
# Runtime equivalent of '-numa' CLI option, available at
diff --git a/qapi/net.json b/qapi/net.json
index 8f99fd911d..a1a0f39f74 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -657,7 +657,8 @@
# }
#
##
-{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
+{ 'command': 'query-rx-filter',
+ 'data': { '*name': 'str' },
'returns': ['RxFilterInfo'] }
##
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 65b6dc2f6f..3bbdfcee84 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -86,6 +86,7 @@
{ 'include': 'char.json' }
{ 'include': 'job.json' }
{ 'include': 'net.json' }
+{ 'include': 'rdma.json' }
{ 'include': 'rocker.json' }
{ 'include': 'tpm.json' }
{ 'include': 'ui.json' }
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 3e88b27f9e..07465f9947 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -562,19 +562,20 @@ static void qobject_input_type_number_keyval(Visitor *v, const char *name,
{
QObjectInputVisitor *qiv = to_qiv(v);
const char *str = qobject_input_get_keyval(qiv, name, errp);
- char *endp;
+ double val;
if (!str) {
return;
}
- errno = 0;
- *obj = strtod(str, &endp);
- if (errno || endp == str || *endp || !isfinite(*obj)) {
+ if (qemu_strtod_finite(str, NULL, &val)) {
/* TODO report -ERANGE more nicely */
error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
full_name(qiv, name), "number");
+ return;
}
+
+ *obj = val;
}
static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
diff --git a/qapi/rdma.json b/qapi/rdma.json
new file mode 100644
index 0000000000..b58105b1b6
--- /dev/null
+++ b/qapi/rdma.json
@@ -0,0 +1,38 @@
+# -*- Mode: Python -*-
+#
+
+##
+# = RDMA device
+##
+
+##
+# @RDMA_GID_STATUS_CHANGED:
+#
+# Emitted when guest driver adds/deletes GID to/from device
+#
+# @netdev: RoCE Network Device name
+#
+# @gid-status: Add or delete indication
+#
+# @subnet-prefix: Subnet Prefix
+#
+# @interface-id : Interface ID
+#
+# Since: 4.0
+#
+# Example:
+#
+# <- {"timestamp": {"seconds": 1541579657, "microseconds": 986760},
+# "event": "RDMA_GID_STATUS_CHANGED",
+# "data":
+# {"netdev": "bridge0",
+# "interface-id": 15880512517475447892,
+# "gid-status": true,
+# "subnet-prefix": 33022}}
+#
+##
+{ 'event': 'RDMA_GID_STATUS_CHANGED',
+ 'data': { 'netdev' : 'str',
+ 'gid-status' : 'bool',
+ 'subnet-prefix' : 'uint64',
+ 'interface-id' : 'uint64' } }
diff --git a/qapi/run-state.json b/qapi/run-state.json
index 332e44897b..d7477cd715 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -60,6 +60,42 @@
'guest-panicked', 'colo', 'preconfig' ] }
##
+# @ShutdownCause:
+#
+# An enumeration of reasons for a Shutdown.
+#
+# @none: No shutdown request pending
+#
+# @host-error: An error prevents further use of guest
+#
+# @host-qmp-quit: Reaction to the QMP command 'quit'
+#
+# @host-qmp-system-reset: Reaction to the QMP command 'system_reset'
+#
+# @host-signal: Reaction to a signal, such as SIGINT
+#
+# @host-ui: Reaction to a UI event, like window close
+#
+# @guest-shutdown: Guest shutdown/suspend request, via ACPI or other
+# hardware-specific means
+#
+# @guest-reset: Guest reset request, and command line turns that into
+# a shutdown
+#
+# @guest-panic: Guest panicked, and command line turns that into a shutdown
+#
+# @subsystem-reset: Partial guest reset that does not trigger QMP events and
+# ignores --no-reboot. This is useful for sanitizing
+# hypercalls on s390 that are used during kexec/kdump/boot
+#
+##
+{ 'enum': 'ShutdownCause',
+ # Beware, shutdown_caused_by_guest() depends on enumeration order
+ 'data': [ 'none', 'host-error', 'host-qmp-quit', 'host-qmp-system-reset',
+ 'host-signal', 'host-ui', 'guest-shutdown', 'guest-reset',
+ 'guest-panic', 'subsystem-reset'] }
+
+##
# @StatusInfo:
#
# Information about VCPU run state
@@ -107,6 +143,8 @@
# a guest-initiated ACPI shutdown request or other hardware-specific action)
# rather than a host request (such as sending qemu a SIGINT). (since 2.10)
#
+# @reason: The @ShutdownCause which resulted in the SHUTDOWN. (since 4.0)
+#
# Note: If the command-line option "-no-shutdown" has been specified, qemu will
# not exit, and a STOP event will eventually follow the SHUTDOWN event
#
@@ -118,7 +156,7 @@
# "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
#
##
-{ 'event': 'SHUTDOWN', 'data': { 'guest': 'bool' } }
+{ 'event': 'SHUTDOWN', 'data': { 'guest': 'bool', 'reason': 'ShutdownCause' } }
##
# @POWERDOWN:
@@ -146,6 +184,8 @@
# rather than a host request (such as the QMP command system_reset).
# (since 2.10)
#
+# @reason: The @ShutdownCause of the RESET. (since 4.0)
+#
# Since: 0.12.0
#
# Example:
@@ -154,7 +194,7 @@
# "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
#
##
-{ 'event': 'RESET', 'data': { 'guest': 'bool' } }
+{ 'event': 'RESET', 'data': { 'guest': 'bool', 'reason': 'ShutdownCause' } }
##
# @STOP:
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index b3fdd0827d..bd92080667 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -4,10 +4,10 @@
* Copyright Red Hat, Inc. 2012-2016
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
+ * David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
* See the COPYING.LIB file in the top-level directory.
- *
*/
#include "qemu/osdep.h"
@@ -18,20 +18,42 @@
#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qnull.h"
#include "qemu/option.h"
-#include "qemu/queue.h"
-#include "qemu/range.h"
-
+#include "qemu/cutils.h"
+
+typedef enum ListMode {
+ /* no list parsing active / no list expected */
+ LM_NONE,
+ /* we have an unparsed string remaining */
+ LM_UNPARSED,
+ /* we have an unfinished int64 range */
+ LM_INT64_RANGE,
+ /* we have an unfinished uint64 range */
+ LM_UINT64_RANGE,
+ /* we have parsed the string completely and no range is remaining */
+ LM_END,
+} ListMode;
+
+/* protect against DOS attacks, limit the amount of elements per range */
+#define RANGE_MAX_ELEMENTS 65536
+
+typedef union RangeElement {
+ int64_t i64;
+ uint64_t u64;
+} RangeElement;
struct StringInputVisitor
{
Visitor visitor;
- GList *ranges;
- GList *cur_range;
- int64_t cur;
+ /* List parsing state */
+ ListMode lm;
+ RangeElement rangeNext;
+ RangeElement rangeEnd;
+ const char *unparsed_string;
+ void *list;
+ /* The original string to parse */
const char *string;
- void *list; /* Only needed for sanity checking the caller */
};
static StringInputVisitor *to_siv(Visitor *v)
@@ -39,136 +61,42 @@ static StringInputVisitor *to_siv(Visitor *v)
return container_of(v, StringInputVisitor, visitor);
}
-static void free_range(void *range, void *dummy)
-{
- g_free(range);
-}
-
-static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
-{
- char *str = (char *) siv->string;
- long long start, end;
- Range *cur;
- char *endptr;
-
- if (siv->ranges) {
- return 0;
- }
-
- if (!*str) {
- return 0;
- }
-
- do {
- errno = 0;
- start = strtoll(str, &endptr, 0);
- if (errno == 0 && endptr > str) {
- if (*endptr == '\0') {
- cur = g_malloc0(sizeof(*cur));
- range_set_bounds(cur, start, start);
- siv->ranges = range_list_insert(siv->ranges, cur);
- cur = NULL;
- str = NULL;
- } else if (*endptr == '-') {
- str = endptr + 1;
- errno = 0;
- end = strtoll(str, &endptr, 0);
- if (errno == 0 && endptr > str && start <= end &&
- (start > INT64_MAX - 65536 ||
- end < start + 65536)) {
- if (*endptr == '\0') {
- cur = g_malloc0(sizeof(*cur));
- range_set_bounds(cur, start, end);
- siv->ranges = range_list_insert(siv->ranges, cur);
- cur = NULL;
- str = NULL;
- } else if (*endptr == ',') {
- str = endptr + 1;
- cur = g_malloc0(sizeof(*cur));
- range_set_bounds(cur, start, end);
- siv->ranges = range_list_insert(siv->ranges, cur);
- cur = NULL;
- } else {
- goto error;
- }
- } else {
- goto error;
- }
- } else if (*endptr == ',') {
- str = endptr + 1;
- cur = g_malloc0(sizeof(*cur));
- range_set_bounds(cur, start, start);
- siv->ranges = range_list_insert(siv->ranges, cur);
- cur = NULL;
- } else {
- goto error;
- }
- } else {
- goto error;
- }
- } while (str);
-
- return 0;
-error:
- g_list_foreach(siv->ranges, free_range, NULL);
- g_list_free(siv->ranges);
- siv->ranges = NULL;
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
- "an int64 value or range");
- return -1;
-}
-
-static void
-start_list(Visitor *v, const char *name, GenericList **list, size_t size,
- Error **errp)
+static void start_list(Visitor *v, const char *name, GenericList **list,
+ size_t size, Error **errp)
{
StringInputVisitor *siv = to_siv(v);
- /* We don't support visits without a list */
- assert(list);
+ assert(siv->lm == LM_NONE);
siv->list = list;
+ siv->unparsed_string = siv->string;
- if (parse_str(siv, name, errp) < 0) {
- *list = NULL;
- return;
- }
-
- siv->cur_range = g_list_first(siv->ranges);
- if (siv->cur_range) {
- Range *r = siv->cur_range->data;
- if (r) {
- siv->cur = range_lob(r);
+ if (!siv->string[0]) {
+ if (list) {
+ *list = NULL;
}
- *list = g_malloc0(size);
+ siv->lm = LM_END;
} else {
- *list = NULL;
+ if (list) {
+ *list = g_malloc0(size);
+ }
+ siv->lm = LM_UNPARSED;
}
}
static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
{
StringInputVisitor *siv = to_siv(v);
- Range *r;
- if (!siv->ranges || !siv->cur_range) {
+ switch (siv->lm) {
+ case LM_END:
return NULL;
- }
-
- r = siv->cur_range->data;
- if (!r) {
- return NULL;
- }
-
- if (!range_contains(r, siv->cur)) {
- siv->cur_range = g_list_next(siv->cur_range);
- if (!siv->cur_range) {
- return NULL;
- }
- r = siv->cur_range->data;
- if (!r) {
- return NULL;
- }
- siv->cur = range_lob(r);
+ case LM_INT64_RANGE:
+ case LM_UINT64_RANGE:
+ case LM_UNPARSED:
+ /* we have an unparsed string or something left in a range */
+ break;
+ default:
+ abort();
}
tail->next = g_malloc0(size);
@@ -178,88 +106,208 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
static void check_list(Visitor *v, Error **errp)
{
const StringInputVisitor *siv = to_siv(v);
- Range *r;
- GList *cur_range;
- if (!siv->ranges || !siv->cur_range) {
+ switch (siv->lm) {
+ case LM_INT64_RANGE:
+ case LM_UINT64_RANGE:
+ case LM_UNPARSED:
+ error_setg(errp, "Fewer list elements expected");
return;
- }
-
- r = siv->cur_range->data;
- if (!r) {
+ case LM_END:
return;
+ default:
+ abort();
}
-
- if (!range_contains(r, siv->cur)) {
- cur_range = g_list_next(siv->cur_range);
- if (!cur_range) {
- return;
- }
- r = cur_range->data;
- if (!r) {
- return;
- }
- }
-
- error_setg(errp, "Range contains too many values");
}
static void end_list(Visitor *v, void **obj)
{
StringInputVisitor *siv = to_siv(v);
+ assert(siv->lm != LM_NONE);
assert(siv->list == obj);
+ siv->list = NULL;
+ siv->unparsed_string = NULL;
+ siv->lm = LM_NONE;
+}
+
+static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj)
+{
+ const char *endptr;
+ int64_t start, end;
+
+ /* parse a simple int64 or range */
+ if (qemu_strtoi64(siv->unparsed_string, &endptr, 0, &start)) {
+ return -EINVAL;
+ }
+ end = start;
+
+ switch (endptr[0]) {
+ case '\0':
+ siv->unparsed_string = endptr;
+ break;
+ case ',':
+ siv->unparsed_string = endptr + 1;
+ break;
+ case '-':
+ /* parse the end of the range */
+ if (qemu_strtoi64(endptr + 1, &endptr, 0, &end)) {
+ return -EINVAL;
+ }
+ if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
+ return -EINVAL;
+ }
+ switch (endptr[0]) {
+ case '\0':
+ siv->unparsed_string = endptr;
+ break;
+ case ',':
+ siv->unparsed_string = endptr + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* we have a proper range (with maybe only one element) */
+ siv->lm = LM_INT64_RANGE;
+ siv->rangeNext.i64 = start;
+ siv->rangeEnd.i64 = end;
+ return 0;
}
static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
Error **errp)
{
StringInputVisitor *siv = to_siv(v);
-
- if (parse_str(siv, name, errp) < 0) {
+ int64_t val;
+
+ switch (siv->lm) {
+ case LM_NONE:
+ /* just parse a simple int64, bail out if not completely consumed */
+ if (qemu_strtoi64(siv->string, NULL, 0, &val)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ name ? name : "null", "int64");
+ return;
+ }
+ *obj = val;
return;
+ case LM_UNPARSED:
+ if (try_parse_int64_list_entry(siv, obj)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+ "list of int64 values or ranges");
+ return;
+ }
+ assert(siv->lm == LM_INT64_RANGE);
+ /* fall through */
+ case LM_INT64_RANGE:
+ /* return the next element in the range */
+ assert(siv->rangeNext.i64 <= siv->rangeEnd.i64);
+ *obj = siv->rangeNext.i64++;
+
+ if (siv->rangeNext.i64 > siv->rangeEnd.i64 || *obj == INT64_MAX) {
+ /* end of range, check if there is more to parse */
+ siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
+ }
+ return;
+ case LM_END:
+ error_setg(errp, "Fewer list elements expected");
+ return;
+ default:
+ abort();
}
+}
- if (!siv->ranges) {
- goto error;
- }
-
- if (!siv->cur_range) {
- Range *r;
+static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj)
+{
+ const char *endptr;
+ uint64_t start, end;
- siv->cur_range = g_list_first(siv->ranges);
- if (!siv->cur_range) {
- goto error;
+ /* parse a simple uint64 or range */
+ if (qemu_strtou64(siv->unparsed_string, &endptr, 0, &start)) {
+ return -EINVAL;
+ }
+ end = start;
+
+ switch (endptr[0]) {
+ case '\0':
+ siv->unparsed_string = endptr;
+ break;
+ case ',':
+ siv->unparsed_string = endptr + 1;
+ break;
+ case '-':
+ /* parse the end of the range */
+ if (qemu_strtou64(endptr + 1, &endptr, 0, &end)) {
+ return -EINVAL;
}
-
- r = siv->cur_range->data;
- if (!r) {
- goto error;
+ if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
+ return -EINVAL;
}
-
- siv->cur = range_lob(r);
+ switch (endptr[0]) {
+ case '\0':
+ siv->unparsed_string = endptr;
+ break;
+ case ',':
+ siv->unparsed_string = endptr + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
}
- *obj = siv->cur;
- siv->cur++;
- return;
-
-error:
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
- "an int64 value or range");
+ /* we have a proper range (with maybe only one element) */
+ siv->lm = LM_UINT64_RANGE;
+ siv->rangeNext.u64 = start;
+ siv->rangeEnd.u64 = end;
+ return 0;
}
static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
Error **errp)
{
- /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
- int64_t i;
- Error *err = NULL;
- parse_type_int64(v, name, &i, &err);
- if (err) {
- error_propagate(errp, err);
- } else {
- *obj = i;
+ StringInputVisitor *siv = to_siv(v);
+ uint64_t val;
+
+ switch (siv->lm) {
+ case LM_NONE:
+ /* just parse a simple uint64, bail out if not completely consumed */
+ if (qemu_strtou64(siv->string, NULL, 0, &val)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+ "uint64");
+ return;
+ }
+ *obj = val;
+ return;
+ case LM_UNPARSED:
+ if (try_parse_uint64_list_entry(siv, obj)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+ "list of uint64 values or ranges");
+ return;
+ }
+ assert(siv->lm == LM_UINT64_RANGE);
+ /* fall through */
+ case LM_UINT64_RANGE:
+ /* return the next element in the range */
+ assert(siv->rangeNext.u64 <= siv->rangeEnd.u64);
+ *obj = siv->rangeNext.u64++;
+
+ if (siv->rangeNext.u64 > siv->rangeEnd.u64 || *obj == UINT64_MAX) {
+ /* end of range, check if there is more to parse */
+ siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
+ }
+ return;
+ case LM_END:
+ error_setg(errp, "Fewer list elements expected");
+ return;
+ default:
+ abort();
}
}
@@ -270,6 +318,7 @@ static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
Error *err = NULL;
uint64_t val;
+ assert(siv->lm == LM_NONE);
parse_option_size(name, siv->string, &val, &err);
if (err) {
error_propagate(errp, err);
@@ -284,6 +333,7 @@ static void parse_type_bool(Visitor *v, const char *name, bool *obj,
{
StringInputVisitor *siv = to_siv(v);
+ assert(siv->lm == LM_NONE);
if (!strcasecmp(siv->string, "on") ||
!strcasecmp(siv->string, "yes") ||
!strcasecmp(siv->string, "true")) {
@@ -306,6 +356,7 @@ static void parse_type_str(Visitor *v, const char *name, char **obj,
{
StringInputVisitor *siv = to_siv(v);
+ assert(siv->lm == LM_NONE);
*obj = g_strdup(siv->string);
}
@@ -313,12 +364,10 @@ static void parse_type_number(Visitor *v, const char *name, double *obj,
Error **errp)
{
StringInputVisitor *siv = to_siv(v);
- char *endp = (char *) siv->string;
double val;
- errno = 0;
- val = strtod(siv->string, &endp);
- if (errno || endp == siv->string || *endp) {
+ assert(siv->lm == LM_NONE);
+ if (qemu_strtod_finite(siv->string, NULL, &val)) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"number");
return;
@@ -332,9 +381,10 @@ static void parse_type_null(Visitor *v, const char *name, QNull **obj,
{
StringInputVisitor *siv = to_siv(v);
+ assert(siv->lm == LM_NONE);
*obj = NULL;
- if (!siv->string || siv->string[0]) {
+ if (siv->string[0]) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"null");
return;
@@ -347,8 +397,6 @@ static void string_input_free(Visitor *v)
{
StringInputVisitor *siv = to_siv(v);
- g_list_foreach(siv->ranges, free_range, NULL);
- g_list_free(siv->ranges);
g_free(siv);
}
@@ -374,5 +422,6 @@ Visitor *string_input_visitor_new(const char *str)
v->visitor.free = string_input_free;
v->string = str;
+ v->lm = LM_NONE;
return &v->visitor;
}
diff --git a/qapi/tpm.json b/qapi/tpm.json
index d50deef5e9..b30323bb6b 100644
--- a/qapi/tpm.json
+++ b/qapi/tpm.json
@@ -76,8 +76,9 @@
#
# Since: 1.5
##
-{ 'struct': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
- '*cancel-path' : 'str'} }
+{ 'struct': 'TPMPassthroughOptions',
+ 'data': { '*path': 'str',
+ '*cancel-path': 'str' } }
##
# @TPMEmulatorOptions:
diff --git a/qapi/transaction.json b/qapi/transaction.json
index 5875cdb16c..95edb78227 100644
--- a/qapi/transaction.json
+++ b/qapi/transaction.json
@@ -46,9 +46,9 @@
# - @abort: since 1.6
# - @block-dirty-bitmap-add: since 2.5
# - @block-dirty-bitmap-clear: since 2.5
-# - @x-block-dirty-bitmap-enable: since 3.0
-# - @x-block-dirty-bitmap-disable: since 3.0
-# - @x-block-dirty-bitmap-merge: since 3.1
+# - @block-dirty-bitmap-enable: since 4.0
+# - @block-dirty-bitmap-disable: since 4.0
+# - @block-dirty-bitmap-merge: since 4.0
# - @blockdev-backup: since 2.3
# - @blockdev-snapshot: since 2.5
# - @blockdev-snapshot-internal-sync: since 1.7
@@ -62,9 +62,9 @@
'abort': 'Abort',
'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd',
'block-dirty-bitmap-clear': 'BlockDirtyBitmap',
- 'x-block-dirty-bitmap-enable': 'BlockDirtyBitmap',
- 'x-block-dirty-bitmap-disable': 'BlockDirtyBitmap',
- 'x-block-dirty-bitmap-merge': 'BlockDirtyBitmapMerge',
+ 'block-dirty-bitmap-enable': 'BlockDirtyBitmap',
+ 'block-dirty-bitmap-disable': 'BlockDirtyBitmap',
+ 'block-dirty-bitmap-merge': 'BlockDirtyBitmapMerge',
'blockdev-backup': 'BlockdevBackup',
'blockdev-snapshot': 'BlockdevSnapshot',
'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal',
diff --git a/qapi/ui.json b/qapi/ui.json
index fd39acb5c3..5ad13248d5 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -598,7 +598,8 @@
# 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'},
+{ 'command': 'change-vnc-password',
+ 'data': { 'password': 'str' },
'if': 'defined(CONFIG_VNC)' }
##
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index cb4291f1e5..219206a836 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -46,14 +46,6 @@ would automatically enable USB support on the machine type.
If using the new syntax, USB support must be explicitly
enabled via the ``-machine usb=on'' argument.
-@subsection -fsdev handle (since 2.12.0)
-
-The ``handle'' fsdev backend does not support symlinks and causes the 9p
-filesystem in the guest to fail a fair amount of tests from the PJD POSIX
-filesystem test suite. Also it requires the CAP_DAC_READ_SEARCH capability,
-which is not the recommended way to run QEMU. This backend should not be
-used and it will be removed with no replacement.
-
@subsection -no-frame (since 2.12.0)
The @code{--no-frame} argument works with SDL 1.2 only. The other user
@@ -114,19 +106,25 @@ The ``query-cpus'' command is replaced by the ``query-cpus-fast'' command.
The ``arch'' output member of the ``query-cpus-fast'' command is
replaced by the ``target'' output member.
-@section System emulator human monitor commands
+@subsection cpu-add (since 4.0)
+
+Use ``device_add'' for hotplugging vCPUs instead of ``cpu-add''. See
+documentation of ``query-hotpluggable-cpus'' for additional
+details.
+
+@section Human Monitor Protocol (HMP) commands
@subsection The hub_id parameter of 'hostfwd_add' / 'hostfwd_remove' (since 3.1)
The @option{[hub_id name]} parameter tuple of the 'hostfwd_add' and
'hostfwd_remove' HMP commands has been replaced by @option{netdev_id}.
-@section System emulator devices
+@subsection cpu-add (since 4.0)
-@subsection ivshmem (since 2.6.0)
+Use ``device_add'' for hotplugging vCPUs instead of ``cpu-add''. See
+documentation of ``query-hotpluggable-cpus'' for additional details.
-The ``ivshmem'' device type is replaced by either the ``ivshmem-plain''
-or ``ivshmem-doorbell`` device types.
+@section System emulator devices
@subsection bluetooth (since 3.1)
@@ -137,7 +135,7 @@ their usecases.
@section System emulator machines
-@subsection pc-0.10 and pc-0.11 (since 3.0)
+@subsection pc-0.12, pc-0.13, pc-0.14 and pc-0.15 (since 4.0)
These machine types are very old and likely can not be used for live migration
from old QEMU versions anymore. A newer machine type should be used instead.
diff --git a/qemu-doc.texi b/qemu-doc.texi
index f7ad1dfe4b..16b955cbf9 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -37,6 +37,7 @@
* QEMU System emulator for non PC targets::
* QEMU Guest Agent::
* QEMU User space emulator::
+* System requirements::
* Implementation notes::
* Deprecated features::
* Supported build platforms::
@@ -2813,6 +2814,18 @@ Act as if the host page size was 'pagesize' bytes
Run the emulation in single step mode.
@end table
+@node System requirements
+@chapter System requirements
+
+@section KVM kernel module
+
+On x86_64 hosts, the default set of CPU features enabled by the KVM accelerator
+require the host to be running Linux v4.5 or newer.
+
+The OpteronG[345] CPU models require KVM support for RDTSCP, which was
+added with Linux 4.5 which is supported by the major distros. And even
+if RHEL7 has kernel 3.10, KVM there has the required functionality there
+to make it close to a 4.5 or newer kernel.
@include qemu-tech.texi
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 5363482213..2c39124036 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
#include "qemu-io.h"
#include "sysemu/block-backend.h"
#include "block/block.h"
@@ -1978,6 +1979,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
int flags = bs->open_flags;
bool writethrough = !blk_enable_write_cache(blk);
bool has_rw_option = false;
+ bool has_cache_option = false;
BlockReopenQueue *brq;
Error *local_err = NULL;
@@ -1989,6 +1991,7 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
error_report("Invalid cache option: %s", optarg);
return -EINVAL;
}
+ has_cache_option = true;
break;
case 'o':
if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
@@ -2046,11 +2049,33 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
}
qopts = qemu_opts_find(&reopen_opts, NULL);
- opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
+ opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : qdict_new();
qemu_opts_reset(&reopen_opts);
+ if (qdict_haskey(opts, BDRV_OPT_READ_ONLY)) {
+ if (has_rw_option) {
+ error_report("Cannot set both -r/-w and '" BDRV_OPT_READ_ONLY "'");
+ qobject_unref(opts);
+ return -EINVAL;
+ }
+ } else {
+ qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
+ }
+
+ if (qdict_haskey(opts, BDRV_OPT_CACHE_DIRECT) ||
+ qdict_haskey(opts, BDRV_OPT_CACHE_NO_FLUSH)) {
+ if (has_cache_option) {
+ error_report("Cannot set both -c and the cache options");
+ qobject_unref(opts);
+ return -EINVAL;
+ }
+ } else {
+ qdict_put_bool(opts, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
+ qdict_put_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, flags & BDRV_O_NO_FLUSH);
+ }
+
bdrv_subtree_drained_begin(bs);
- brq = bdrv_reopen_queue(NULL, bs, opts, flags);
+ brq = bdrv_reopen_queue(NULL, bs, opts);
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
bdrv_subtree_drained_end(bs);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index ca7109652e..1f7b2a03f5 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -43,6 +43,12 @@
#include "trace/control.h"
#include "qemu-version.h"
+#ifdef __linux__
+#define HAVE_NBD_DEVICE 1
+#else
+#define HAVE_NBD_DEVICE 0
+#endif
+
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
#define QEMU_NBD_OPT_CACHE 256
#define QEMU_NBD_OPT_AIO 257
@@ -55,7 +61,7 @@
#define MBR_SIZE 512
-static NBDExport *exp;
+static NBDExport *export;
static int verbose;
static char *srcpath;
static SocketAddress *saddr;
@@ -70,7 +76,8 @@ static void usage(const char *name)
{
(printf) (
"Usage: %s [OPTIONS] FILE\n"
-"QEMU Disk Network Block Device Server\n"
+" or: %s -L [OPTIONS]\n"
+"QEMU Disk Network Block Device Utility\n"
"\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
@@ -89,8 +96,10 @@ static void usage(const char *name)
"Exposing part of the image:\n"
" -o, --offset=OFFSET offset into the image\n"
" -P, --partition=NUM only expose partition NUM\n"
+" -B, --bitmap=NAME expose a persistent dirty bitmap\n"
"\n"
"General purpose options:\n"
+" -L, --list list exports available from another NBD server\n"
" --object type,id=ID,... define an object such as 'secret' for providing\n"
" passwords and/or encryption keys\n"
" --tls-creds=ID use id of an earlier --object to provide TLS\n"
@@ -98,11 +107,11 @@ static void usage(const char *name)
" specify tracing options\n"
" --fork fork off the server process and exit the parent\n"
" once the server is running\n"
-#ifdef __linux__
+#if HAVE_NBD_DEVICE
+"\n"
"Kernel NBD client support:\n"
" -c, --connect=DEV connect FILE to the local NBD device DEV\n"
" -d, --disconnect disconnect the specified device\n"
-"\n"
#endif
"\n"
"Block device options:\n"
@@ -124,7 +133,7 @@ static void usage(const char *name)
" --image-opts treat FILE as a full set of image options\n"
"\n"
QEMU_HELP_BOTTOM "\n"
- , name, NBD_DEFAULT_PORT, "DEVICE");
+ , name, name, NBD_DEFAULT_PORT, "DEVICE");
}
static void version(const char *name)
@@ -169,7 +178,7 @@ static void read_partition(uint8_t *p, struct partition_record *r)
}
static int find_partition(BlockBackend *blk, int partition,
- off_t *offset, off_t *size)
+ uint64_t *offset, uint64_t *size)
{
struct partition_record mbr[4];
uint8_t data[MBR_SIZE];
@@ -236,6 +245,92 @@ static void termsig_handler(int signum)
}
+static int qemu_nbd_client_list(SocketAddress *saddr, QCryptoTLSCreds *tls,
+ const char *hostname)
+{
+ int ret = EXIT_FAILURE;
+ int rc;
+ Error *err = NULL;
+ QIOChannelSocket *sioc;
+ NBDExportInfo *list;
+ int i, j;
+
+ sioc = qio_channel_socket_new();
+ if (qio_channel_socket_connect_sync(sioc, saddr, &err) < 0) {
+ error_report_err(err);
+ return EXIT_FAILURE;
+ }
+ rc = nbd_receive_export_list(QIO_CHANNEL(sioc), tls, hostname, &list,
+ &err);
+ if (rc < 0) {
+ if (err) {
+ error_report_err(err);
+ }
+ goto out;
+ }
+ printf("exports available: %d\n", rc);
+ for (i = 0; i < rc; i++) {
+ printf(" export: '%s'\n", list[i].name);
+ if (list[i].description && *list[i].description) {
+ printf(" description: %s\n", list[i].description);
+ }
+ if (list[i].flags & NBD_FLAG_HAS_FLAGS) {
+ printf(" size: %" PRIu64 "\n", list[i].size);
+ printf(" flags: 0x%x (", list[i].flags);
+ if (list[i].flags & NBD_FLAG_READ_ONLY) {
+ printf(" readonly");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_FLUSH) {
+ printf(" flush");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_FUA) {
+ printf(" fua");
+ }
+ if (list[i].flags & NBD_FLAG_ROTATIONAL) {
+ printf(" rotational");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_TRIM) {
+ printf(" trim");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_WRITE_ZEROES) {
+ printf(" zeroes");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_DF) {
+ printf(" df");
+ }
+ if (list[i].flags & NBD_FLAG_CAN_MULTI_CONN) {
+ printf(" multi");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_RESIZE) {
+ printf(" resize");
+ }
+ if (list[i].flags & NBD_FLAG_SEND_CACHE) {
+ printf(" cache");
+ }
+ printf(" )\n");
+ }
+ if (list[i].min_block) {
+ printf(" min block: %u\n", list[i].min_block);
+ printf(" opt block: %u\n", list[i].opt_block);
+ printf(" max block: %u\n", list[i].max_block);
+ }
+ if (list[i].n_contexts) {
+ printf(" available meta contexts: %d\n", list[i].n_contexts);
+ for (j = 0; j < list[i].n_contexts; j++) {
+ printf(" %s\n", list[i].contexts[j]);
+ }
+ }
+ }
+ nbd_free_export_list(list, rc);
+
+ ret = EXIT_SUCCESS;
+ out:
+ object_unref(OBJECT(sioc));
+ return ret;
+}
+
+
+#if HAVE_NBD_DEVICE
static void *show_parts(void *arg)
{
char *device = arg;
@@ -256,7 +351,7 @@ static void *show_parts(void *arg)
static void *nbd_client_thread(void *arg)
{
char *device = arg;
- NBDExportInfo info = { .request_sizes = false, };
+ NBDExportInfo info = { .request_sizes = false, .name = g_strdup("") };
QIOChannelSocket *sioc;
int fd;
int ret;
@@ -271,7 +366,7 @@ static void *nbd_client_thread(void *arg)
goto out;
}
- ret = nbd_receive_negotiate(QIO_CHANNEL(sioc), NULL,
+ ret = nbd_receive_negotiate(QIO_CHANNEL(sioc),
NULL, NULL, NULL, &info, &local_error);
if (ret < 0) {
if (local_error) {
@@ -310,6 +405,7 @@ static void *nbd_client_thread(void *arg)
}
close(fd);
object_unref(OBJECT(sioc));
+ g_free(info.name);
kill(getpid(), SIGTERM);
return (void *) EXIT_SUCCESS;
@@ -318,16 +414,18 @@ out_fd:
out_socket:
object_unref(OBJECT(sioc));
out:
+ g_free(info.name);
kill(getpid(), SIGTERM);
return (void *) EXIT_FAILURE;
}
+#endif /* HAVE_NBD_DEVICE */
static int nbd_can_accept(void)
{
return state == RUNNING && nb_fds < shared;
}
-static void nbd_export_closed(NBDExport *exp)
+static void nbd_export_closed(NBDExport *export)
{
assert(state == TERMINATING);
state = TERMINATED;
@@ -414,7 +512,8 @@ static QemuOptsList qemu_object_opts = {
-static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
+static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, bool list,
+ Error **errp)
{
Object *obj;
QCryptoTLSCreds *creds;
@@ -434,10 +533,18 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
return NULL;
}
- if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
- error_setg(errp,
- "Expecting TLS credentials with a server endpoint");
- return NULL;
+ if (list) {
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
+ error_setg(errp,
+ "Expecting TLS credentials with a client endpoint");
+ return NULL;
+ }
+ } else {
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ error_setg(errp,
+ "Expecting TLS credentials with a server endpoint");
+ return NULL;
+ }
}
object_ref(obj);
return creds;
@@ -460,7 +567,8 @@ static void setup_address_and_port(const char **address, const char **port)
static const char *socket_activation_validate_opts(const char *device,
const char *sockpath,
const char *address,
- const char *port)
+ const char *port,
+ bool list)
{
if (device != NULL) {
return "NBD device can't be set when using socket activation";
@@ -478,6 +586,10 @@ static const char *socket_activation_validate_opts(const char *device,
return "TCP port number can't be set when using socket activation";
}
+ if (list) {
+ return "List mode is incompatible with socket activation";
+ }
+
return NULL;
}
@@ -491,17 +603,17 @@ int main(int argc, char **argv)
{
BlockBackend *blk;
BlockDriverState *bs;
- off_t dev_offset = 0;
+ uint64_t dev_offset = 0;
uint16_t nbdflags = 0;
bool disconnect = false;
const char *bindto = NULL;
const char *port = NULL;
char *sockpath = NULL;
char *device = NULL;
- off_t fd_size;
+ int64_t fd_size;
QemuOpts *sn_opts = NULL;
const char *sn_id_or_name = NULL;
- const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:";
+ const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:B:L";
struct option lopt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
@@ -511,8 +623,10 @@ int main(int argc, char **argv)
{ "offset", required_argument, NULL, 'o' },
{ "read-only", no_argument, NULL, 'r' },
{ "partition", required_argument, NULL, 'P' },
+ { "bitmap", required_argument, NULL, 'B' },
{ "connect", required_argument, NULL, 'c' },
{ "disconnect", no_argument, NULL, 'd' },
+ { "list", no_argument, NULL, 'L' },
{ "snapshot", no_argument, NULL, 's' },
{ "load-snapshot", required_argument, NULL, 'l' },
{ "nocache", no_argument, NULL, 'n' },
@@ -536,9 +650,8 @@ int main(int argc, char **argv)
};
int ch;
int opt_ind = 0;
- char *end;
int flags = BDRV_O_RDWR;
- int partition = -1;
+ int partition = 0;
int ret = 0;
bool seen_cache = false;
bool seen_discard = false;
@@ -548,13 +661,15 @@ int main(int argc, char **argv)
Error *local_err = NULL;
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL;
- const char *export_name = ""; /* Default export name */
+ const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
+ const char *bitmap = NULL;
const char *tlscredsid = NULL;
bool imageOpts = false;
bool writethrough = true;
char *trace_file = NULL;
bool fork_process = false;
+ bool list = false;
int old_stderr = -1;
unsigned socket_activation;
@@ -571,6 +686,7 @@ int main(int argc, char **argv)
#endif
module_call_init(MODULE_INIT_TRACE);
+ error_set_progname(argv[0]);
qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
@@ -648,13 +764,8 @@ int main(int argc, char **argv)
port = optarg;
break;
case 'o':
- dev_offset = strtoll (optarg, &end, 0);
- if (*end) {
- error_report("Invalid offset `%s'", optarg);
- exit(EXIT_FAILURE);
- }
- if (dev_offset < 0) {
- error_report("Offset must be positive `%s'", optarg);
+ if (qemu_strtou64(optarg, NULL, 0, &dev_offset) < 0) {
+ error_report("Invalid offset '%s'", optarg);
exit(EXIT_FAILURE);
}
break;
@@ -676,16 +787,15 @@ int main(int argc, char **argv)
flags &= ~BDRV_O_RDWR;
break;
case 'P':
- partition = strtol(optarg, &end, 0);
- if (*end) {
- error_report("Invalid partition `%s'", optarg);
- exit(EXIT_FAILURE);
- }
- if (partition < 1 || partition > 8) {
- error_report("Invalid partition %d", partition);
+ if (qemu_strtoi(optarg, NULL, 0, &partition) < 0 ||
+ partition < 1 || partition > 8) {
+ error_report("Invalid partition '%s'", optarg);
exit(EXIT_FAILURE);
}
break;
+ case 'B':
+ bitmap = optarg;
+ break;
case 'k':
sockpath = optarg;
if (sockpath[0] != '/') {
@@ -700,15 +810,11 @@ int main(int argc, char **argv)
device = optarg;
break;
case 'e':
- shared = strtol(optarg, &end, 0);
- if (*end) {
+ if (qemu_strtoi(optarg, NULL, 0, &shared) < 0 ||
+ shared < 1) {
error_report("Invalid shared device number '%s'", optarg);
exit(EXIT_FAILURE);
}
- if (shared < 1) {
- error_report("Shared device number must be greater than 0");
- exit(EXIT_FAILURE);
- }
break;
case 'f':
fmt = optarg;
@@ -757,13 +863,33 @@ int main(int argc, char **argv)
case QEMU_NBD_OPT_FORK:
fork_process = true;
break;
+ case 'L':
+ list = true;
+ break;
}
}
- if ((argc - optind) != 1) {
+ if (list) {
+ if (argc != optind) {
+ error_report("List mode is incompatible with a file name");
+ exit(EXIT_FAILURE);
+ }
+ if (export_name || export_description || dev_offset || partition ||
+ device || disconnect || fmt || sn_id_or_name || bitmap ||
+ seen_aio || seen_discard || seen_cache) {
+ error_report("List mode is incompatible with per-device settings");
+ exit(EXIT_FAILURE);
+ }
+ if (fork_process) {
+ error_report("List mode is incompatible with forking");
+ exit(EXIT_FAILURE);
+ }
+ } else if ((argc - optind) != 1) {
error_report("Invalid number of arguments");
error_printf("Try `%s --help' for more information.\n", argv[0]);
exit(EXIT_FAILURE);
+ } else if (!export_name) {
+ export_name = "";
}
qemu_opts_foreach(&qemu_object_opts,
@@ -782,7 +908,8 @@ int main(int argc, char **argv)
} else {
/* Using socket activation - check user didn't use -p etc. */
const char *err_msg = socket_activation_validate_opts(device, sockpath,
- bindto, port);
+ bindto, port,
+ list);
if (err_msg != NULL) {
error_report("%s", err_msg);
exit(EXIT_FAILURE);
@@ -805,7 +932,7 @@ int main(int argc, char **argv)
error_report("TLS is not supported with a host device");
exit(EXIT_FAILURE);
}
- tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
+ tlscreds = nbd_get_tls_creds(tlscredsid, list, &local_err);
if (local_err) {
error_report("Failed to get TLS creds %s",
error_get_pretty(local_err));
@@ -813,6 +940,17 @@ int main(int argc, char **argv)
}
}
+ if (list) {
+ saddr = nbd_build_socket_address(sockpath, bindto, port);
+ return qemu_nbd_client_list(saddr, tlscreds, bindto);
+ }
+
+#if !HAVE_NBD_DEVICE
+ if (disconnect || device) {
+ error_report("Kernel /dev/nbdN support not available");
+ exit(EXIT_FAILURE);
+ }
+#else /* HAVE_NBD_DEVICE */
if (disconnect) {
int nbdfd = open(argv[optind], O_RDWR);
if (nbdfd < 0) {
@@ -828,6 +966,7 @@ int main(int argc, char **argv)
return 0;
}
+#endif
if ((device && !verbose) || fork_process) {
int stderr_fd[2];
@@ -983,28 +1122,46 @@ int main(int argc, char **argv)
}
if (dev_offset >= fd_size) {
- error_report("Offset (%lld) has to be smaller than the image size "
- "(%lld)",
- (long long int)dev_offset, (long long int)fd_size);
+ error_report("Offset (%" PRIu64 ") has to be smaller than the image "
+ "size (%" PRId64 ")", dev_offset, fd_size);
exit(EXIT_FAILURE);
}
fd_size -= dev_offset;
- if (partition != -1) {
- ret = find_partition(blk, partition, &dev_offset, &fd_size);
+ if (partition) {
+ uint64_t limit;
+
+ if (dev_offset) {
+ error_report("Cannot request partition and offset together");
+ exit(EXIT_FAILURE);
+ }
+ ret = find_partition(blk, partition, &dev_offset, &limit);
if (ret < 0) {
error_report("Could not find partition %d: %s", partition,
strerror(-ret));
exit(EXIT_FAILURE);
}
+ /*
+ * MBR partition limits are (32-bit << 9); this assert lets
+ * the compiler know that we can't overflow 64 bits.
+ */
+ assert(dev_offset + limit >= dev_offset);
+ if (dev_offset + limit > fd_size) {
+ error_report("Discovered partition %d at offset %" PRIu64
+ " size %" PRIu64 ", but size exceeds file length %"
+ PRId64, partition, dev_offset, limit, fd_size);
+ exit(EXIT_FAILURE);
+ }
+ fd_size = limit;
}
- exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed,
- writethrough, NULL, &error_fatal);
- nbd_export_set_name(exp, export_name);
- nbd_export_set_description(exp, export_description);
+ export = nbd_export_new(bs, dev_offset, fd_size, export_name,
+ export_description, bitmap, nbdflags,
+ nbd_export_closed, writethrough, NULL,
+ &error_fatal);
if (device) {
+#if HAVE_NBD_DEVICE
int ret;
ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
@@ -1012,6 +1169,7 @@ int main(int argc, char **argv)
error_report("Failed to create client thread: %s", strerror(ret));
exit(EXIT_FAILURE);
}
+#endif
} else {
/* Shut up GCC warnings. */
memset(&client_thread, 0, sizeof(client_thread));
@@ -1037,9 +1195,9 @@ int main(int argc, char **argv)
main_loop_wait(false);
if (state == TERMINATE) {
state = TERMINATING;
- nbd_export_close(exp);
- nbd_export_put(exp);
- exp = NULL;
+ nbd_export_close(export);
+ nbd_export_put(export);
+ export = NULL;
}
} while (state != TERMINATED);
diff --git a/qemu-nbd.texi b/qemu-nbd.texi
index 9a84e81eed..386bece468 100644
--- a/qemu-nbd.texi
+++ b/qemu-nbd.texi
@@ -2,6 +2,8 @@
@c man begin SYNOPSIS
@command{qemu-nbd} [OPTION]... @var{filename}
+@command{qemu-nbd} @option{-L} [OPTION]...
+
@command{qemu-nbd} @option{-d} @var{dev}
@c man end
@end example
@@ -10,11 +12,19 @@
Export a QEMU disk image using the NBD protocol.
+Other uses:
+@itemize
+@item
+Bind a /dev/nbdX block device to a QEMU server (on Linux).
+@item
+As a client to query exports of a remote NBD server.
+@end itemize
+
@c man end
@c man begin OPTIONS
@var{filename} is a disk image filename, or a set of block
-driver options if @var{--image-opts} is specified.
+driver options if @option{--image-opts} is specified.
@var{dev} is an NBD device.
@@ -25,30 +35,37 @@ See the @code{qemu(1)} manual page for full details of the properties
supported. The common object types that it makes sense to define are the
@code{secret} object, which is used to supply passwords and/or encryption
keys, and the @code{tls-creds} object, which is used to supply TLS
-credentials for the qemu-nbd server.
+credentials for the qemu-nbd server or client.
@item -p, --port=@var{port}
-The TCP port to listen on (default @samp{10809})
+The TCP port to listen on as a server, or connect to as a client
+(default @samp{10809}).
@item -o, --offset=@var{offset}
-The offset into the image
+The offset into the image.
@item -b, --bind=@var{iface}
-The interface to bind to (default @samp{0.0.0.0})
+The interface to bind to as a server, or connect to as a client
+(default @samp{0.0.0.0}).
@item -k, --socket=@var{path}
-Use a unix socket with path @var{path}
+Use a unix socket with path @var{path}.
@item --image-opts
Treat @var{filename} as a set of image options, instead of a plain
filename. If this flag is specified, the @var{-f} flag should
not be used, instead the '@code{format=}' option should be set.
@item -f, --format=@var{fmt}
Force the use of the block driver for format @var{fmt} instead of
-auto-detecting
+auto-detecting.
@item -r, --read-only
-Export the disk as read-only
+Export the disk as read-only.
@item -P, --partition=@var{num}
-Only expose partition @var{num}
+Only expose MBR partition @var{num}. Understands physical partitions
+1-4 and logical partitions 5-8.
+@item -B, --bitmap=@var{name}
+If @var{filename} has a qcow2 persistent bitmap @var{name}, expose
+that bitmap via the ``qemu:dirty-bitmap:@var{name}'' context
+accessible through NBD_OPT_SET_META_CONTEXT.
@item -s, --snapshot
Use @var{filename} as an external snapshot, create a temporary
file with backing_file=@var{filename}, redirect the write to
-the temporary one
+the temporary one.
@item -l, --load-snapshot=@var{snapshot_param}
Load an internal snapshot inside @var{filename} and export it
as an read-only device, @var{snapshot_param} format is
@@ -72,31 +89,38 @@ driver-specific optimized zero write commands. @var{detect-zeroes} is one of
converts a zero write to an unmap operation and can only be used if
@var{discard} is set to @samp{unmap}. The default is @samp{off}.
@item -c, --connect=@var{dev}
-Connect @var{filename} to NBD device @var{dev}
+Connect @var{filename} to NBD device @var{dev} (Linux only).
@item -d, --disconnect
-Disconnect the device @var{dev}
+Disconnect the device @var{dev} (Linux only).
@item -e, --shared=@var{num}
-Allow up to @var{num} clients to share the device (default @samp{1})
+Allow up to @var{num} clients to share the device (default
+@samp{1}). Safe for readers, but for now, consistency is not
+guaranteed between multiple writers.
@item -t, --persistent
-Don't exit on the last connection
+Don't exit on the last connection.
@item -x, --export-name=@var{name}
-Set the NBD volume export name. This switches the server to use
-the new style NBD protocol negotiation
+Set the NBD volume export name (default of a zero-length string).
@item -D, --description=@var{description}
Set the NBD volume export description, as a human-readable
-string. Requires the use of @option{-x}
+string.
+@item -L, --list
+Connect as a client and list all details about the exports exposed by
+a remote NBD server. This enables list mode, and is incompatible
+with options that change behavior related to a specific export (such as
+@option{--export-name}, @option{--offset}, ...).
@item --tls-creds=ID
Enable mandatory TLS encryption for the server by setting the ID
of the TLS credentials object previously created with the --object
-option.
+option; or provide the credentials needed for connecting as a client
+in list mode.
@item --fork
Fork off the server process and exit the parent once the server is running.
@item -v, --verbose
-Display extra debugging information
+Display extra debugging information.
@item -h, --help
-Display this help and exit
+Display this help and exit.
@item -V, --version
-Display version information and exit
+Display version information and exit.
@item -T, --trace [[enable=]@var{pattern}][,events=@var{file}][,file=@var{file}]
@findex --trace
@include qemu-option-trace.texi
@@ -104,6 +128,63 @@ Display version information and exit
@c man end
+@c man begin EXAMPLES
+Start a server listening on port 10809 that exposes only the
+guest-visible contents of a qcow2 file, with no TLS encryption, and
+with the default export name (an empty string). The command is
+one-shot, and will block until the first successful client
+disconnects:
+
+@example
+qemu-nbd -f qcow2 file.qcow2
+@end example
+
+Start a long-running server listening with encryption on port 10810,
+and require clients to have a correct X.509 certificate to connect to
+a 1 megabyte subset of a raw file, using the export name 'subset':
+
+@example
+qemu-nbd \
+ --object tls-creds-x509,id=tls0,endpoint=server,dir=/path/to/qemutls \
+ --tls-creds tls0 -t -x subset -p 10810 \
+ --image-opts driver=raw,offset=1M,size=1M,file.driver=file,file.filename=file.raw
+@end example
+
+Serve a read-only copy of just the first MBR partition of a guest
+image over a Unix socket with as many as 5 simultaneous readers, with
+a persistent process forked as a daemon:
+
+@example
+qemu-nbd --fork --persistent --shared=5 --socket=/path/to/sock \
+ --partition=1 --read-only --format=qcow2 file.qcow2
+@end example
+
+Expose the guest-visible contents of a qcow2 file via a block device
+/dev/nbd0 (and possibly creating /dev/nbd0p1 and friends for
+partitions found within), then disconnect the device when done.
+Access to bind qemu-nbd to an /dev/nbd device generally requires root
+privileges, and may also require the execution of @code{modprobe nbd}
+to enable the kernel NBD client module. @emph{CAUTION}: Do not use
+this method to mount filesystems from an untrusted guest image - a
+malicious guest may have prepared the image to attempt to trigger
+kernel bugs in partition probing or file system mounting.
+
+@example
+qemu-nbd -c /dev/nbd0 -f qcow2 file.qcow2
+qemu-nbd -d /dev/nbd0
+@end example
+
+Query a remote server to see details about what export(s) it is
+serving on port 10809, and authenticating via PSK:
+
+@example
+qemu-nbd \
+ --object tls-creds-psk,id=tls0,dir=/tmp/keys,username=eblake,endpoint=client \
+ --tls-creds tls0 -L -b remote.example.com
+@end example
+
+@c man end
+
@ignore
@setfilename qemu-nbd
diff --git a/qemu-options.hx b/qemu-options.hx
index 269eda7a5d..521511ec13 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -538,8 +538,8 @@ ETEXI
DEF("name", HAS_ARG, QEMU_OPTION_name,
"-name string1[,process=string2][,debug-threads=on|off]\n"
" set the name of the guest\n"
- " string1 sets the window title and string2 the process name (on Linux)\n"
- " When debug-threads is enabled, individual threads are given a separate name (on Linux)\n"
+ " string1 sets the window title and string2 the process name\n"
+ " When debug-threads is enabled, individual threads are given a separate name\n"
" NOTE: The thread names are for debugging and not a stable API.\n",
QEMU_ARCH_ALL)
STEXI
@@ -1019,7 +1019,7 @@ Define a new file system device. Valid options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
-Currently "local", "handle" and "proxy" file system drivers are supported.
+Currently "local" and "proxy" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
@@ -1037,7 +1037,7 @@ hidden .virtfs_metadata directory. Directories exported by this security model c
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory
-only for local fsdriver. Other fsdrivers (like handle, proxy) don't take
+only for local fsdriver. Other fsdrivers (like proxy) don't take
security model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
@@ -1088,7 +1088,7 @@ The general form of a Virtual File system pass-through options are:
@table @option
@item @var{fsdriver}
This option specifies the fs driver backend to use.
-Currently "local", "handle" and "proxy" file system drivers are supported.
+Currently "local" and "proxy" file system drivers are supported.
@item id=@var{id}
Specifies identifier for this device
@item path=@var{path}
@@ -1106,7 +1106,7 @@ hidden .virtfs_metadata directory. Directories exported by this security model c
interact with other unix tools. "none" security model is same as
passthrough except the sever won't report failures if it fails to
set file attributes like ownership. Security model is mandatory only
-for local fsdriver. Other fsdrivers (like handle, proxy) don't take security
+for local fsdriver. Other fsdrivers (like proxy) don't take security
model as a parameter.
@item writeout=@var{writeout}
This is an optional argument. The only supported value is "immediate".
@@ -3394,13 +3394,9 @@ ETEXI
DEF("xen-domid", HAS_ARG, QEMU_OPTION_xen_domid,
"-xen-domid id specify xen guest domain id\n", QEMU_ARCH_ALL)
-DEF("xen-create", 0, QEMU_OPTION_xen_create,
- "-xen-create create domain using xen hypercalls, bypassing xend\n"
- " warning: should not be used when xend is in use\n",
- QEMU_ARCH_ALL)
DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
"-xen-attach attach to existing xen domain\n"
- " xend will use this when starting QEMU\n",
+ " libxl will use this when starting QEMU\n",
QEMU_ARCH_ALL)
DEF("xen-domid-restrict", 0, QEMU_OPTION_xen_domid_restrict,
"-xen-domid-restrict restrict set of available xen operations\n"
@@ -3411,14 +3407,10 @@ STEXI
@item -xen-domid @var{id}
@findex -xen-domid
Specify xen guest domain @var{id} (XEN only).
-@item -xen-create
-@findex -xen-create
-Create domain using xen hypercalls, bypassing xend.
-Warning: should not be used when xend is in use (XEN only).
@item -xen-attach
@findex -xen-attach
Attach to existing xen domain.
-xend will use this when starting QEMU (XEN only).
+libxl will use this when starting QEMU (XEN only).
@findex -xen-domid-restrict
Restrict set of available xen operations to specified domain id (XEN only).
ETEXI
diff --git a/qemu-seccomp.c b/qemu-seccomp.c
index 5c73e6ad05..36d5829831 100644
--- a/qemu-seccomp.c
+++ b/qemu-seccomp.c
@@ -41,7 +41,8 @@ struct QemuSeccompSyscall {
};
const struct scmp_arg_cmp sched_setscheduler_arg[] = {
- SCMP_A1(SCMP_CMP_NE, SCHED_IDLE)
+ /* was SCMP_A1(SCMP_CMP_NE, SCHED_IDLE), but expanded due to GCC 4.x bug */
+ { .arg = 1, .op = SCMP_CMP_NE, .datum_a = SCHED_IDLE }
};
static const struct QemuSeccompSyscall blacklist[] = {
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 1877976522..7ee6a33cce 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -1291,7 +1291,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
/* cannot risk guest agent blocking itself on a write in this state */
ga_set_frozen(ga_state);
- QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
+ QTAILQ_FOREACH_REVERSE(mount, &mounts, next) {
/* To issue fsfreeze in the reverse order of mounts, check if the
* mount is listed in the list here */
if (has_mountpoints) {
@@ -1573,10 +1573,7 @@ static bool systemd_supports_mode(SuspendMode mode, Error **errp)
return true;
}
- if (local_err) {
- error_propagate(errp, local_err);
- }
-
+ error_propagate(errp, local_err);
return false;
}
@@ -1782,7 +1779,7 @@ static void guest_suspend(SuspendMode mode, Error **errp)
if (!mode_supported) {
error_setg(errp,
"the requested suspend mode is not supported by the guest");
- } else if (local_err) {
+ } else {
error_propagate(errp, local_err);
}
}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 62e1b51dfe..989b93e702 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -10,12 +10,8 @@
* 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 _WIN32_WINNT
-# define _WIN32_WINNT 0x0600
-#endif
-
#include "qemu/osdep.h"
+
#include <wtypes.h>
#include <powrprof.h>
#include <winsock2.h>
@@ -470,13 +466,11 @@ static STORAGE_BUS_TYPE win2qemu[] = {
[BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA,
[BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB,
[BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID,
-#if (_WIN32_WINNT >= 0x0600)
[BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI,
[BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS,
[BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA,
[BusTypeSd] = GUEST_DISK_BUS_TYPE_SD,
[BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC,
-#endif
#if (_WIN32_WINNT >= 0x0601)
[BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL,
[BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL,
@@ -728,10 +722,8 @@ static void get_single_disk_info(GuestDiskAddress *disk, Error **errp)
if (disk->bus_type == GUEST_DISK_BUS_TYPE_SCSI
|| disk->bus_type == GUEST_DISK_BUS_TYPE_IDE
|| disk->bus_type == GUEST_DISK_BUS_TYPE_RAID
-#if (_WIN32_WINNT >= 0x0600)
/* This bus type is not supported before Windows Server 2003 SP1 */
|| disk->bus_type == GUEST_DISK_BUS_TYPE_SAS
-#endif
) {
/* We are able to use the same ioctls for different bus types
* according to Microsoft docs
@@ -1326,7 +1318,6 @@ static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr,
return NULL;
}
-#if (_WIN32_WINNT >= 0x0600)
static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
{
/* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
@@ -1334,60 +1325,6 @@ static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
*/
return ip_addr->OnLinkPrefixLength;
}
-#else
-/* When using the Windows XP and 2003 build environment, do the best we can to
- * figure out the prefix.
- */
-static IP_ADAPTER_INFO *guest_get_adapters_info(void)
-{
- IP_ADAPTER_INFO *adptr_info = NULL;
- ULONG adptr_info_len = 0;
- DWORD ret;
-
- /* Call the first time to get the adptr_info_len. */
- GetAdaptersInfo(adptr_info, &adptr_info_len);
-
- adptr_info = g_malloc(adptr_info_len);
- ret = GetAdaptersInfo(adptr_info, &adptr_info_len);
- if (ret != ERROR_SUCCESS) {
- g_free(adptr_info);
- adptr_info = NULL;
- }
- return adptr_info;
-}
-
-static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
-{
- int64_t prefix = -1; /* Use for AF_INET6 and unknown/undetermined values. */
- IP_ADAPTER_INFO *adptr_info, *info;
- IP_ADDR_STRING *ip;
- struct in_addr *p;
-
- if (ip_addr->Address.lpSockaddr->sa_family != AF_INET) {
- return prefix;
- }
- adptr_info = guest_get_adapters_info();
- if (adptr_info == NULL) {
- return prefix;
- }
-
- /* Match up the passed in ip_addr with one found in adaptr_info.
- * The matching one in adptr_info will have the netmask.
- */
- p = &((struct sockaddr_in *)ip_addr->Address.lpSockaddr)->sin_addr;
- for (info = adptr_info; info; info = info->Next) {
- for (ip = &info->IpAddressList; ip; ip = ip->Next) {
- if (p->S_un.S_addr == inet_addr(ip->IpAddress.String)) {
- prefix = ctpop32(inet_addr(ip->IpMask.String));
- goto out;
- }
- }
- }
-out:
- g_free(adptr_info);
- return prefix;
-}
-#endif
#define INTERFACE_PATH_BUF_SZ 512
@@ -1908,7 +1845,6 @@ typedef struct _GA_WTSINFOA {
GuestUserList *qmp_guest_get_users(Error **err)
{
-#if (_WIN32_WINNT >= 0x0600)
#define QGA_NANOSECONDS 10000000
GHashTable *cache = NULL;
@@ -1978,10 +1914,6 @@ GuestUserList *qmp_guest_get_users(Error **err)
}
g_hash_table_destroy(cache);
return head;
-#else
- error_setg(err, QERR_UNSUPPORTED);
- return NULL;
-#endif
}
typedef struct _ga_matrix_lookup_t {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index c6725b3ec8..a4ff5b8fc9 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -567,9 +567,11 @@
# For the best results it's strongly recommended to have the pm-utils
# package installed in the guest.
#
-# IMPORTANT: guest-suspend-ram requires QEMU to support the 'system_wakeup'
-# command. Thus, it's *required* to query QEMU for the presence of the
-# 'system_wakeup' command before issuing guest-suspend-ram.
+# IMPORTANT: guest-suspend-ram requires working wakeup support in
+# QEMU. You should check QMP command query-current-machine returns
+# wakeup-suspend-support: true before issuing this command. Failure in
+# doing so can result in a suspended guest that QEMU will not be able to
+# awaken, forcing the user to power cycle the guest to bring it back.
#
# This command does NOT return a response on success. There are two options
# to check for success:
@@ -594,9 +596,11 @@
#
# This command requires the pm-utils package to be installed in the guest.
#
-# IMPORTANT: guest-suspend-hybrid requires QEMU to support the 'system_wakeup'
-# command. Thus, it's *required* to query QEMU for the presence of the
-# 'system_wakeup' command before issuing guest-suspend-hybrid.
+# IMPORTANT: guest-suspend-hybrid requires working wakeup support in
+# QEMU. You should check QMP command query-current-machine returns
+# wakeup-suspend-support: true before issuing this command. Failure in
+# doing so can result in a suspended guest that QEMU will not be able to
+# awaken, forcing the user to power cycle the guest to bring it back.
#
# This command does NOT return a response on success. There are two options
# to check for success:
diff --git a/qmp.c b/qmp.c
index e7c0a2fd60..4c819dd8cf 100644
--- a/qmp.c
+++ b/qmp.c
@@ -88,7 +88,7 @@ UuidInfo *qmp_query_uuid(Error **errp)
void qmp_quit(Error **errp)
{
no_shutdown = 0;
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP);
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_QMP_QUIT);
}
void qmp_stop(Error **errp)
@@ -109,7 +109,7 @@ void qmp_stop(Error **errp)
void qmp_system_reset(Error **errp)
{
- qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP);
+ qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
}
void qmp_system_powerdown(Error **erp)
@@ -183,7 +183,13 @@ void qmp_cont(Error **errp)
void qmp_system_wakeup(Error **errp)
{
- qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ if (!qemu_wakeup_suspend_enabled()) {
+ error_setg(errp,
+ "wake-up from suspend is not supported by this guest");
+ return;
+ }
+
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, errp);
}
ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index 5a840dfd86..7a7ae9e8d1 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -288,6 +288,11 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict)
goto out;
}
+ if (qdict_haskey(dict, qstring_get_str(key))) {
+ parse_error(ctxt, token, "duplicate key");
+ goto out;
+ }
+
qdict_put_obj(dict, qstring_get_str(key), value);
qobject_unref(key);
diff --git a/qom/cpu.c b/qom/cpu.c
index 9ad1372d57..5442a7323b 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -312,7 +312,6 @@ static void cpu_common_parse_features(const char *typename, char *features,
prop->driver = typename;
prop->property = g_strdup(featurestr);
prop->value = g_strdup(val);
- prop->errp = &error_fatal;
qdev_prop_register_global(prop);
} else {
error_setg(errp, "Expected key=value format, found %s.",
diff --git a/qom/object.c b/qom/object.c
index 547dcf97c3..b8c732063b 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -49,7 +49,6 @@ struct TypeImpl
void (*class_init)(ObjectClass *klass, void *data);
void (*class_base_init)(ObjectClass *klass, void *data);
- void (*class_finalize)(ObjectClass *klass, void *data);
void *class_data;
@@ -114,7 +113,6 @@ static TypeImpl *type_new(const TypeInfo *info)
ti->class_init = info->class_init;
ti->class_base_init = info->class_base_init;
- ti->class_finalize = info->class_finalize;
ti->class_data = info->class_data;
ti->instance_init = info->instance_init;
@@ -372,6 +370,44 @@ static void object_post_init_with_type(Object *obj, TypeImpl *ti)
}
}
+void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
+{
+ int i;
+
+ if (!props) {
+ return;
+ }
+
+ for (i = 0; i < props->len; i++) {
+ GlobalProperty *p = g_ptr_array_index(props, i);
+ Error *err = NULL;
+
+ if (object_dynamic_cast(obj, p->driver) == NULL) {
+ continue;
+ }
+ if (p->optional && !object_property_find(obj, p->property, NULL)) {
+ continue;
+ }
+ p->used = true;
+ object_property_parse(obj, p->value, p->property, &err);
+ if (err != NULL) {
+ error_prepend(&err, "can't apply global %s.%s=%s: ",
+ p->driver, p->property, p->value);
+ /*
+ * If errp != NULL, propagate error and return.
+ * If errp == NULL, report a warning, but keep going
+ * with the remaining globals.
+ */
+ if (errp) {
+ error_propagate(errp, err);
+ return;
+ } else {
+ warn_report_err(err);
+ }
+ }
+ }
+}
+
static void object_initialize_with_type(void *data, size_t size, TypeImpl *type)
{
Object *obj = data;
@@ -417,6 +453,7 @@ void object_initialize_childv(Object *parentobj, const char *propname,
{
Error *local_err = NULL;
Object *obj;
+ UserCreatable *uc;
object_initialize(childobj, size, type);
obj = OBJECT(childobj);
@@ -431,8 +468,9 @@ void object_initialize_childv(Object *parentobj, const char *propname,
goto out;
}
- if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
- user_creatable_complete(obj, &local_err);
+ uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE);
+ if (uc) {
+ user_creatable_complete(uc, &local_err);
if (local_err) {
object_unparent(obj);
goto out;
@@ -590,6 +628,7 @@ Object *object_new_with_propv(const char *typename,
Object *obj;
ObjectClass *klass;
Error *local_err = NULL;
+ UserCreatable *uc;
klass = object_class_by_name(typename);
if (!klass) {
@@ -612,8 +651,9 @@ Object *object_new_with_propv(const char *typename,
goto error;
}
- if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
- user_creatable_complete(obj, &local_err);
+ uc = (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE);
+ if (uc) {
+ user_creatable_complete(uc, &local_err);
if (local_err) {
object_unparent(obj);
goto error;
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index 97b79b48bb..db85d1eb75 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -8,18 +8,10 @@
#include "qapi/opts-visitor.h"
#include "qemu/config-file.h"
-void user_creatable_complete(Object *obj, Error **errp)
+void user_creatable_complete(UserCreatable *uc, Error **errp)
{
+ UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
- UserCreatableClass *ucc;
- UserCreatable *uc =
- (UserCreatable *)object_dynamic_cast(obj, TYPE_USER_CREATABLE);
-
- if (!uc) {
- return;
- }
-
- ucc = USER_CREATABLE_GET_CLASS(uc);
if (ucc->complete) {
ucc->complete(uc, errp);
}
@@ -89,7 +81,7 @@ Object *user_creatable_add_type(const char *type, const char *id,
goto out;
}
- user_creatable_complete(obj, &local_err);
+ user_creatable_complete(USER_CREATABLE(obj), &local_err);
if (local_err) {
object_property_del(object_get_objects_root(),
id, &error_abort);
diff --git a/qtest.c b/qtest.c
index 69b9e9962b..60988c8aa2 100644
--- a/qtest.c
+++ b/qtest.c
@@ -164,6 +164,17 @@ static bool qtest_opened;
* where NUM is an IRQ number. For the PC, interrupts can be intercepted
* simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
* NUM=0 even though it is remapped to GSI 2).
+ *
+ * Setting interrupt level:
+ *
+ * > set_irq_in QOM-PATH NAME NUM LEVEL
+ * < OK
+ *
+ * where NAME is the name of the irq/gpio list, NUM is an IRQ number and
+ * LEVEL is an signed integer IRQ level.
+ *
+ * Forcibly set the given interrupt pin to the given level.
+ *
*/
static int hex2nib(char ch)
@@ -290,7 +301,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
if (!dev) {
qtest_send_prefix(chr);
qtest_send(chr, "FAIL Unknown device\n");
- return;
+ return;
}
if (irq_intercept_dev) {
@@ -300,7 +311,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
} else {
qtest_send(chr, "OK\n");
}
- return;
+ return;
}
QLIST_FOREACH(ngl, &dev->gpios, node) {
@@ -326,7 +337,39 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
irq_intercept_dev = dev;
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "set_irq_in") == 0) {
+ DeviceState *dev;
+ qemu_irq irq;
+ char *name;
+ int ret;
+ int num;
+ int level;
+ g_assert(words[1] && words[2] && words[3] && words[4]);
+
+ dev = DEVICE(object_resolve_path(words[1], NULL));
+ if (!dev) {
+ qtest_send_prefix(chr);
+ qtest_send(chr, "FAIL Unknown device\n");
+ return;
+ }
+
+ if (strcmp(words[2], "unnamed-gpio-in") == 0) {
+ name = NULL;
+ } else {
+ name = words[2];
+ }
+
+ ret = qemu_strtoi(words[3], NULL, 0, &num);
+ g_assert(!ret);
+ ret = qemu_strtoi(words[4], NULL, 0, &level);
+ g_assert(!ret);
+
+ irq = qdev_get_gpio_in_named(dev, name, num);
+
+ qemu_set_irq(irq, level);
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "outb") == 0 ||
strcmp(words[0], "outw") == 0 ||
strcmp(words[0], "outl") == 0) {
diff --git a/roms/Makefile b/roms/Makefile
index f4141e1d96..a6043eff37 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -83,12 +83,12 @@ build-seabios-config-%: config.%
cp $< seabios/builds/$*/.config
$(MAKE) -C seabios \
EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
- CROSS_COMPILE=$(x86_64_cross_prefix) \
+ CROSS_PREFIX=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ oldnoconfig
$(MAKE) -C seabios \
EXTRAVERSION=$(SEABIOS_EXTRAVERSION) \
- CROSS_COMPILE=$(x86_64_cross_prefix) \
+ CROSS_PREFIX=$(x86_64_cross_prefix) \
KCONFIG_CONFIG=$(CURDIR)/seabios/builds/$*/.config \
OUT=$(CURDIR)/seabios/builds/$*/ all
diff --git a/roms/ipxe b/roms/ipxe
-Subproject 0600d3ae94f93efd10fc6b3c7420a9557a3a167
+Subproject de4565cbe76ea9f7913a01f331be3ee901bb6e1
diff --git a/roms/qemu-palcode b/roms/qemu-palcode
-Subproject f3c7e44c70254975df2a00af39701eafbac4d47
+Subproject 51c237d7e20d05100eacadee2f61abc17e6bc09
diff --git a/rules.mak b/rules.mak
index bbb2667928..86e033d815 100644
--- a/rules.mak
+++ b/rules.mak
@@ -132,7 +132,9 @@ modules:
# otherwise print the 'quiet' output in the format " NAME args to print"
# NAME should be a short name of the command, 7 letters or fewer.
# If called with only a single argument, will print nothing in quiet mode.
-quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1))
+quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1
+quiet-@ = $(if $(V),,@)
+quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
# cc-option
# Usage: CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
diff --git a/scripts/analyse-locks-simpletrace.py b/scripts/analyse-locks-simpletrace.py
index 30090bdfff..7d9b574300 100755
--- a/scripts/analyse-locks-simpletrace.py
+++ b/scripts/analyse-locks-simpletrace.py
@@ -7,7 +7,6 @@
#
from __future__ import print_function
-import os
import simpletrace
import argparse
import numpy as np
diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py
index 5c2010c917..e527eb168e 100755
--- a/scripts/analyze-migration.py
+++ b/scripts/analyze-migration.py
@@ -23,7 +23,6 @@ import json
import os
import argparse
import collections
-import pprint
def mkdir_p(path):
try:
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 60f6f89a27..d10dddf1be 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -7,6 +7,7 @@
use strict;
use warnings;
+use Term::ANSIColor qw(:constants);
my $P = $0;
$P =~ s@.*/@@g;
@@ -26,6 +27,7 @@ my $tst_only;
my $emacs = 0;
my $terse = 0;
my $file = undef;
+my $color = "auto";
my $no_warnings = 0;
my $summary = 1;
my $mailback = 0;
@@ -64,6 +66,8 @@ Options:
is all off)
--test-only=WORD report only warnings/errors containing WORD
literally
+ --color[=WHEN] Use colors 'always', 'never', or only when output
+ is a terminal ('auto'). Default is 'auto'.
-h, --help, --version display this help and exit
When FILE is - read standard input.
@@ -72,6 +76,14 @@ EOM
exit($exitcode);
}
+# Perl's Getopt::Long allows options to take optional arguments after a space.
+# Prevent --color by itself from consuming other arguments
+foreach (@ARGV) {
+ if ($_ eq "--color" || $_ eq "-color") {
+ $_ = "--color=$color";
+ }
+}
+
GetOptions(
'q|quiet+' => \$quiet,
'tree!' => \$tree,
@@ -89,6 +101,8 @@ GetOptions(
'debug=s' => \%debug,
'test-only=s' => \$tst_only,
+ 'color=s' => \$color,
+ 'no-color' => sub { $color = 'never'; },
'h|help' => \$help,
'version' => \$help
) or help(1);
@@ -144,6 +158,16 @@ if (!$chk_patch && !$chk_branch && !$file) {
die "One of --file, --branch, --patch is required\n";
}
+if ($color =~ /^always$/i) {
+ $color = 1;
+} elsif ($color =~ /^never$/i) {
+ $color = 0;
+} elsif ($color =~ /^auto$/i) {
+ $color = (-t STDOUT);
+} else {
+ die "Invalid color mode: $color\n";
+}
+
my $dbg_values = 0;
my $dbg_possible = 0;
my $dbg_type = 0;
@@ -202,7 +226,6 @@ our $Attribute = qr{
QEMU_NORETURN|
QEMU_WARN_UNUSED_RESULT|
QEMU_SENTINEL|
- QEMU_ARTIFICIAL|
QEMU_PACKED|
GCC_FMT_ATTR
}x;
@@ -340,13 +363,18 @@ my @lines = ();
my $vname;
if ($chk_branch) {
my @patches;
+ my %git_commits = ();
my $HASH;
- open($HASH, "-|", "git", "log", "--format=%H", $ARGV[0]) ||
- die "$P: git log --format=%H $ARGV[0] failed - $!\n";
-
- while (<$HASH>) {
- chomp;
- push @patches, $_;
+ open($HASH, "-|", "git", "log", "--reverse", "--no-merges", "--format=%H %s", $ARGV[0]) ||
+ die "$P: git log --reverse --no-merges --format='%H %s' $ARGV[0] failed - $!\n";
+
+ for my $line (<$HASH>) {
+ $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
+ next if (!defined($1) || !defined($2));
+ my $sha1 = $1;
+ my $subject = $2;
+ push(@patches, $sha1);
+ $git_commits{$sha1} = $subject;
}
close $HASH;
@@ -354,21 +382,33 @@ if ($chk_branch) {
die "$P: no revisions returned for revlist '$chk_branch'\n"
unless @patches;
+ my $i = 1;
+ my $num_patches = @patches;
for my $hash (@patches) {
my $FILE;
open($FILE, '-|', "git", "show", $hash) ||
die "$P: git show $hash - $!\n";
- $vname = $hash;
while (<$FILE>) {
chomp;
push(@rawlines, $_);
}
close($FILE);
+ $vname = substr($hash, 0, 12) . ' (' . $git_commits{$hash} . ')';
+ if ($num_patches > 1 && $quiet == 0) {
+ my $prefix = "$i/$num_patches";
+ $prefix = BLUE . BOLD . $prefix . RESET if $color;
+ print "$prefix Checking commit $vname\n";
+ $vname = "Patch $i/$num_patches";
+ } else {
+ $vname = "Commit " . $vname;
+ }
if (!process($hash)) {
$exit = 1;
+ print "\n" if ($num_patches > 1 && $quiet == 0);
}
@rawlines = ();
@lines = ();
+ $i++;
}
} else {
for my $filename (@ARGV) {
@@ -387,6 +427,7 @@ if ($chk_branch) {
} else {
$vname = $filename;
}
+ print "Checking $filename...\n" if @ARGV > 1 && $quiet == 0;
while (<$FILE>) {
chomp;
push(@rawlines, $_);
@@ -1166,14 +1207,23 @@ sub possible {
my $prefix = '';
sub report {
- if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+ my ($level, $msg) = @_;
+ if (defined $tst_only && $msg !~ /\Q$tst_only\E/) {
return 0;
}
- my $line = $prefix . $_[0];
- $line = (split('\n', $line))[0] . "\n" if ($terse);
+ my $output = '';
+ $output .= BOLD if $color;
+ $output .= $prefix;
+ $output .= RED if $color && $level eq 'ERROR';
+ $output .= MAGENTA if $color && $level eq 'WARNING';
+ $output .= $level . ':';
+ $output .= RESET if $color;
+ $output .= ' ' . $msg . "\n";
- push(our @report, $line);
+ $output = (split('\n', $output))[0] . "\n" if ($terse);
+
+ push(our @report, $output);
return 1;
}
@@ -1181,13 +1231,13 @@ sub report_dump {
our @report;
}
sub ERROR {
- if (report("ERROR: $_[0]\n")) {
+ if (report("ERROR", $_[0])) {
our $clean = 0;
our $cnt_error++;
}
}
sub WARN {
- if (report("WARNING: $_[0]\n")) {
+ if (report("WARNING", $_[0])) {
our $clean = 0;
our $cnt_warn++;
}
@@ -1570,6 +1620,54 @@ sub process {
# check we are in a valid C source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|cpp)$/);
+# Block comment styles
+
+ # Block comments use /* on a line of its own
+ if ($rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
+ $rawline =~ m@^\+.*/\*\*?[ \t]*.+[ \t]*$@) { # /* or /** non-blank
+ WARN("Block comments use a leading /* on a separate line\n" . $herecurr);
+ }
+
+# Block comments use * on subsequent lines
+ if ($prevline =~ /$;[ \t]*$/ && #ends in comment
+ $prevrawline =~ /^\+.*?\/\*/ && #starting /*
+ $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */
+ $rawline =~ /^\+/ && #line is new
+ $rawline !~ /^\+[ \t]*\*/) { #no leading *
+ WARN("Block comments use * on subsequent lines\n" . $hereprev);
+ }
+
+# Block comments use */ on trailing lines
+ if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */
+ $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
+ $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/
+ $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */
+ WARN("Block comments use a trailing */ on a separate line\n" . $herecurr);
+ }
+
+# Block comment * alignment
+ if ($prevline =~ /$;[ \t]*$/ && #ends in comment
+ $line =~ /^\+[ \t]*$;/ && #leading comment
+ $rawline =~ /^\+[ \t]*\*/ && #leading *
+ (($prevrawline =~ /^\+.*?\/\*/ && #leading /*
+ $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */
+ $prevrawline =~ /^\+[ \t]*\*/)) { #leading *
+ my $oldindent;
+ $prevrawline =~ m@^\+([ \t]*/?)\*@;
+ if (defined($1)) {
+ $oldindent = expand_tabs($1);
+ } else {
+ $prevrawline =~ m@^\+(.*/?)\*@;
+ $oldindent = expand_tabs($1);
+ }
+ $rawline =~ m@^\+([ \t]*)\*@;
+ my $newindent = $1;
+ $newindent = expand_tabs($newindent);
+ if (length($oldindent) ne length($newindent)) {
+ WARN("Block comments should align the * on each line\n" . $hereprev);
+ }
+ }
+
# Check for potential 'bare' types
my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
$realline_next);
@@ -2212,6 +2310,11 @@ sub process {
}
}
+ if ($line =~ /^.\s*(Q(?:S?LIST|SIMPLEQ|TAILQ)_HEAD)\s*\(\s*[^,]/ &&
+ $line !~ /^.typedef/) {
+ ERROR("named $1 should be typedefed separately\n" . $herecurr);
+ }
+
# Need a space before open parenthesis after if, while etc
if ($line=~/\b(if|while|for|switch)\(/) {
ERROR("space required before the open parenthesis '('\n" . $herecurr);
@@ -2817,30 +2920,31 @@ sub process {
}
}
+ if ($is_patch && $chk_signoff && $signoff == 0) {
+ ERROR("Missing Signed-off-by: line(s)\n");
+ }
+
# If we have no input at all, then there is nothing to report on
# so just keep quiet.
if ($#rawlines == -1) {
- exit(0);
+ return 1;
}
# In mailback mode only produce a report in the negative, for
# things that appear to be patches.
if ($mailback && ($clean == 1 || !$is_patch)) {
- exit(0);
+ return 1;
}
# This is not a patch, and we are are in 'no-patch' mode so
# just keep quiet.
if (!$chk_patch && !$is_patch) {
- exit(0);
+ return 1;
}
if (!$is_patch) {
ERROR("Does not appear to be a unified-diff format patch\n");
}
- if ($is_patch && $chk_signoff && $signoff == 0) {
- ERROR("Missing Signed-off-by: line(s)\n");
- }
print report_dump();
if ($summary && !($clean == 1 && $quiet == 1)) {
diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h
index 9f2e72e7e1..e485cdccae 100644
--- a/scripts/cocci-macro-file.h
+++ b/scripts/cocci-macro-file.h
@@ -23,7 +23,6 @@
#define QEMU_NORETURN __attribute__ ((__noreturn__))
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define QEMU_SENTINEL __attribute__((sentinel))
-#define QEMU_ARTIFICIAL __attribute__((always_inline, artificial))
#define QEMU_PACKED __attribute__((gcc_struct, packed))
#define cat(x,y) x ## y
@@ -93,29 +92,19 @@ struct { \
/*
* Tail queue definitions.
*/
-#define Q_TAILQ_HEAD(name, type, qual) \
-struct name { \
- qual type *tqh_first; /* first element */ \
- qual type *qual *tqh_last; /* addr of last next element */ \
-}
#define QTAILQ_HEAD(name, type) \
-struct name { \
- type *tqh_first; /* first element */ \
- type **tqh_last; /* addr of last next element */ \
+union name { \
+ struct type *tqh_first; /* first element */ \
+ QTailQLink tqh_circ; /* link for last element */ \
}
#define QTAILQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).tqh_first }
+ { .tqh_circ = { NULL, &(head).tqh_circ } }
-#define Q_TAILQ_ENTRY(type, qual) \
-struct { \
- qual type *tqe_next; /* next element */ \
- qual type *qual *tqe_prev; /* address of previous next element */\
-}
#define QTAILQ_ENTRY(type) \
-struct { \
- type *tqe_next; /* next element */ \
- type **tqe_prev; /* address of previous next element */ \
+union { \
+ struct type *tqe_next; /* next element */ \
+ QTailQLink tqe_circ; /* link for prev element */ \
}
/* From glib */
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index e93a7c0c84..483dafb2fc 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -26,7 +26,6 @@ check for crashes and unexpected errors.
from __future__ import print_function
import sys
-import os
import glob
import logging
import traceback
@@ -83,7 +82,6 @@ ERROR_WHITELIST = [
{'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device
- {'device':'ivshmem', 'expected':True}, # You must specify either 'shm' or 'chardev'
{'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev'
{'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev'
{'device':'loader', 'expected':True}, # please include valid arguments
@@ -182,21 +180,6 @@ ERROR_WHITELIST = [
# other exitcode=1 failures not listed above will just generate INFO messages:
{'exitcode':1, 'loglevel':logging.INFO},
- # KNOWN CRASHES:
- # Known crashes will generate error messages, but won't be fatal.
- # Those entries must be removed once we fix the crashes.
- {'exitcode':-6, 'log':r"Device 'serial0' is in use", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"qemu_net_client_setup: Assertion `!peer->peer' failed", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r'RAMBlock "[\w.-]+" already registered', 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"find_ram_offset: Assertion `size != 0' failed.", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"add_cpreg_to_hashtable: code should not be reached", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"qemu_alloc_display: Assertion `surface->image != NULL' failed", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Unexpected error in error_set_from_qdev_prop_error", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR},
-
# everything else (including SIGABRT and SIGSEGV) will be a fatal error:
{'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL},
]
diff --git a/scripts/fix-multiline-comments.sh b/scripts/fix-multiline-comments.sh
new file mode 100755
index 0000000000..93f9b10669
--- /dev/null
+++ b/scripts/fix-multiline-comments.sh
@@ -0,0 +1,62 @@
+#! /bin/sh
+#
+# Fix multiline comments to match CODING_STYLE
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini
+#
+# Usage: scripts/fix-multiline-comments.sh [-i] FILE...
+#
+# -i edits the file in place (requires gawk 4.1.0).
+#
+# Set the AWK environment variable to choose the awk interpreter to use
+# (default 'awk')
+
+if test "$1" = -i; then
+ # gawk extension
+ inplace="-i inplace"
+ shift
+fi
+${AWK-awk} $inplace 'BEGIN { indent = -1 }
+{
+ line = $0
+ # apply a star to the indent on lines after the first
+ if (indent != -1) {
+ if (line == "") {
+ line = sp " *"
+ } else if (substr(line, 1, indent + 2) == sp " ") {
+ line = sp " *" substr(line, indent + 3)
+ }
+ }
+
+ is_lead = (line ~ /^[ \t]*\/\*/)
+ is_trail = (line ~ /\*\//)
+ if (is_lead && !is_trail) {
+ # grab the indent at the start of a comment, but not for
+ # single-line comments
+ match(line, /^[ \t]*\/\*/)
+ indent = RLENGTH - 2
+ sp = substr(line, 1, indent)
+ }
+
+ # the regular expression filters out lone /*, /**, or */
+ if (indent != -1 && !(line ~ /^[ \t]*(\/\*+|\*\/)[ \t]*$/)) {
+ if (is_lead) {
+ # split the leading /* or /** on a separate line
+ match(line, /^[ \t]*\/\*+/)
+ lead = substr(line, 1, RLENGTH)
+ match(line, /^[ \t]*\/\*+[ \t]*/)
+ line = lead "\n" sp " *" substr(line, RLENGTH)
+ }
+ if (is_trail) {
+ # split the trailing */ on a separate line
+ match(line, /[ \t]*\*\//)
+ line = substr(line, 1, RSTART - 1) "\n" sp " */"
+ }
+ }
+ if (is_trail) {
+ indent = -1
+ }
+ print line
+}' "$@"
diff --git a/scripts/gtester-cat b/scripts/gtester-cat
deleted file mode 100755
index 061a952cad..0000000000
--- a/scripts/gtester-cat
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-#
-# Copyright IBM, Corp. 2012
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2 or later.
-# See the COPYING file in the top-level directory.
-
-cat <<EOF
-<?xml version="1.0"?>
-<gtester>
- <info>
- <package>qemu</package>
- <version>0.0</version>
- <revision>rev</revision>
- </info>
-EOF
-
-sed \
- -e '/<?xml/d' \
- -e '/^<gtester>$/d' \
- -e '/<info>/,/<\/info>/d' \
- -e '$b' \
- -e '/^<\/gtester>$/d' "$@"
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 7b62a4c7b0..c89edc0cb0 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -588,11 +588,11 @@ def discriminator_find_enum_define(expr):
if not base_members:
return None
- discriminator_type = base_members.get(discriminator)
- if not discriminator_type:
+ discriminator_value = base_members.get(discriminator)
+ if not discriminator_value:
return None
- return enum_types.get(discriminator_type)
+ return enum_types.get(discriminator_value['type'])
# Names must be letters, numbers, -, and _. They must start with letter,
@@ -704,8 +704,10 @@ def check_type(info, source, value, allow_array=False,
% (source, key))
# Todo: allow dictionaries to represent default values of
# an optional argument.
- check_type(info, "Member '%s' of %s" % (key, source), arg,
- allow_array=True,
+ check_known_keys(info, "member '%s' of %s" % (key, source),
+ arg, ['type'], ['if'])
+ check_type(info, "Member '%s' of %s" % (key, source),
+ arg['type'], allow_array=True,
allow_metas=['built-in', 'union', 'alternate', 'struct',
'enum'])
@@ -740,6 +742,10 @@ def check_event(expr, info):
allow_metas=meta)
+def enum_get_names(expr):
+ return [e['name'] for e in expr['data']]
+
+
def check_union(expr, info):
name = expr['union']
base = expr.get('base')
@@ -772,13 +778,17 @@ def check_union(expr, info):
# member of the base struct.
check_name(info, "Discriminator of flat union '%s'" % name,
discriminator)
- discriminator_type = base_members.get(discriminator)
- if not discriminator_type:
+ discriminator_value = base_members.get(discriminator)
+ if not discriminator_value:
raise QAPISemError(info,
"Discriminator '%s' is not a member of base "
"struct '%s'"
% (discriminator, base))
- enum_define = enum_types.get(discriminator_type)
+ if discriminator_value.get('if'):
+ raise QAPISemError(info, 'The discriminator %s.%s for union %s '
+ 'must not be conditional' %
+ (base, discriminator, name))
+ enum_define = enum_types.get(discriminator_value['type'])
allow_metas = ['struct']
# Do not allow string discriminator
if not enum_define:
@@ -792,14 +802,17 @@ def check_union(expr, info):
for (key, value) in members.items():
check_name(info, "Member of union '%s'" % name, key)
+ check_known_keys(info, "member '%s' of union '%s'" % (key, name),
+ value, ['type'], ['if'])
# Each value must name a known type
check_type(info, "Member '%s' of union '%s'" % (key, name),
- value, allow_array=not base, allow_metas=allow_metas)
+ value['type'],
+ allow_array=not base, allow_metas=allow_metas)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
if enum_define:
- if key not in enum_define['data']:
+ if key not in enum_get_names(enum_define):
raise QAPISemError(info,
"Discriminator value '%s' is not found in "
"enum '%s'"
@@ -818,20 +831,23 @@ def check_alternate(expr, info):
"in 'data'" % name)
for (key, value) in members.items():
check_name(info, "Member of alternate '%s'" % name, key)
+ check_known_keys(info,
+ "member '%s' of alternate '%s'" % (key, name),
+ value, ['type'], ['if'])
+ typ = value['type']
# Ensure alternates have no type conflicts.
- check_type(info, "Member '%s' of alternate '%s'" % (key, name),
- value,
+ check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ,
allow_metas=['built-in', 'union', 'struct', 'enum'])
- qtype = find_alternate_member_qtype(value)
+ qtype = find_alternate_member_qtype(typ)
if not qtype:
raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
- "type '%s'" % (name, key, value))
+ "type '%s'" % (name, key, typ))
conflicting = set([qtype])
if qtype == 'QTYPE_QSTRING':
- enum_expr = enum_types.get(value)
+ enum_expr = enum_types.get(typ)
if enum_expr:
- for v in enum_expr['data']:
+ for v in enum_get_names(enum_expr):
if v in ['on', 'off']:
conflicting.add('QTYPE_QBOOL')
if re.match(r'[-+0-9.]', v): # lazy, could be tightened
@@ -849,7 +865,7 @@ def check_alternate(expr, info):
def check_enum(expr, info):
name = expr['enum']
- members = expr.get('data')
+ members = expr['data']
prefix = expr.get('prefix')
if not isinstance(members, list):
@@ -858,8 +874,12 @@ def check_enum(expr, info):
if prefix is not None and not isinstance(prefix, str):
raise QAPISemError(info,
"Enum '%s' requires a string for 'prefix'" % name)
+
for member in members:
- check_name(info, "Member of enum '%s'" % name, member,
+ source = "dictionary member of enum '%s'" % name
+ check_known_keys(info, source, member, ['name'], ['if'])
+ check_if(member, info)
+ check_name(info, "Member of enum '%s'" % name, member['name'],
enum_member=True)
@@ -873,6 +893,24 @@ def check_struct(expr, info):
allow_metas=['struct'])
+def check_known_keys(info, source, keys, required, optional):
+
+ def pprint(elems):
+ return ', '.join("'" + e + "'" for e in sorted(elems))
+
+ missing = set(required) - set(keys)
+ if missing:
+ raise QAPISemError(info, "Key%s %s %s missing from %s"
+ % ('s' if len(missing) > 1 else '', pprint(missing),
+ 'are' if len(missing) > 1 else 'is', source))
+ allowed = set(required + optional)
+ unknown = set(keys) - allowed
+ if unknown:
+ raise QAPISemError(info, "Unknown key%s %s in %s\nValid keys are %s."
+ % ('s' if len(unknown) > 1 else '', pprint(unknown),
+ source, pprint(allowed)))
+
+
def check_keys(expr_elem, meta, required, optional=[]):
expr = expr_elem['expr']
info = expr_elem['info']
@@ -880,10 +918,9 @@ def check_keys(expr_elem, meta, required, optional=[]):
if not isinstance(name, str):
raise QAPISemError(info, "'%s' key must have a string value" % meta)
required = required + [meta]
+ source = "%s '%s'" % (meta, name)
+ check_known_keys(info, source, expr.keys(), required, optional)
for (key, value) in expr.items():
- if key not in required and key not in optional:
- raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
- % (key, meta, name))
if key in ['gen', 'success-response'] and value is not False:
raise QAPISemError(info,
"'%s' of %s '%s' should only use false value"
@@ -895,10 +932,20 @@ def check_keys(expr_elem, meta, required, optional=[]):
% (key, meta, name))
if key == 'if':
check_if(expr, info)
- for key in required:
- if key not in expr:
- raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
- % (key, meta, name))
+
+
+def normalize_enum(expr):
+ if isinstance(expr['data'], list):
+ expr['data'] = [m if isinstance(m, dict) else {'name': m}
+ for m in expr['data']]
+
+
+def normalize_members(members):
+ if isinstance(members, OrderedDict):
+ for key, arg in members.items():
+ if isinstance(arg, dict):
+ continue
+ members[key] = {'type': arg}
def check_exprs(exprs):
@@ -924,27 +971,34 @@ def check_exprs(exprs):
if 'enum' in expr:
meta = 'enum'
check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
+ normalize_enum(expr)
enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
check_keys(expr_elem, 'union', ['data'],
['base', 'discriminator', 'if'])
+ normalize_members(expr.get('base'))
+ normalize_members(expr['data'])
union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
check_keys(expr_elem, 'alternate', ['data'], ['if'])
+ normalize_members(expr['data'])
elif 'struct' in expr:
meta = 'struct'
check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
+ normalize_members(expr['data'])
struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
'boxed', 'allow-oob', 'allow-preconfig', 'if'])
+ normalize_members(expr.get('data'))
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
+ normalize_members(expr.get('data'))
else:
raise QAPISemError(expr_elem['info'],
"Expression is missing metatype")
@@ -1063,7 +1117,7 @@ class QAPISchemaVisitor(object):
def visit_builtin_type(self, name, info, json_type):
pass
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
pass
def visit_array_type(self, name, info, ifcond, element_type):
@@ -1161,22 +1215,22 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond, values, prefix):
+ def __init__(self, name, info, doc, ifcond, members, prefix):
QAPISchemaType.__init__(self, name, info, doc, ifcond)
- for v in values:
- assert isinstance(v, QAPISchemaMember)
- v.set_owner(name)
+ for m in members:
+ assert isinstance(m, QAPISchemaMember)
+ m.set_owner(name)
assert prefix is None or isinstance(prefix, str)
- self.values = values
+ self.members = members
self.prefix = prefix
def check(self, schema):
QAPISchemaType.check(self, schema)
seen = {}
- for v in self.values:
- v.check_clash(self.info, seen)
+ for m in self.members:
+ m.check_clash(self.info, seen)
if self.doc:
- self.doc.connect_member(v)
+ self.doc.connect_member(m)
def is_implicit(self):
# See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
@@ -1186,14 +1240,14 @@ class QAPISchemaEnumType(QAPISchemaType):
return c_name(self.name)
def member_names(self):
- return [v.name for v in self.values]
+ return [m.name for m in self.members]
def json_type(self):
return 'string'
def visit(self, visitor):
visitor.visit_enum_type(self.name, self.info, self.ifcond,
- self.member_names(), self.prefix)
+ self.members, self.prefix)
class QAPISchemaArrayType(QAPISchemaType):
@@ -1318,9 +1372,10 @@ class QAPISchemaObjectType(QAPISchemaType):
class QAPISchemaMember(object):
role = 'member'
- def __init__(self, name):
+ def __init__(self, name, ifcond=None):
assert isinstance(name, str)
self.name = name
+ self.ifcond = listify_cond(ifcond)
self.owner = None
def set_owner(self, name):
@@ -1361,8 +1416,8 @@ class QAPISchemaMember(object):
class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, typ, optional):
- QAPISchemaMember.__init__(self, name)
+ def __init__(self, name, typ, optional, ifcond=None):
+ QAPISchemaMember.__init__(self, name, ifcond)
assert isinstance(typ, str)
assert isinstance(optional, bool)
self._type_name = typ
@@ -1403,9 +1458,10 @@ class QAPISchemaObjectTypeVariants(object):
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = set([v.name for v in self.variants])
- for val in self.tag_member.type.values:
- if val.name not in cases:
- v = QAPISchemaObjectTypeVariant(val.name, 'q_empty')
+ for m in self.tag_member.type.members:
+ if m.name not in cases:
+ v = QAPISchemaObjectTypeVariant(m.name, 'q_empty',
+ m.ifcond)
v.set_owner(self.tag_member.owner)
self.variants.append(v)
for v in self.variants:
@@ -1428,8 +1484,8 @@ class QAPISchemaObjectTypeVariants(object):
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
role = 'branch'
- def __init__(self, name, typ):
- QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
+ def __init__(self, name, typ, ifcond=None):
+ QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
class QAPISchemaAlternateType(QAPISchemaType):
@@ -1620,14 +1676,16 @@ class QAPISchema(object):
self.the_empty_object_type = QAPISchemaObjectType(
'q_empty', None, None, None, None, [], None)
self._def_entity(self.the_empty_object_type)
- qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
- 'qstring', 'qdict', 'qlist',
- 'qbool'])
+
+ qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
+ 'qbool']
+ qtype_values = self._make_enum_members([{'name': n} for n in qtypes])
+
self._def_entity(QAPISchemaEnumType('QType', None, None, None,
qtype_values, 'QTYPE'))
def _make_enum_members(self, values):
- return [QAPISchemaMember(v) for v in values]
+ return [QAPISchemaMember(v['name'], v.get('if')) for v in values]
def _make_implicit_enum_type(self, name, info, ifcond, values):
# See also QAPISchemaObjectTypeMember._pretty_owner()
@@ -1674,7 +1732,7 @@ class QAPISchema(object):
name, info, doc, ifcond,
self._make_enum_members(data), prefix))
- def _make_member(self, name, typ, info):
+ def _make_member(self, name, typ, ifcond, info):
optional = False
if name.startswith('*'):
name = name[1:]
@@ -1682,10 +1740,10 @@ class QAPISchema(object):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
- return QAPISchemaObjectTypeMember(name, typ, optional)
+ return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
def _make_members(self, data, info):
- return [self._make_member(key, value, info)
+ return [self._make_member(key, value['type'], value.get('if'), info)
for (key, value) in data.items()]
def _def_struct_type(self, expr, info, doc):
@@ -1697,17 +1755,17 @@ class QAPISchema(object):
self._make_members(data, info),
None))
- def _make_variant(self, case, typ):
- return QAPISchemaObjectTypeVariant(case, typ)
+ def _make_variant(self, case, typ, ifcond):
+ return QAPISchemaObjectTypeVariant(case, typ, ifcond)
- def _make_simple_variant(self, case, typ, info):
+ def _make_simple_variant(self, case, typ, ifcond, info):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
typ = self._make_implicit_object_type(
typ, info, None, self.lookup_type(typ),
- 'wrapper', [self._make_member('data', typ, info)])
- return QAPISchemaObjectTypeVariant(case, typ)
+ 'wrapper', [self._make_member('data', typ, None, info)])
+ return QAPISchemaObjectTypeVariant(case, typ, ifcond)
def _def_union_type(self, expr, info, doc):
name = expr['union']
@@ -1721,14 +1779,15 @@ class QAPISchema(object):
name, info, doc, ifcond,
'base', self._make_members(base, info))
if tag_name:
- variants = [self._make_variant(key, value)
+ variants = [self._make_variant(key, value['type'], value.get('if'))
for (key, value) in data.items()]
members = []
else:
- variants = [self._make_simple_variant(key, value, info)
+ variants = [self._make_simple_variant(key, value['type'],
+ value.get('if'), info)
for (key, value) in data.items()]
- typ = self._make_implicit_enum_type(name, info, ifcond,
- [v.name for v in variants])
+ enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
+ typ = self._make_implicit_enum_type(name, info, ifcond, enum)
tag_member = QAPISchemaObjectTypeMember('type', typ, False)
members = [tag_member]
self._def_entity(
@@ -1741,7 +1800,7 @@ class QAPISchema(object):
name = expr['alternate']
data = expr['data']
ifcond = expr.get('if')
- variants = [self._make_variant(key, value)
+ variants = [self._make_variant(key, value['type'], value.get('if'))
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
self._def_entity(
@@ -2012,19 +2071,21 @@ def _wrap_ifcond(ifcond, before, after):
return out
-def gen_enum_lookup(name, values, prefix=None):
+def gen_enum_lookup(name, members, prefix=None):
ret = mcgen('''
const QEnumLookup %(c_name)s_lookup = {
.array = (const char *const[]) {
''',
c_name=c_name(name))
- for value in values:
- index = c_enum_const(name, value, prefix)
+ for m in members:
+ ret += gen_if(m.ifcond)
+ index = c_enum_const(name, m.name, prefix)
ret += mcgen('''
- [%(index)s] = "%(value)s",
+ [%(index)s] = "%(name)s",
''',
- index=index, value=value)
+ index=index, name=m.name)
+ ret += gen_endif(m.ifcond)
ret += mcgen('''
},
@@ -2035,9 +2096,9 @@ const QEnumLookup %(c_name)s_lookup = {
return ret
-def gen_enum(name, values, prefix=None):
+def gen_enum(name, members, prefix=None):
# append automatically generated _MAX value
- enum_values = values + ['_MAX']
+ enum_members = members + [QAPISchemaMember('_MAX')]
ret = mcgen('''
@@ -2045,14 +2106,13 @@ typedef enum %(c_name)s {
''',
c_name=c_name(name))
- i = 0
- for value in enum_values:
+ for m in enum_members:
+ ret += gen_if(m.ifcond)
ret += mcgen('''
- %(c_enum)s = %(i)d,
+ %(c_enum)s,
''',
- c_enum=c_enum_const(name, value, prefix),
- i=i)
- i += 1
+ c_enum=c_enum_const(name, m.name, prefix))
+ ret += gen_endif(m.ifcond)
ret += mcgen('''
} %(c_name)s;
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 987fd3c943..c03b690161 100755
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -126,19 +126,27 @@ def texi_body(doc):
return texi_format(doc.body.text)
-def texi_enum_value(value):
+def texi_if(ifcond, prefix='\n', suffix='\n'):
+ """Format the #if condition"""
+ if not ifcond:
+ return ''
+ return '%s@b{If:} @code{%s}%s' % (prefix, ', '.join(ifcond), suffix)
+
+
+def texi_enum_value(value, desc, suffix):
"""Format a table of members item for an enumeration value"""
- return '@item @code{%s}\n' % value.name
+ return '@item @code{%s}\n%s%s' % (
+ value.name, desc, texi_if(value.ifcond, prefix='@*'))
-def texi_member(member, suffix=''):
+def texi_member(member, desc, suffix):
"""Format a table of members item for an object type member"""
typ = member.type.doc_type()
membertype = ': ' + typ if typ else ''
- return '@item @code{%s%s}%s%s\n' % (
+ return '@item @code{%s%s}%s%s\n%s%s' % (
member.name, membertype,
' (optional)' if member.optional else '',
- suffix)
+ suffix, desc, texi_if(member.ifcond, prefix='@*'))
def texi_members(doc, what, base, variants, member_func):
@@ -155,17 +163,17 @@ def texi_members(doc, what, base, variants, member_func):
desc = 'One of ' + members_text + '\n'
else:
desc = 'Not documented\n'
- items += member_func(section.member) + desc
+ items += member_func(section.member, desc, suffix='')
if base:
items += '@item The members of @code{%s}\n' % base.doc_type()
if variants:
for v in variants.variants:
- when = ' when @code{%s} is @t{"%s"}' % (
- variants.tag_member.name, v.name)
+ when = ' when @code{%s} is @t{"%s"}%s' % (
+ variants.tag_member.name, v.name, texi_if(v.ifcond, " (", ")"))
if v.type.is_implicit():
assert not v.type.base and not v.type.variants
for m in v.type.local_members:
- items += member_func(m, when)
+ items += member_func(m, desc='', suffix=when)
else:
items += '@item The members of @code{%s}%s\n' % (
v.type.doc_type(), when)
@@ -185,8 +193,7 @@ def texi_sections(doc, ifcond):
body += texi_example(section.text)
else:
body += texi_format(section.text)
- if ifcond:
- body += '\n\n@b{If:} @code{%s}' % ", ".join(ifcond)
+ body += texi_if(ifcond, suffix='')
return body
@@ -206,7 +213,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
def write(self, output_dir):
self._gen.write(output_dir, self._prefix + 'qapi-doc.texi')
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
doc = self.cur_doc
self._gen.add(TYPE_FMT(type='Enum',
name=doc.symbol,
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 2ed7902424..37ee5de682 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -143,8 +143,8 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
QAPISchemaModularCVisitor.__init__(
self, prefix, 'qapi-events',
' * Schema-defined QAPI/QMP events', __doc__)
- self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
- self._event_names = []
+ self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
+ self._event_enum_members = []
def _begin_module(self, name):
types = self._module_basename('qapi-types', name)
@@ -170,15 +170,16 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
def visit_end(self):
(genc, genh) = self._module[self._main_module]
- genh.add(gen_enum(self._enum_name, self._event_names))
- genc.add(gen_enum_lookup(self._enum_name, self._event_names))
+ genh.add(gen_enum(self._event_enum_name, self._event_enum_members))
+ genc.add(gen_enum_lookup(self._event_enum_name,
+ self._event_enum_members))
def visit_event(self, name, info, ifcond, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed,
- self._enum_name))
- self._event_names.append(name)
+ self._event_enum_name))
+ self._event_enum_members.append(QAPISchemaMember(name, ifcond))
def gen_events(schema, output_dir, prefix):
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 67d6106f77..f7f2ca07e4 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -162,6 +162,8 @@ const QLitObject %(c_name)s = %(c_string)s;
ret = {'name': member.name, 'type': self._use_type(member.type)}
if member.optional:
ret['default'] = None
+ if member.ifcond:
+ ret = (ret, {'if': member.ifcond})
return ret
def _gen_variants(self, tag_name, variants):
@@ -169,13 +171,17 @@ const QLitObject %(c_name)s = %(c_string)s;
'variants': [self._gen_variant(v) for v in variants]}
def _gen_variant(self, variant):
- return {'case': variant.name, 'type': self._use_type(variant.type)}
+ return ({'case': variant.name, 'type': self._use_type(variant.type)},
+ {'if': variant.ifcond})
def visit_builtin_type(self, name, info, json_type):
self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
- def visit_enum_type(self, name, info, ifcond, values, prefix):
- self._gen_qlit(name, 'enum', {'values': values}, ifcond)
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
+ self._gen_qlit(name, 'enum',
+ {'values':
+ [(m.name, {'if': m.ifcond}) for m in members]},
+ ifcond)
def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type)
@@ -191,8 +197,9 @@ const QLitObject %(c_name)s = %(c_string)s;
def visit_alternate_type(self, name, info, ifcond, variants):
self._gen_qlit(name, 'alternate',
- {'members': [{'type': self._use_type(m.type)}
- for m in variants.variants]}, ifcond)
+ {'members': [
+ ({'type': self._use_type(m.type)}, {'if': m.ifcond})
+ for m in variants.variants]}, ifcond)
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index fd7808103c..62d4cf9f95 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -43,6 +43,7 @@ struct %(c_name)s {
def gen_struct_members(members):
ret = ''
for memb in members:
+ ret += gen_if(memb.ifcond)
if memb.optional:
ret += mcgen('''
bool has_%(c_name)s;
@@ -52,6 +53,7 @@ def gen_struct_members(members):
%(c_type)s %(c_name)s;
''',
c_type=memb.type.c_type(), c_name=c_name(memb.name))
+ ret += gen_endif(memb.ifcond)
return ret
@@ -131,11 +133,13 @@ def gen_variants(variants):
for var in variants.variants:
if var.type.name == 'q_empty':
continue
+ ret += gen_if(var.ifcond)
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
c_type=var.type.c_unboxed_type(),
c_name=c_name(var.name))
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
} u;
@@ -212,10 +216,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_type_cleanup_decl(name))
self._genc.add(gen_type_cleanup(name))
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
- self._genh.preamble_add(gen_enum(name, values, prefix))
- self._genc.add(gen_enum_lookup(name, values, prefix))
+ self._genh.preamble_add(gen_enum(name, members, prefix))
+ self._genc.add(gen_enum_lookup(name, members, prefix))
def visit_array_type(self, name, info, ifcond, element_type):
with ifcontext(ifcond, self._genh, self._genc):
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 460cf12989..82eab72b21 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -54,6 +54,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_type=base.c_name())
for memb in members:
+ ret += gen_if(memb.ifcond)
if memb.optional:
ret += mcgen('''
if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@@ -73,6 +74,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
ret += mcgen('''
}
''')
+ ret += gen_endif(memb.ifcond)
if variants:
ret += mcgen('''
@@ -84,6 +86,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case_str = c_enum_const(variants.tag_member.type.name,
var.name,
variants.tag_member.type.prefix)
+ ret += gen_if(var.ifcond)
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
@@ -100,6 +103,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
default:
abort();
@@ -190,6 +194,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
c_name=c_name(name))
for var in variants.variants:
+ ret += gen_if(var.ifcond)
ret += mcgen('''
case %(case)s:
''',
@@ -217,6 +222,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
ret += mcgen('''
break;
''')
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
case QTYPE_NONE:
@@ -310,7 +316,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
''',
types=types))
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name, scalar=True))
self._genc.add(gen_visit_enum(name))
diff --git a/scripts/qemu.py b/scripts/qemu.py
index 6e3b0e6771..0a5e02eb56 100644
--- a/scripts/qemu.py
+++ b/scripts/qemu.py
@@ -351,7 +351,7 @@ class QEMUMachine(object):
command = ' '.join(self._qemu_full_args)
else:
command = ''
- LOG.warn(msg, exitcode, command)
+ LOG.warn(msg, -exitcode, command)
self._launched = False
diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py
index 5ae77c8a92..ee7fda2638 100755
--- a/scripts/replay-dump.py
+++ b/scripts/replay-dump.py
@@ -3,7 +3,7 @@
#
# Dump the contents of a recorded execution stream
#
-# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
+# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index 4ad34f90cd..45485b864b 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -11,7 +11,6 @@
from __future__ import print_function
import struct
-import re
import inspect
from tracetool import read_events, Event
from tracetool.backend.simple import is_string
diff --git a/scripts/tap-driver.pl b/scripts/tap-driver.pl
new file mode 100755
index 0000000000..5e59b5db49
--- /dev/null
+++ b/scripts/tap-driver.pl
@@ -0,0 +1,378 @@
+#! /usr/bin/env perl
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# 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; either version 2, or (at your option)
+# any later version.
+#
+# This program 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 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 <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# ---------------------------------- #
+# Imports, static data, and setup. #
+# ---------------------------------- #
+
+use warnings FATAL => 'all';
+use strict;
+use Getopt::Long ();
+use TAP::Parser;
+use Term::ANSIColor qw(:constants);
+
+my $ME = "tap-driver.pl";
+my $VERSION = "2018-11-30";
+
+my $USAGE = <<'END';
+Usage:
+ tap-driver [--test-name=TEST] [--color={always|never|auto}]
+ [--verbose] [--show-failures-only]
+END
+
+my $HELP = "$ME: TAP-aware test driver for QEMU testsuite harness." .
+ "\n" . $USAGE;
+
+# It's important that NO_PLAN evaluates "false" as a boolean.
+use constant NO_PLAN => 0;
+use constant EARLY_PLAN => 1;
+use constant LATE_PLAN => 2;
+
+use constant DIAG_STRING => "#";
+
+# ------------------- #
+# Global variables. #
+# ------------------- #
+
+my $testno = 0; # Number of test results seen so far.
+my $bailed_out = 0; # Whether a "Bail out!" directive has been seen.
+my $failed = 0; # Final exit code
+
+# Whether the TAP plan has been seen or not, and if yes, which kind
+# it is ("early" is seen before any test result, "late" otherwise).
+my $plan_seen = NO_PLAN;
+
+# ----------------- #
+# Option parsing. #
+# ----------------- #
+
+my %cfg = (
+ "color" => 0,
+ "verbose" => 0,
+ "show-failures-only" => 0,
+);
+
+my $color = "auto";
+my $test_name = undef;
+
+# Perl's Getopt::Long allows options to take optional arguments after a space.
+# Prevent --color by itself from consuming other arguments
+foreach (@ARGV) {
+ if ($_ eq "--color" || $_ eq "-color") {
+ $_ = "--color=$color";
+ }
+}
+
+Getopt::Long::GetOptions
+ (
+ 'help' => sub { print $HELP; exit 0; },
+ 'version' => sub { print "$ME $VERSION\n"; exit 0; },
+ 'test-name=s' => \$test_name,
+ 'color=s' => \$color,
+ 'show-failures-only' => sub { $cfg{"show-failures-only"} = 1; },
+ 'verbose' => sub { $cfg{"verbose"} = 1; },
+ ) or exit 1;
+
+if ($color =~ /^always$/i) {
+ $cfg{'color'} = 1;
+} elsif ($color =~ /^never$/i) {
+ $cfg{'color'} = 0;
+} elsif ($color =~ /^auto$/i) {
+ $cfg{'color'} = (-t STDOUT);
+} else {
+ die "Invalid color mode: $color\n";
+}
+
+# ------------- #
+# Prototypes. #
+# ------------- #
+
+sub colored ($$);
+sub decorate_result ($);
+sub extract_tap_comment ($);
+sub handle_tap_bailout ($);
+sub handle_tap_plan ($);
+sub handle_tap_result ($);
+sub is_null_string ($);
+sub main ();
+sub report ($;$);
+sub stringify_result_obj ($);
+sub testsuite_error ($);
+
+# -------------- #
+# Subroutines. #
+# -------------- #
+
+# If the given string is undefined or empty, return true, otherwise
+# return false. This function is useful to avoid pitfalls like:
+# if ($message) { print "$message\n"; }
+# which wouldn't print anything if $message is the literal "0".
+sub is_null_string ($)
+{
+ my $str = shift;
+ return ! (defined $str and length $str);
+}
+
+sub stringify_result_obj ($)
+{
+ my $result_obj = shift;
+ if ($result_obj->is_unplanned || $result_obj->number != $testno)
+ {
+ return "ERROR";
+ }
+ elsif ($plan_seen == LATE_PLAN)
+ {
+ return "ERROR";
+ }
+ elsif (!$result_obj->directive)
+ {
+ return $result_obj->is_ok ? "PASS" : "FAIL";
+ }
+ elsif ($result_obj->has_todo)
+ {
+ return $result_obj->is_actual_ok ? "XPASS" : "XFAIL";
+ }
+ elsif ($result_obj->has_skip)
+ {
+ return $result_obj->is_ok ? "SKIP" : "FAIL";
+ }
+ die "$ME: INTERNAL ERROR"; # NOTREACHED
+}
+
+sub colored ($$)
+{
+ my ($color_string, $text) = @_;
+ return $color_string . $text . RESET;
+}
+
+sub decorate_result ($)
+{
+ my $result = shift;
+ return $result unless $cfg{"color"};
+ my %color_for_result =
+ (
+ "ERROR" => BOLD.MAGENTA,
+ "PASS" => GREEN,
+ "XPASS" => BOLD.YELLOW,
+ "FAIL" => BOLD.RED,
+ "XFAIL" => YELLOW,
+ "SKIP" => BLUE,
+ );
+ if (my $color = $color_for_result{$result})
+ {
+ return colored ($color, $result);
+ }
+ else
+ {
+ return $result; # Don't colorize unknown stuff.
+ }
+}
+
+sub report ($;$)
+{
+ my ($msg, $result, $explanation) = (undef, @_);
+ if ($result =~ /^(?:X?(?:PASS|FAIL)|SKIP|ERROR)/)
+ {
+ # Output on console might be colorized.
+ $msg = decorate_result($result);
+ if ($result =~ /^(?:PASS|XFAIL|SKIP)/)
+ {
+ return if $cfg{"show-failures-only"};
+ }
+ else
+ {
+ $failed = 1;
+ }
+ }
+ elsif ($result eq "#")
+ {
+ $msg = " ";
+ }
+ else
+ {
+ die "$ME: INTERNAL ERROR"; # NOTREACHED
+ }
+ $msg .= " $explanation" if defined $explanation;
+ print $msg . "\n";
+}
+
+sub testsuite_error ($)
+{
+ report "ERROR", "- $_[0]";
+}
+
+sub handle_tap_result ($)
+{
+ $testno++;
+ my $result_obj = shift;
+
+ my $test_result = stringify_result_obj $result_obj;
+ my $string = $result_obj->number;
+
+ my $description = $result_obj->description;
+ $string .= " $test_name" unless is_null_string $test_name;
+ $string .= " $description" unless is_null_string $description;
+
+ if ($plan_seen == LATE_PLAN)
+ {
+ $string .= " # AFTER LATE PLAN";
+ }
+ elsif ($result_obj->is_unplanned)
+ {
+ $string .= " # UNPLANNED";
+ }
+ elsif ($result_obj->number != $testno)
+ {
+ $string .= " # OUT-OF-ORDER (expecting $testno)";
+ }
+ elsif (my $directive = $result_obj->directive)
+ {
+ $string .= " # $directive";
+ my $explanation = $result_obj->explanation;
+ $string .= " $explanation"
+ unless is_null_string $explanation;
+ }
+
+ report $test_result, $string;
+}
+
+sub handle_tap_plan ($)
+{
+ my $plan = shift;
+ if ($plan_seen)
+ {
+ # Error, only one plan per stream is acceptable.
+ testsuite_error "multiple test plans";
+ return;
+ }
+ # The TAP plan can come before or after *all* the TAP results; we speak
+ # respectively of an "early" or a "late" plan. If we see the plan line
+ # after at least one TAP result has been seen, assume we have a late
+ # plan; in this case, any further test result seen after the plan will
+ # be flagged as an error.
+ $plan_seen = ($testno >= 1 ? LATE_PLAN : EARLY_PLAN);
+ # If $testno > 0, we have an error ("too many tests run") that will be
+ # automatically dealt with later, so don't worry about it here. If
+ # $plan_seen is true, we have an error due to a repeated plan, and that
+ # has already been dealt with above. Otherwise, we have a valid "plan
+ # with SKIP" specification, and should report it as a particular kind
+ # of SKIP result.
+ if ($plan->directive && $testno == 0)
+ {
+ my $explanation = is_null_string ($plan->explanation) ?
+ undef : "- " . $plan->explanation;
+ report "SKIP", $explanation;
+ }
+}
+
+sub handle_tap_bailout ($)
+{
+ my ($bailout, $msg) = ($_[0], "Bail out!");
+ $bailed_out = 1;
+ $msg .= " " . $bailout->explanation
+ unless is_null_string $bailout->explanation;
+ testsuite_error $msg;
+}
+
+sub extract_tap_comment ($)
+{
+ my $line = shift;
+ if (index ($line, DIAG_STRING) == 0)
+ {
+ # Strip leading `DIAG_STRING' from `$line'.
+ $line = substr ($line, length (DIAG_STRING));
+ # And strip any leading and trailing whitespace left.
+ $line =~ s/(?:^\s*|\s*$)//g;
+ # Return what is left (if any).
+ return $line;
+ }
+ return "";
+}
+
+sub main ()
+{
+ my $iterator = TAP::Parser::Iterator::Stream->new(\*STDIN);
+ my $parser = TAP::Parser->new ({iterator => $iterator });
+
+ while (defined (my $cur = $parser->next))
+ {
+ # Parsing of TAP input should stop after a "Bail out!" directive.
+ next if $bailed_out;
+
+ if ($cur->is_plan)
+ {
+ handle_tap_plan ($cur);
+ }
+ elsif ($cur->is_test)
+ {
+ handle_tap_result ($cur);
+ }
+ elsif ($cur->is_bailout)
+ {
+ handle_tap_bailout ($cur);
+ }
+ elsif ($cfg{"verbose"})
+ {
+ my $comment = extract_tap_comment ($cur->raw);
+ report "#", "$comment" if length $comment;
+ }
+ }
+ # A "Bail out!" directive should cause us to ignore any following TAP
+ # error.
+ if (!$bailed_out)
+ {
+ if (!$plan_seen)
+ {
+ testsuite_error "missing test plan";
+ }
+ elsif ($parser->tests_planned != $parser->tests_run)
+ {
+ my ($planned, $run) = ($parser->tests_planned, $parser->tests_run);
+ my $bad_amount = $run > $planned ? "many" : "few";
+ testsuite_error (sprintf "too %s tests run (expected %d, got %d)",
+ $bad_amount, $planned, $run);
+ }
+ }
+}
+
+# ----------- #
+# Main code. #
+# ----------- #
+
+main;
+exit($failed);
+
+# Local Variables:
+# perl-indent-level: 2
+# perl-continued-statement-offset: 2
+# perl-continued-brace-offset: 0
+# perl-brace-offset: 0
+# perl-brace-imaginary-offset: 0
+# perl-label-offset: -2
+# cperl-indent-level: 2
+# cperl-brace-offset: 0
+# cperl-continued-brace-offset: 0
+# cperl-label-offset: -2
+# cperl-extra-newline-before-brace: t
+# cperl-merge-trailing-else: nil
+# cperl-continued-statement-offset: 2
+# End:
diff --git a/scripts/tap-merge.pl b/scripts/tap-merge.pl
new file mode 100755
index 0000000000..59e3fa5007
--- /dev/null
+++ b/scripts/tap-merge.pl
@@ -0,0 +1,110 @@
+#! /usr/bin/env perl
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini <pbonzini@redhat.com>
+#
+# 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; either version 2, or (at your option)
+# any later version.
+#
+# This program 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 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 <https://www.gnu.org/licenses/>.
+
+# ---------------------------------- #
+# Imports, static data, and setup. #
+# ---------------------------------- #
+
+use warnings FATAL => 'all';
+use strict;
+use Getopt::Long ();
+use TAP::Parser;
+
+my $ME = "tap-merge.pl";
+my $VERSION = "2018-11-30";
+
+my $HELP = "$ME: merge multiple TAP inputs from stdin.";
+
+use constant DIAG_STRING => "#";
+
+# ----------------- #
+# Option parsing. #
+# ----------------- #
+
+Getopt::Long::GetOptions
+ (
+ 'help' => sub { print $HELP; exit 0; },
+ 'version' => sub { print "$ME $VERSION\n"; exit 0; },
+ );
+
+# -------------- #
+# Subroutines. #
+# -------------- #
+
+sub main ()
+{
+ my $iterator = TAP::Parser::Iterator::Stream->new(\*STDIN);
+ my $parser = TAP::Parser->new ({iterator => $iterator });
+ my $testno = 0; # Number of test results seen so far.
+ my $bailed_out = 0; # Whether a "Bail out!" directive has been seen.
+
+ while (defined (my $cur = $parser->next))
+ {
+ if ($cur->is_bailout)
+ {
+ $bailed_out = 1;
+ print DIAG_STRING . " " . $cur->as_string . "\n";
+ next;
+ }
+ elsif ($cur->is_plan)
+ {
+ $bailed_out = 0;
+ next;
+ }
+ elsif ($cur->is_test)
+ {
+ $bailed_out = 0 if $cur->number == 1;
+ $testno++;
+ $cur = TAP::Parser::Result::Test->new({
+ ok => $cur->ok,
+ test_num => $testno,
+ directive => $cur->directive,
+ explanation => $cur->explanation,
+ description => $cur->description
+ });
+ }
+ elsif ($cur->is_version)
+ {
+ next if $testno > 0;
+ }
+ print $cur->as_string . "\n" unless $bailed_out;
+ }
+ print "1..$testno\n";
+}
+
+# ----------- #
+# Main code. #
+# ----------- #
+
+main;
+
+# Local Variables:
+# perl-indent-level: 2
+# perl-continued-statement-offset: 2
+# perl-continued-brace-offset: 0
+# perl-brace-offset: 0
+# perl-brace-imaginary-offset: 0
+# perl-label-offset: -2
+# cperl-indent-level: 2
+# cperl-brace-offset: 0
+# cperl-continued-brace-offset: 0
+# cperl-label-offset: -2
+# cperl-extra-newline-before-brace: t
+# cperl-merge-trailing-else: nil
+# cperl-continued-statement-offset: 2
+# End:
diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 39ce584a32..839b7917cf 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -398,7 +398,7 @@ $sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
- BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
+ BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) {
if(exists $sects{$sect}) {
$head = $sect;
$head =~ s/SEEALSO/SEE ALSO/;
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index fe2b0771f2..3beaa66bd8 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -15,8 +15,6 @@ __email__ = "stefanha@linux.vnet.ibm.com"
import sys
import getopt
-import os.path
-import re
from tracetool import error_write, out
import tracetool.backend
diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py
index 6751f41bc5..33c95af8e9 100644
--- a/scripts/tracetool/backend/log.py
+++ b/scripts/tracetool/backend/log.py
@@ -39,7 +39,7 @@ def generate_h(event, group):
' struct timeval _now;',
' gettimeofday(&_now, NULL);',
' qemu_log("%%d@%%zu.%%06zu:%(name)s " %(fmt)s "\\n",',
- ' getpid(),',
+ ' qemu_get_thread_id(),',
' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
' %(argnames)s);',
' }',
diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py
index e7e44842ca..57b04061cf 100644
--- a/scripts/tracetool/format/simpletrace_stap.py
+++ b/scripts/tracetool/format/simpletrace_stap.py
@@ -14,7 +14,7 @@ __email__ = "stefanha@redhat.com"
from tracetool import out
-from tracetool.backend.dtrace import binary, probeprefix
+from tracetool.backend.dtrace import probeprefix
from tracetool.backend.simple import is_string
from tracetool.format.stap import stap_escape
diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c
index 2a8f300dde..d9f4e8c3ad 100644
--- a/scsi/pr-manager.c
+++ b/scsi/pr-manager.c
@@ -48,24 +48,21 @@ static int pr_manager_worker(void *opaque)
}
-BlockAIOCB *pr_manager_execute(PRManager *pr_mgr,
- AioContext *ctx, int fd,
- struct sg_io_hdr *hdr,
- BlockCompletionFunc *complete,
- void *opaque)
+int coroutine_fn pr_manager_execute(PRManager *pr_mgr, AioContext *ctx, int fd,
+ struct sg_io_hdr *hdr)
{
- PRManagerData *data = g_new(PRManagerData, 1);
ThreadPool *pool = aio_get_thread_pool(ctx);
+ PRManagerData data = {
+ .pr_mgr = pr_mgr,
+ .fd = fd,
+ .hdr = hdr,
+ };
- trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1], opaque);
- data->pr_mgr = pr_mgr;
- data->fd = fd;
- data->hdr = hdr;
+ trace_pr_manager_execute(fd, hdr->cmdp[0], hdr->cmdp[1]);
/* The matching object_unref is in pr_manager_worker. */
object_ref(OBJECT(pr_mgr));
- return thread_pool_submit_aio(pool, pr_manager_worker,
- data, complete, opaque);
+ return thread_pool_submit_co(pool, pr_manager_worker, &data);
}
bool pr_manager_is_connected(PRManager *pr_mgr)
diff --git a/scsi/trace-events b/scsi/trace-events
index 45f5b6e49b..f8a68b11eb 100644
--- a/scsi/trace-events
+++ b/scsi/trace-events
@@ -1,3 +1,3 @@
# scsi/pr-manager.c
-pr_manager_execute(int fd, int cmd, int sa, void *opaque) "fd=%d cmd=0x%02x service action=0x%02x opaque=%p"
+pr_manager_execute(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x"
pr_manager_run(int fd, int cmd, int sa) "fd=%d cmd=0x%02x service action=0x%02x"
diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 28049b03cd..959558c732 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,5 +1,32 @@
-common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o \
- ip_input.o ip_output.o dnssearch.o dhcpv6.o
-common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-common-obj-y += tcp_subr.o tcp_timer.o udp.o udp6.o bootp.o tftp.o arp_table.o \
- ndp_table.o ncsi.o
+slirp-obj-y = slirp.mo
+
+slirp.mo-objs = \
+ arp_table.o \
+ bootp.o \
+ cksum.o \
+ dhcpv6.o \
+ dnssearch.o \
+ if.o \
+ ip6_icmp.o \
+ ip6_input.o \
+ ip6_output.o \
+ ip_icmp.o \
+ ip_input.o \
+ ip_output.o \
+ mbuf.o \
+ misc.o \
+ ncsi.o \
+ ndp_table.o \
+ sbuf.o \
+ slirp.o \
+ socket.o \
+ tcp_input.o \
+ tcp_output.o \
+ tcp_subr.o \
+ tcp_timer.o \
+ tftp.o \
+ udp.o \
+ udp6.o \
+ $(NULL)
+
+slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\"
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index f81963bb88..bf71b984ad 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -34,9 +34,9 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
DEBUG_CALL("arp_table_add");
DEBUG_ARG("ip = %s", inet_ntoa((struct in_addr){.s_addr = ip_addr}));
- DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
- ethaddr[0], ethaddr[1], ethaddr[2],
- ethaddr[3], ethaddr[4], ethaddr[5]));
+ DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+ ethaddr[0], ethaddr[1], ethaddr[2],
+ ethaddr[3], ethaddr[4], ethaddr[5]);
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* Do not register broadcast addresses */
@@ -79,9 +79,9 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
- DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+ DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
}
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 7b1af73c95..4c9a77eb98 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -36,12 +36,7 @@
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) \
-do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## __VA_ARGS__); fflush(dfd); } while (0)
-#else
-#define DPRINTF(fmt, ...) do{}while(0)
-#endif
+#define DPRINTF(fmt, ...) DEBUG_CALL(fmt, ##__VA_ARGS__)
static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
@@ -167,8 +162,9 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
if (preq_addr.s_addr != htonl(0L))
DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
- else
+ else {
DPRINTF("\n");
+ }
if (dhcp_msg_type == 0)
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
diff --git a/slirp/cksum.c b/slirp/cksum.c
index 6d73abf4a0..84c858fafb 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -70,9 +70,7 @@ int cksum(struct mbuf *m, int len)
if (len < mlen)
mlen = len;
-#ifdef DEBUG
len -= mlen;
-#endif
/*
* Force to even boundary.
*/
@@ -122,12 +120,10 @@ int cksum(struct mbuf *m, int len)
s_util.c[0] = *(uint8_t *)w;
cont:
-#ifdef DEBUG
if (len) {
- DEBUG_ERROR((dfd, "cksum: out of data\n"));
- DEBUG_ERROR((dfd, " len = %d\n", len));
+ DEBUG_ERROR("cksum: out of data");
+ DEBUG_ERROR(" len = %d", len);
}
-#endif
if (mlen == -1) {
/* The last mbuf has odd # of bytes. Follow the
standard (the odd byte may be shifted left by 8 bits
diff --git a/slirp/debug.h b/slirp/debug.h
index 6cfa61edb3..269d97d807 100644
--- a/slirp/debug.h
+++ b/slirp/debug.h
@@ -5,30 +5,37 @@
* terms and conditions of the copyright.
*/
-//#define DEBUG 1
-
-#ifdef DEBUG
+#ifndef DEBUG_H_
+#define DEBUG_H_
#define DBG_CALL 0x1
#define DBG_MISC 0x2
#define DBG_ERROR 0x4
-#define dfd stderr
-
extern int slirp_debug;
-#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); }
-#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); }
-#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); }
-#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); }
-#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); }
-
-#else
-
-#define DEBUG_CALL(x)
-#define DEBUG_ARG(x, y)
-#define DEBUG_ARGS(x)
-#define DEBUG_MISC(x)
-#define DEBUG_ERROR(x)
-
-#endif
+#define DEBUG_CALL(fmt, ...) do { \
+ if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
+ g_debug(fmt "...", ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#define DEBUG_ARG(fmt, ...) do { \
+ if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
+ g_debug(" " fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#define DEBUG_MISC(fmt, ...) do { \
+ if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \
+ g_debug(fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#define DEBUG_ERROR(fmt, ...) do { \
+ if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \
+ g_debug(fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
+
+#endif /* DEBUG_H_ */
diff --git a/slirp/dhcpv6.c b/slirp/dhcpv6.c
index d266611e85..752df40536 100644
--- a/slirp/dhcpv6.c
+++ b/slirp/dhcpv6.c
@@ -50,7 +50,7 @@ struct requested_infos {
* the odata region, thus the caller must keep odata valid as long as it
* needs to access the requested_infos struct.
*/
-static int dhcpv6_parse_info_request(uint8_t *odata, int olen,
+static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
struct requested_infos *ri)
{
int i, req_opt;
@@ -61,7 +61,7 @@ static int dhcpv6_parse_info_request(uint8_t *odata, int olen,
int len = odata[2] << 8 | odata[3];
if (len + 4 > olen) {
- qemu_log_mask(LOG_GUEST_ERROR, "Guest sent bad DHCPv6 packet!\n");
+ slirp->cb->guest_error("Guest sent bad DHCPv6 packet!");
return -E2BIG;
}
@@ -92,14 +92,14 @@ static int dhcpv6_parse_info_request(uint8_t *odata, int olen,
ri->want_boot_url = true;
break;
default:
- DEBUG_MISC((dfd, "dhcpv6: Unsupported option request %d\n",
- req_opt));
+ DEBUG_MISC("dhcpv6: Unsupported option request %d",
+ req_opt);
}
}
break;
default:
- DEBUG_MISC((dfd, "dhcpv6 info req: Unsupported option %d, len=%d\n",
- option, len));
+ DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d",
+ option, len);
}
odata += len + 4;
@@ -121,7 +121,7 @@ static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
struct mbuf *m;
uint8_t *resp;
- if (dhcpv6_parse_info_request(odata, olen, &ri) < 0) {
+ if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
return;
}
@@ -203,7 +203,6 @@ void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
break;
default:
- DEBUG_MISC((dfd, "dhcpv6_input: Unsupported message type 0x%x\n",
- data[0]));
+ DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
}
}
diff --git a/slirp/if.c b/slirp/if.c
index 590753c658..73e3705740 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -131,12 +131,10 @@ diddit:
}
}
-#ifndef FULL_BOLT
/*
* This prevents us from malloc()ing too many mbufs
*/
if_start(ifm->slirp);
-#endif
}
/*
@@ -150,7 +148,7 @@ diddit:
*/
void if_start(Slirp *slirp)
{
- uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ uint64_t now = slirp->cb->clock_get_ns();
bool from_batchq = false;
struct mbuf *ifm, *ifm_next, *ifqt;
diff --git a/slirp/ip.h b/slirp/ip.h
index 59cf4aa918..243b6c8b24 100644
--- a/slirp/ip.h
+++ b/slirp/ip.h
@@ -33,7 +33,9 @@
#ifndef IP_H
#define IP_H
-#ifdef HOST_WORDS_BIGENDIAN
+#include <glib.h>
+
+#if G_BYTE_ORDER == G_BIG_ENDIAN
# undef NTOHL
# undef NTOHS
# undef HTONL
@@ -69,7 +71,7 @@ typedef uint32_t n_long; /* long as received from the net */
* Structure of an internet header, naked of options.
*/
struct ip {
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t ip_v:4, /* version */
ip_hl:4; /* header length */
#else
@@ -135,7 +137,7 @@ struct ip_timestamp {
uint8_t ipt_code; /* IPOPT_TS */
uint8_t ipt_len; /* size of structure (variable) */
uint8_t ipt_ptr; /* index of current entry */
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t ipt_oflw:4, /* overflow counter */
ipt_flg:4; /* flags, see below */
#else
@@ -175,7 +177,7 @@ struct ip_timestamp {
#define IP_MSS 576 /* default maximum segment size */
-#if SIZEOF_CHAR_P == 4
+#if GLIB_SIZEOF_VOID_P == 4
struct mbuf_ptr {
struct mbuf *mptr;
uint32_t dummy;
diff --git a/slirp/ip6.h b/slirp/ip6.h
index b1bea43b3c..14e9c78735 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -6,6 +6,7 @@
#ifndef SLIRP_IP6_H
#define SLIRP_IP6_H
+#include <glib.h>
#include "net/eth.h"
#define ALLNODES_MULTICAST { .s6_addr = \
@@ -113,7 +114,7 @@ static inline void in6_compute_ethaddr(struct in6_addr ip,
* Structure of an internet header, naked of options.
*/
struct ip6 {
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint32_t
ip_v:4, /* version */
ip_tc_hi:4, /* traffic class */
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index cd1e0b9fe1..5261baae27 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -17,7 +17,7 @@ static void ra_timer_handler(void *opaque)
{
Slirp *slirp = opaque;
timer_mod(slirp->ra_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+ slirp->cb->clock_get_ns() / SCALE_MS + NDP_Interval);
ndp_send_ra(slirp);
}
@@ -31,7 +31,7 @@ void icmp6_init(Slirp *slirp)
SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
ra_timer_handler, slirp);
timer_mod(slirp->ra_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+ slirp->cb->clock_get_ns() / SCALE_MS + NDP_Interval);
}
void icmp6_cleanup(Slirp *slirp)
@@ -74,9 +74,10 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
Slirp *slirp = m->slirp;
struct mbuf *t;
struct ip6 *ip = mtod(m, struct ip6 *);
+ char addrstr[INET6_ADDRSTRLEN];
DEBUG_CALL("icmp6_send_error");
- DEBUG_ARGS((dfd, " type = %d, code = %d\n", type, code));
+ DEBUG_ARG("type = %d, code = %d", type, code);
if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
in6_zero(&ip->ip_src)) {
@@ -90,11 +91,8 @@ void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
struct ip6 *rip = mtod(t, struct ip6 *);
rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
rip->ip_dst = ip->ip_src;
-#if !defined(_WIN32) || (_WIN32_WINNT >= 0x0600)
- char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
DEBUG_ARG("target = %s", addrstr);
-#endif
rip->ip_nh = IPPROTO_ICMPV6;
const int error_data_len = MIN(m->m_len,
@@ -222,12 +220,12 @@ void ndp_send_ra(Slirp *slirp)
*/
void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
{
- DEBUG_CALL("ndp_send_ns");
-#if !defined(_WIN32) || (_WIN32_WINNT >= 0x0600)
char addrstr[INET6_ADDRSTRLEN];
+
inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
+
+ DEBUG_CALL("ndp_send_ns");
DEBUG_ARG("target = %s", addrstr);
-#endif
/* Build IPv6 packet */
struct mbuf *t = m_get(slirp);
@@ -342,8 +340,7 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
case ICMP6_NDP_RA:
DEBUG_CALL(" type = Router Advertisement");
- qemu_log_mask(LOG_GUEST_ERROR,
- "Warning: guest sent NDP RA, but shouldn't");
+ slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't");
break;
case ICMP6_NDP_NS:
@@ -376,8 +373,8 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
case ICMP6_NDP_REDIRECT:
DEBUG_CALL(" type = Redirect");
- qemu_log_mask(LOG_GUEST_ERROR,
- "Warning: guest sent NDP REDIRECT, but shouldn't");
+ slirp->cb->guest_error(
+ "Warning: guest sent NDP REDIRECT, but shouldn't");
break;
}
}
@@ -393,7 +390,7 @@ void icmp6_input(struct mbuf *m)
int hlen = sizeof(struct ip6);
DEBUG_CALL("icmp6_input");
- DEBUG_ARG("m = %lx", (long) m);
+ DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len);
if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
@@ -417,7 +414,7 @@ void icmp6_input(struct mbuf *m)
icmp6_send_echoreply(m, slirp, ip, icmp);
} else {
/* TODO */
- error_report("external icmpv6 not supported yet");
+ g_critical("external icmpv6 not supported yet");
}
break;
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
index b3378b17b5..32b0914055 100644
--- a/slirp/ip6_icmp.h
+++ b/slirp/ip6_icmp.h
@@ -34,7 +34,7 @@ struct ndp_rs { /* Router Solicitation Message */
struct ndp_ra { /* Router Advertisement Message */
uint8_t chl; /* Cur Hop Limit */
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t
M:1,
O:1,
@@ -56,7 +56,7 @@ struct ndp_ns { /* Neighbor Solicitation Message */
} QEMU_PACKED;
struct ndp_na { /* Neighbor Advertisement Message */
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint32_t
R:1, /* Router Flag */
S:1, /* Solicited Flag */
@@ -125,7 +125,7 @@ struct ndpopt {
#define ndpopt_linklayer ndpopt_body.linklayer_addr
struct prefixinfo { /* Prefix Information */
uint8_t prefix_length;
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t L:1, A:1, reserved1:6;
#else
uint8_t reserved1:6, A:1, L:1;
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index ac2e3ea882..ab656a0a9d 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -31,7 +31,7 @@ void ip6_input(struct mbuf *m)
}
DEBUG_CALL("ip6_input");
- DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len);
if (m->m_len < sizeof(struct ip6)) {
diff --git a/slirp/ip6_output.c b/slirp/ip6_output.c
index 762cbfe89c..52c88ad691 100644
--- a/slirp/ip6_output.c
+++ b/slirp/ip6_output.c
@@ -19,8 +19,8 @@ int ip6_output(struct socket *so, struct mbuf *m, int fast)
struct ip6 *ip = mtod(m, struct ip6 *);
DEBUG_CALL("ip6_output");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("so = %p", so);
+ DEBUG_ARG("m = %p", m);
/* Fill IPv6 header */
ip->ip_v = IP6VERSION;
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 9210eef3f3..7c7e042049 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -34,6 +34,10 @@
#include "slirp.h"
#include "ip_icmp.h"
+#ifndef WITH_ICMP_ERROR_MSG
+#define WITH_ICMP_ERROR_MSG 0
+#endif
+
/* The message sent when emulating PING */
/* Be nice and tell them it's just a pseudo-ping packet */
static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
@@ -99,8 +103,8 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
if (sendto(so->s, m->m_data + hlen, m->m_len - hlen, 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
- DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
- errno, strerror(errno)));
+ DEBUG_MISC("icmp_input icmp sendto tx errno = %d-%s",
+ errno, strerror(errno));
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
icmp_detach(so);
}
@@ -165,8 +169,8 @@ icmp_input(struct mbuf *m, int hlen)
return;
}
if (udp_attach(so, AF_INET) == -1) {
- DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
- errno,strerror(errno)));
+ DEBUG_MISC("icmp_input udp_attach errno = %d-%s",
+ errno,strerror(errno));
sofree(so);
m_free(m);
goto end_error;
@@ -188,8 +192,8 @@ icmp_input(struct mbuf *m, int hlen)
if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
(struct sockaddr *)&addr, sockaddr_size(&addr)) == -1) {
- DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
- errno,strerror(errno)));
+ DEBUG_MISC("icmp_input udp sendto tx errno = %d-%s",
+ errno,strerror(errno));
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
udp_detach(so);
}
@@ -253,13 +257,12 @@ icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
/* check msrc */
if(!msrc) goto end_error;
ip = mtod(msrc, struct ip *);
-#ifdef DEBUG
- { char bufa[20], bufb[20];
+ if (slirp_debug & DBG_MISC) {
+ char bufa[20], bufb[20];
strcpy(bufa, inet_ntoa(ip->ip_src));
strcpy(bufb, inet_ntoa(ip->ip_dst));
- DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb));
+ DEBUG_MISC(" %.16s to %.16s", bufa, bufb);
}
-#endif
if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */
/* Do not reply to source-only IPs */
@@ -319,8 +322,7 @@ icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
HTONS(icp->icmp_ip.ip_id);
HTONS(icp->icmp_ip.ip_off);
-#ifdef DEBUG
- if(message) { /* DEBUG : append message to ICMP packet */
+ if (message && WITH_ICMP_ERROR_MSG) { /* append message to ICMP packet */
int message_len;
char *cpnt;
message_len=strlen(message);
@@ -329,7 +331,6 @@ icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
memcpy(cpnt, message, message_len);
m->m_len+=message_len;
}
-#endif
icp->icmp_cksum = 0;
icp->icmp_cksum = cksum(m, m->m_len);
@@ -457,8 +458,8 @@ void icmp_receive(struct socket *so)
} else {
error_code = ICMP_UNREACH_HOST;
}
- DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
- strerror(errno)));
+ DEBUG_MISC(" udp icmp rx errno = %d-%s", errno,
+ strerror(errno));
icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
} else {
icmp_reflect(so->so_m);
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 348e1dca5a..d360620838 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -193,7 +193,7 @@ ip_input(struct mbuf *m)
m = dtom(slirp, ip);
} else
if (fp)
- ip_freef(slirp, fp);
+ ip_freef(slirp, fp);
} else
ip->ip_len -= hlen;
@@ -448,206 +448,6 @@ ip_slowtimo(Slirp *slirp)
}
/*
- * Do option processing on a datagram,
- * possibly discarding it if bad options are encountered,
- * or forwarding it if source-routed.
- * Returns 1 if packet has been forwarded/freed,
- * 0 if the packet should be processed further.
- */
-
-#ifdef notdef
-
-int
-ip_dooptions(m)
- struct mbuf *m;
-{
- register struct ip *ip = mtod(m, struct ip *);
- register u_char *cp;
- register struct ip_timestamp *ipt;
- register struct in_ifaddr *ia;
- int opt, optlen, cnt, off, code, type, forward = 0;
- struct in_addr *sin, dst;
-typedef uint32_t n_time;
- n_time ntime;
-
- dst = ip->ip_dst;
- cp = (u_char *)(ip + 1);
- cnt = (ip->ip_hl << 2) - sizeof (struct ip);
- for (; cnt > 0; cnt -= optlen, cp += optlen) {
- opt = cp[IPOPT_OPTVAL];
- if (opt == IPOPT_EOL)
- break;
- if (opt == IPOPT_NOP)
- optlen = 1;
- else {
- optlen = cp[IPOPT_OLEN];
- if (optlen <= 0 || optlen > cnt) {
- code = &cp[IPOPT_OLEN] - (u_char *)ip;
- goto bad;
- }
- }
- switch (opt) {
-
- default:
- break;
-
- /*
- * Source routing with record.
- * Find interface with current destination address.
- * If none on this machine then drop if strictly routed,
- * or do nothing if loosely routed.
- * Record interface address and bring up next address
- * component. If strictly routed make sure next
- * address is on directly accessible net.
- */
- case IPOPT_LSRR:
- case IPOPT_SSRR:
- if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
- code = &cp[IPOPT_OFFSET] - (u_char *)ip;
- goto bad;
- }
- ipaddr.sin_addr = ip->ip_dst;
- ia = (struct in_ifaddr *)
- ifa_ifwithaddr((struct sockaddr *)&ipaddr);
- if (ia == 0) {
- if (opt == IPOPT_SSRR) {
- type = ICMP_UNREACH;
- code = ICMP_UNREACH_SRCFAIL;
- goto bad;
- }
- /*
- * Loose routing, and not at next destination
- * yet; nothing to do except forward.
- */
- break;
- }
- off--; /* 0 origin */
- if (off > optlen - sizeof(struct in_addr)) {
- /*
- * End of source route. Should be for us.
- */
- save_rte(cp, ip->ip_src);
- break;
- }
- /*
- * locate outgoing interface
- */
- bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
- sizeof(ipaddr.sin_addr));
- if (opt == IPOPT_SSRR) {
-#define INA struct in_ifaddr *
-#define SA struct sockaddr *
- if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
- ia = (INA)ifa_ifwithnet((SA)&ipaddr);
- } else
- ia = ip_rtaddr(ipaddr.sin_addr);
- if (ia == 0) {
- type = ICMP_UNREACH;
- code = ICMP_UNREACH_SRCFAIL;
- goto bad;
- }
- ip->ip_dst = ipaddr.sin_addr;
- bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
- (caddr_t)(cp + off), sizeof(struct in_addr));
- cp[IPOPT_OFFSET] += sizeof(struct in_addr);
- /*
- * Let ip_intr's mcast routing check handle mcast pkts
- */
- forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
- break;
-
- case IPOPT_RR:
- if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
- code = &cp[IPOPT_OFFSET] - (u_char *)ip;
- goto bad;
- }
- /*
- * If no space remains, ignore.
- */
- off--; /* 0 origin */
- if (off > optlen - sizeof(struct in_addr))
- break;
- bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
- sizeof(ipaddr.sin_addr));
- /*
- * locate outgoing interface; if we're the destination,
- * use the incoming interface (should be same).
- */
- if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
- (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
- type = ICMP_UNREACH;
- code = ICMP_UNREACH_HOST;
- goto bad;
- }
- bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
- (caddr_t)(cp + off), sizeof(struct in_addr));
- cp[IPOPT_OFFSET] += sizeof(struct in_addr);
- break;
-
- case IPOPT_TS:
- code = cp - (u_char *)ip;
- ipt = (struct ip_timestamp *)cp;
- if (ipt->ipt_len < 5)
- goto bad;
- if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) {
- if (++ipt->ipt_oflw == 0)
- goto bad;
- break;
- }
- sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
- switch (ipt->ipt_flg) {
-
- case IPOPT_TS_TSONLY:
- break;
-
- case IPOPT_TS_TSANDADDR:
- if (ipt->ipt_ptr + sizeof(n_time) +
- sizeof(struct in_addr) > ipt->ipt_len)
- goto bad;
- ipaddr.sin_addr = dst;
- ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr,
- m->m_pkthdr.rcvif);
- if (ia == 0)
- continue;
- bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
- (caddr_t)sin, sizeof(struct in_addr));
- ipt->ipt_ptr += sizeof(struct in_addr);
- break;
-
- case IPOPT_TS_PRESPEC:
- if (ipt->ipt_ptr + sizeof(n_time) +
- sizeof(struct in_addr) > ipt->ipt_len)
- goto bad;
- bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
- sizeof(struct in_addr));
- if (ifa_ifwithaddr((SA)&ipaddr) == 0)
- continue;
- ipt->ipt_ptr += sizeof(struct in_addr);
- break;
-
- default:
- goto bad;
- }
- ntime = iptime();
- bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
- sizeof(n_time));
- ipt->ipt_ptr += sizeof(n_time);
- }
- }
- if (forward) {
- ip_forward(m, 1);
- return (1);
- }
- return (0);
-bad:
- icmp_send_error(m, type, code, 0, 0);
-
- return (1);
-}
-
-#endif /* notdef */
-
-/*
* Strip out IP options, at higher
* level protocol in the kernel.
* Second argument is buffer to which options
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 42e42e9a2a..4611a7447b 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -5,8 +5,20 @@
typedef struct Slirp Slirp;
-int get_dns_addr(struct in_addr *pdns_addr);
-int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
+/*
+ * Callbacks from slirp
+ *
+ * The opaque parameter comes from the opaque parameter given to slirp_init().
+ */
+typedef struct SlirpCb {
+ /* Send an ethernet frame to the guest network. */
+ void (*output)(void *opaque, const uint8_t *pkt, int pkt_len);
+ /* Print a message for an error due to guest misbehavior. */
+ void (*guest_error)(const char *msg);
+ /* Return the virtual clock value in nanoseconds */
+ int64_t (*clock_get_ns)(void);
+} SlirpCb;
+
Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost,
@@ -17,7 +29,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
- const char *vdomainname, void *opaque);
+ const char *vdomainname,
+ const SlirpCb *callbacks,
+ void *opaque);
void slirp_cleanup(Slirp *slirp);
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
@@ -26,18 +40,15 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error);
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
-/* you must provide the following functions: */
-void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len);
-
int slirp_add_hostfwd(Slirp *slirp, int is_udp,
struct in_addr host_addr, int host_port,
struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
struct in_addr host_addr, int host_port);
-int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
+int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
-void slirp_connection_info(Slirp *slirp, Monitor *mon);
+char *slirp_connection_info(Slirp *slirp);
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port, const uint8_t *buf, int size);
diff --git a/slirp/main.h b/slirp/main.h
index 90053ce5ec..4bc05fb904 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -8,42 +8,9 @@
#ifndef SLIRP_MAIN_H
#define SLIRP_MAIN_H
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#define TOWRITEMAX 512
-
-extern int slirp_socket;
-extern int slirp_socket_unit;
-extern int slirp_socket_port;
-extern uint32_t slirp_socket_addr;
-extern char *slirp_socket_passwd;
-extern int ctty_closed;
-
-/*
- * Get the difference in 2 times from updtim()
- * Allow for wraparound times, "just in case"
- * x is the greater of the 2 (current time) and y is
- * what it's being compared against.
- */
-#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
-
-extern char *slirp_tty;
-extern char *exec_shell;
extern u_int curtime;
extern struct in_addr loopback_addr;
extern unsigned long loopback_mask;
-extern char *username;
-extern char *socket_path;
-extern int towrite_max;
-extern int ppp_exit;
-extern int tcp_keepintvl;
-
-#define PROTO_SLIP 0x1
-#ifdef USE_PPP
-#define PROTO_PPP 0x2
-#endif
int if_encap(Slirp *slirp, struct mbuf *ifm);
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags);
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index aa1f28afb1..d8d275e0e7 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -232,7 +232,7 @@ dtom(Slirp *slirp, void *dat)
}
}
- DEBUG_ERROR((dfd, "dtom failed"));
+ DEBUG_ERROR("dtom failed");
return (struct mbuf *)0;
}
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index bfdf8c4577..cbf17e136b 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -72,7 +72,6 @@
* How much free room there is
*/
#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
-#define M_TRAILINGSPACE M_FREEROOM
struct mbuf {
/* XXX should union some of these! */
diff --git a/slirp/misc.c b/slirp/misc.c
index 57bdd808e2..eae9596a55 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -8,14 +8,9 @@
#include "qemu/osdep.h"
#include "slirp.h"
#include "libslirp.h"
-#include "monitor/monitor.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
-#ifdef DEBUG
-int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
-#endif
-
inline void
insque(void *a, void *b)
{
@@ -37,189 +32,135 @@ remque(void *a)
element->qh_rlink = NULL;
}
-int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
+int add_exec(struct gfwd_list **ex_ptr, void *chardev, const char *cmdline,
struct in_addr addr, int port)
{
- struct ex_list *tmp_ptr;
-
- /* First, check if the port is "bound" */
- for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
- if (port == tmp_ptr->ex_fport &&
- addr.s_addr == tmp_ptr->ex_addr.s_addr)
- return -1;
- }
+ struct gfwd_list *tmp_ptr;
tmp_ptr = *ex_ptr;
- *ex_ptr = g_new(struct ex_list, 1);
+ *ex_ptr = g_new0(struct gfwd_list, 1);
(*ex_ptr)->ex_fport = port;
(*ex_ptr)->ex_addr = addr;
- (*ex_ptr)->ex_pty = do_pty;
- (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : g_strdup(exec);
+ if (chardev) {
+ (*ex_ptr)->ex_chardev = chardev;
+ } else {
+ (*ex_ptr)->ex_exec = g_strdup(cmdline);
+ }
(*ex_ptr)->ex_next = tmp_ptr;
return 0;
}
-#ifdef _WIN32
-
-int
-fork_exec(struct socket *so, const char *ex, int do_pty)
+static int
+slirp_socketpair_with_oob(int sv[2])
{
- /* not implemented */
- return 0;
-}
-
-#else
-
-/*
- * XXX This is ugly
- * We create and bind a socket, then fork off to another
- * process, which connects to this socket, after which we
- * exec the wanted program. If something (strange) happens,
- * the accept() call could block us forever.
- *
- * do_pty = 0 Fork/exec inetd style
- * do_pty = 1 Fork/exec using slirp.telnetd
- * do_ptr = 2 Fork/exec using pty
- */
-int
-fork_exec(struct socket *so, const char *ex, int do_pty)
-{
- int s, cs;
- struct sockaddr_in addr, csaddr;
- socklen_t addrlen = sizeof(addr);
- socklen_t csaddrlen = sizeof(csaddr);
- int opt;
- const char *argv[256];
- /* don't want to clobber the original */
- char *bptr;
- const char *curarg;
- int c, i, ret;
- pid_t pid;
-
- DEBUG_CALL("fork_exec");
- DEBUG_ARG("so = %p", so);
- DEBUG_ARG("ex = %p", ex);
- DEBUG_ARG("do_pty = %x", do_pty);
-
- if (do_pty == 2) {
- return 0;
- } else {
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
- bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
- listen(s, 1) < 0) {
- error_report("Error: inet socket: %s", strerror(errno));
- if (s >= 0) {
- closesocket(s);
- }
-
- return 0;
- }
- }
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+ socklen_t addrlen = sizeof(addr);
+ int ret, s;
+
+ sv[1] = -1;
+ s = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
+ listen(s, 1) < 0 ||
+ getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
+ goto err;
+ }
- if (getsockname(s, (struct sockaddr *)&csaddr, &csaddrlen) < 0) {
- closesocket(s);
- return 0;
- }
- cs = qemu_socket(AF_INET, SOCK_STREAM, 0);
- if (cs < 0) {
- closesocket(s);
- return 0;
- }
- csaddr.sin_addr = loopback_addr;
- /*
- * This connect won't block because we've already listen()ed on
- * the server end (even though we won't accept() the connection
- * until later on).
- */
- do {
- ret = connect(cs, (struct sockaddr *)&csaddr, csaddrlen);
- } while (ret < 0 && errno == EINTR);
- if (ret < 0) {
- closesocket(s);
- closesocket(cs);
- return 0;
- }
+ sv[1] = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ if (sv[1] < 0) {
+ goto err;
+ }
+ /*
+ * This connect won't block because we've already listen()ed on
+ * the server end (even though we won't accept() the connection
+ * until later on).
+ */
+ do {
+ ret = connect(sv[1], (struct sockaddr *)&addr, addrlen);
+ } while (ret < 0 && errno == EINTR);
+ if (ret < 0) {
+ goto err;
+ }
- pid = fork();
- switch(pid) {
- case -1:
- error_report("Error: fork failed: %s", strerror(errno));
- closesocket(cs);
- close(s);
- return 0;
+ do {
+ sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen);
+ } while (sv[0] < 0 && errno == EINTR);
+ if (sv[0] < 0) {
+ goto err;
+ }
- case 0:
- setsid();
+ closesocket(s);
+ return 0;
- /* Set the DISPLAY */
- close(s);
- dup2(cs, 0);
- dup2(cs, 1);
- dup2(cs, 2);
- for (s = getdtablesize() - 1; s >= 3; s--)
- close(s);
+err:
+ g_critical("slirp_socketpair(): %s", strerror(errno));
+ if (s >= 0) {
+ closesocket(s);
+ }
+ if (sv[1] >= 0) {
+ closesocket(sv[1]);
+ }
+ return -1;
+}
- i = 0;
- bptr = g_strdup(ex); /* No need to free() this */
- if (do_pty == 1) {
- /* Setup "slirp.telnetd -x" */
- argv[i++] = "slirp.telnetd";
- argv[i++] = "-x";
- argv[i++] = bptr;
- } else
- do {
- /* Change the string into argv[] */
- curarg = bptr;
- while (*bptr != ' ' && *bptr != (char)0)
- bptr++;
- c = *bptr;
- *bptr++ = (char)0;
- argv[i++] = g_strdup(curarg);
- } while (c);
+static void
+fork_exec_child_setup(gpointer data)
+{
+#ifndef _WIN32
+ setsid();
+#endif
+}
- argv[i] = NULL;
- execvp(argv[0], (char **)argv);
+int
+fork_exec(struct socket *so, const char *ex)
+{
+ GError *err = NULL;
+ char **argv;
+ int opt, sp[2];
- /* Ooops, failed, let's tell the user why */
- fprintf(stderr, "Error: execvp of %s failed: %s\n",
- argv[0], strerror(errno));
- close(0); close(1); close(2); /* XXX */
- exit(1);
+ DEBUG_CALL("fork_exec");
+ DEBUG_ARG("so = %p", so);
+ DEBUG_ARG("ex = %p", ex);
- default:
- qemu_add_child_watch(pid);
- closesocket(cs);
- /*
- * This should never block, because we already connect()ed
- * on the child end before we forked.
- */
- do {
- so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
- } while (so->s < 0 && errno == EINTR);
- closesocket(s);
- socket_set_fast_reuse(so->s);
- opt = 1;
- qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- qemu_set_nonblock(so->s);
+ if (slirp_socketpair_with_oob(sp) < 0) {
+ return 0;
+ }
- /* Append the telnet options now */
- if (so->so_m != NULL && do_pty == 1) {
- sbappend(so, so->so_m);
- so->so_m = NULL;
- }
+ argv = g_strsplit(ex, " ", -1);
+ g_spawn_async_with_fds(NULL /* cwd */,
+ argv,
+ NULL /* env */,
+ G_SPAWN_SEARCH_PATH,
+ fork_exec_child_setup, NULL /* data */,
+ NULL /* child_pid */,
+ sp[1], sp[1], sp[1],
+ &err);
+ g_strfreev(argv);
+
+ if (err) {
+ g_critical("fork_exec: %s", err->message);
+ g_error_free(err);
+ closesocket(sp[0]);
+ closesocket(sp[1]);
+ return 0;
+ }
- return 1;
- }
+ so->s = sp[0];
+ closesocket(sp[1]);
+ socket_set_fast_reuse(so->s);
+ opt = 1;
+ qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ qemu_set_nonblock(so->s);
+ return 1;
}
-#endif
-void slirp_connection_info(Slirp *slirp, Monitor *mon)
+char *slirp_connection_info(Slirp *slirp)
{
+ GString *str = g_string_new(NULL);
const char * const tcpstates[] = {
[TCPS_CLOSED] = "CLOSED",
[TCPS_LISTEN] = "LISTEN",
@@ -241,8 +182,9 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
const char *state;
char buf[20];
- monitor_printf(mon, " Protocol[State] FD Source Address Port "
- "Dest. Address Port RecvQ SendQ\n");
+ g_string_append_printf(str,
+ " Protocol[State] FD Source Address Port "
+ "Dest. Address Port RecvQ SendQ\n");
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
if (so->so_state & SS_HOSTFWD) {
@@ -264,10 +206,10 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
dst_port = so->so_fport;
}
snprintf(buf, sizeof(buf), " TCP[%s]", state);
- monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s,
+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
ntohs(src.sin_port));
- monitor_printf(mon, "%15s %5d %5d %5d\n",
+ g_string_append_printf(str, "%15s %5d %5d %5d\n",
inet_ntoa(dst_addr), ntohs(dst_port),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
@@ -287,10 +229,10 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
dst_addr = so->so_faddr;
dst_port = so->so_fport;
}
- monitor_printf(mon, "%-19s %3d %15s %5d ", buf, so->s,
+ g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s,
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
ntohs(src.sin_port));
- monitor_printf(mon, "%15s %5d %5d %5d\n",
+ g_string_append_printf(str, "%15s %5d %5d %5d\n",
inet_ntoa(dst_addr), ntohs(dst_port),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
@@ -300,9 +242,11 @@ void slirp_connection_info(Slirp *slirp, Monitor *mon)
(so->so_expire - curtime) / 1000);
src.sin_addr = so->so_laddr;
dst_addr = so->so_faddr;
- monitor_printf(mon, "%-19s %3d %15s - ", buf, so->s,
+ g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s,
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
- monitor_printf(mon, "%15s - %5d %5d\n", inet_ntoa(dst_addr),
+ g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr),
so->so_rcv.sb_cc, so->so_snd.sb_cc);
}
+
+ return g_string_free(str, FALSE);
}
diff --git a/slirp/misc.h b/slirp/misc.h
index 5211bbd30a..1df707c052 100644
--- a/slirp/misc.h
+++ b/slirp/misc.h
@@ -8,12 +8,12 @@
#ifndef MISC_H
#define MISC_H
-struct ex_list {
- int ex_pty; /* Do we want a pty? */
+struct gfwd_list {
+ void *ex_chardev;
struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
- const char *ex_exec; /* Command line of what to exec */
- struct ex_list *ex_next;
+ char *ex_exec; /* Command line of what to exec */
+ struct gfwd_list *ex_next;
};
#define EMU_NONE 0x0
@@ -26,7 +26,6 @@ struct ex_list {
#define EMU_REALAUDIO 0x5
#define EMU_RLOGIN 0x6
#define EMU_IDENT 0x7
-#define EMU_RSH 0x8
#define EMU_NOCONNECT 0x10 /* Don't connect */
@@ -52,7 +51,7 @@ struct slirp_quehead {
void slirp_insque(void *, void *);
void slirp_remque(void *);
-int add_exec(struct ex_list **, int, char *, struct in_addr, int);
-int fork_exec(struct socket *so, const char *ex, int do_pty);
+int add_exec(struct gfwd_list **, void *, const char *, struct in_addr, int);
+int fork_exec(struct socket *so, const char *ex);
#endif
diff --git a/slirp/ncsi.c b/slirp/ncsi.c
index 7116034afc..8594382270 100644
--- a/slirp/ncsi.c
+++ b/slirp/ncsi.c
@@ -128,7 +128,7 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
memset(reh->h_source, 0xff, ETH_ALEN);
reh->h_proto = htons(ETH_P_NCSI);
- for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) {
+ for (i = 0; i < G_N_ELEMENTS(ncsi_rsp_handlers); i++) {
if (ncsi_rsp_handlers[i].type == nh->type + 0x80) {
handler = &ncsi_rsp_handlers[i];
break;
@@ -163,5 +163,5 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
*pchecksum = htonl(checksum);
ncsi_rsp_len += 4;
- slirp_output(slirp->opaque, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
+ slirp->cb->output(slirp->opaque, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
}
diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
index e1676a0a7b..b7b73722f7 100644
--- a/slirp/ndp_table.c
+++ b/slirp/ndp_table.c
@@ -10,18 +10,17 @@
void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
uint8_t ethaddr[ETH_ALEN])
{
+ char addrstr[INET6_ADDRSTRLEN];
NdpTable *ndp_table = &slirp->ndp_table;
int i;
- DEBUG_CALL("ndp_table_add");
-#if !defined(_WIN32) || (_WIN32_WINNT >= 0x0600)
- char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+ DEBUG_CALL("ndp_table_add");
DEBUG_ARG("ip = %s", addrstr);
-#endif
- DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
- ethaddr[0], ethaddr[1], ethaddr[2],
- ethaddr[3], ethaddr[4], ethaddr[5]));
+ DEBUG_ARG("hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+ ethaddr[0], ethaddr[1], ethaddr[2],
+ ethaddr[3], ethaddr[4], ethaddr[5]);
if (IN6_IS_ADDR_MULTICAST(&ip_addr) || in6_zero(&ip_addr)) {
/* Do not register multicast or unspecified addresses */
@@ -50,15 +49,14 @@ void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
uint8_t out_ethaddr[ETH_ALEN])
{
+ char addrstr[INET6_ADDRSTRLEN];
NdpTable *ndp_table = &slirp->ndp_table;
int i;
- DEBUG_CALL("ndp_table_search");
-#if !defined(_WIN32) || (_WIN32_WINNT >= 0x0600)
- char addrstr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+
+ DEBUG_CALL("ndp_table_search");
DEBUG_ARG("ip = %s", addrstr);
-#endif
assert(!in6_zero(&ip_addr));
@@ -69,18 +67,18 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
out_ethaddr[3] = ip_addr.s6_addr[13];
out_ethaddr[4] = ip_addr.s6_addr[14];
out_ethaddr[5] = ip_addr.s6_addr[15];
- DEBUG_ARGS((dfd, " multicast addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+ DEBUG_ARG("multicast addr = %02x:%02x:%02x:%02x:%02x:%02x",
+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
for (i = 0; i < NDP_TABLE_SIZE; i++) {
if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN);
- DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
- out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
- out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+ DEBUG_ARG("found hw addr = %02x:%02x:%02x:%02x:%02x:%02x",
+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]);
return 1;
}
}
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
index a722ecb629..644c201341 100644
--- a/slirp/sbuf.h
+++ b/slirp/sbuf.h
@@ -8,7 +8,6 @@
#ifndef SBUF_H
#define SBUF_H
-#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
struct sbuf {
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 322edf51eb..a9674ab090 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -35,6 +35,11 @@
#include <net/if.h>
#endif
+int slirp_debug;
+
+/* Define to 1 if you want KEEPALIVE timers */
+bool slirp_do_keepalive;
+
/* host loopback address */
struct in_addr loopback_addr;
/* host loopback network mask */
@@ -47,7 +52,7 @@ static const uint8_t special_ethaddr[ETH_ALEN] = {
u_int curtime;
-static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
+static QTAILQ_HEAD(, Slirp) slirp_instances =
QTAILQ_HEAD_INITIALIZER(slirp_instances);
static struct in_addr dns_addr;
@@ -161,9 +166,7 @@ static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
if (!f)
return -1;
-#ifdef DEBUG
- fprintf(stderr, "IP address of your DNS(s): ");
-#endif
+ DEBUG_MISC("IP address of your DNS(s):");
while (fgets(buff, 512, f) != NULL) {
if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
char *c = strchr(buff2, '%');
@@ -186,26 +189,18 @@ static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
}
*cached_time = curtime;
}
-#ifdef DEBUG
- else
- fprintf(stderr, ", ");
-#endif
+
if (++found > 3) {
-#ifdef DEBUG
- fprintf(stderr, "(more)");
-#endif
+ DEBUG_MISC(" (more)");
break;
- }
-#ifdef DEBUG
- else {
+ } else if (slirp_debug & DBG_MISC) {
char s[INET6_ADDRSTRLEN];
const char *res = inet_ntop(af, tmp_addr, s, sizeof(s));
if (!res) {
- res = "(string conversion error)";
+ res = " (string conversion error)";
}
- fprintf(stderr, "%s", res);
+ DEBUG_MISC(" %s", res);
}
-#endif
}
}
fclose(f);
@@ -252,6 +247,7 @@ int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
static void slirp_init_once(void)
{
static int initialized;
+ const char *debug;
#ifdef _WIN32
WSADATA Data;
#endif
@@ -268,6 +264,18 @@ static void slirp_init_once(void)
loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
loopback_mask = htonl(IN_CLASSA_NET);
+
+ debug = g_getenv("SLIRP_DEBUG");
+ if (debug) {
+ const GDebugKey keys[] = {
+ { "call", DBG_CALL },
+ { "misc", DBG_MISC },
+ { "error", DBG_ERROR },
+ };
+ slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
+ }
+
+
}
static void slirp_state_save(QEMUFile *f, void *opaque);
@@ -287,12 +295,15 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
- const char *vdomainname, void *opaque)
+ const char *vdomainname,
+ const SlirpCb *callbacks,
+ void *opaque)
{
Slirp *slirp = g_malloc0(sizeof(Slirp));
slirp_init_once();
+ slirp->cb = callbacks;
slirp->grand = g_rand_new();
slirp->restricted = restricted;
@@ -339,6 +350,14 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
void slirp_cleanup(Slirp *slirp)
{
+ struct gfwd_list *e, *next;
+
+ for (e = slirp->guestfwd_list; e; e = next) {
+ next = e->ex_next;
+ g_free(e->ex_exec);
+ g_free(e);
+ }
+
QTAILQ_REMOVE(&slirp_instances, slirp, entry);
unregister_savevm(NULL, "slirp", slirp);
@@ -560,15 +579,15 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
void slirp_pollfds_poll(GArray *pollfds, int select_error)
{
- Slirp *slirp;
+ Slirp *slirp = QTAILQ_FIRST(&slirp_instances);
struct socket *so, *so_next;
int ret;
- if (QTAILQ_EMPTY(&slirp_instances)) {
+ if (!slirp) {
return;
}
- curtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+ curtime = slirp->cb->clock_get_ns() / SCALE_MS;
QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
/*
@@ -688,47 +707,6 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
}
}
}
-
- /*
- * Probe a still-connecting, non-blocking socket
- * to check if it's still alive
- */
-#ifdef PROBE_CONN
- if (so->so_state & SS_ISFCONNECTING) {
- ret = qemu_recv(so->s, &ret, 0, 0);
-
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN) {
- continue; /* Still connecting, continue */
- }
-
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
-
- /* tcp_input will take care of it */
- } else {
- ret = send(so->s, &ret, 0, 0);
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN) {
- continue;
- }
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
- } else {
- so->so_state &= ~SS_ISFCONNECTING;
- }
-
- }
- tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
- so->so_ffamily);
- } /* SS_ISFCONNECTING */
-#endif
}
/*
@@ -787,7 +765,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
struct ethhdr *reh = (struct ethhdr *)arp_reply;
struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
int ar_op;
- struct ex_list *ex_ptr;
+ struct gfwd_list *ex_ptr;
if (!slirp->in_enabled) {
return;
@@ -807,7 +785,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
ah->ar_tip == slirp->vhost_addr.s_addr)
goto arp_ok;
- for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
goto arp_ok;
}
@@ -832,7 +810,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
rah->ar_sip = ah->ar_tip;
memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
rah->ar_tip = ah->ar_sip;
- slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
+ slirp->cb->output(slirp->opaque, arp_reply, sizeof(arp_reply));
}
break;
case ARPOP_REPLY:
@@ -932,11 +910,11 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
/* target IP */
rah->ar_tip = iph->ip_dst.s_addr;
slirp->client_ipaddr = iph->ip_dst;
- slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+ slirp->cb->output(slirp->opaque, arp_req, sizeof(arp_req));
ifm->resolution_requested = true;
/* Expire request and drop outgoing packet after 1 second */
- ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+ ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL;
}
return 0;
} else {
@@ -962,8 +940,7 @@ static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
if (!ifm->resolution_requested) {
ndp_send_ns(slirp, ip6h->ip_dst);
ifm->resolution_requested = true;
- ifm->expiration_date =
- qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+ ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL;
}
return 0;
} else {
@@ -1011,14 +988,14 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
}
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
- DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
- eh->h_source[0], eh->h_source[1], eh->h_source[2],
- eh->h_source[3], eh->h_source[4], eh->h_source[5]));
- DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
- eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
- eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
+ DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x",
+ eh->h_source[0], eh->h_source[1], eh->h_source[2],
+ eh->h_source[3], eh->h_source[4], eh->h_source[5]);
+ DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x",
+ eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+ eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
- slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+ slirp->cb->output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
return 1;
}
@@ -1065,9 +1042,11 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
return 0;
}
-int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
- struct in_addr *guest_addr, int guest_port)
+static bool
+check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port)
{
+ struct gfwd_list *tmp_ptr;
+
if (!guest_addr->s_addr) {
guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
(htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
@@ -1076,18 +1055,36 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
slirp->vnetwork_addr.s_addr ||
guest_addr->s_addr == slirp->vhost_addr.s_addr ||
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
+ return false;
+ }
+
+ /* check if the port is "bound" */
+ for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
+ if (guest_port == tmp_ptr->ex_fport &&
+ guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
+ return false;
+ }
+
+ return true;
+}
+
+int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline,
+ struct in_addr *guest_addr, int guest_port)
+{
+ if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
- return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
+
+ return add_exec(&slirp->guestfwd_list, chardev, cmdline, *guest_addr,
htons(guest_port));
}
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
- if (so->s == -1 && so->extra) {
+ if (so->s == -1 && so->chardev) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(so->extra, buf, len);
+ qemu_chr_fe_write_all(so->chardev, buf, len);
return len;
}
@@ -1240,8 +1237,8 @@ static int sbuf_tmp_post_load(void *opaque, int version)
}
if (tmp->woff >= requested_len ||
tmp->roff >= requested_len) {
- error_report("invalid sbuf offsets r/w=%u/%u len=%u",
- tmp->roff, tmp->woff, requested_len);
+ g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
+ tmp->roff, tmp->woff, requested_len);
return -EINVAL;
}
@@ -1349,7 +1346,7 @@ static int ss_family_post_load(void *opaque, int version_id)
tss->parent->ss.ss_family = AF_INET6;
break;
default:
- error_report("invalid ss_family type %x", tss->portable_family);
+ g_critical("invalid ss_family type %x", tss->portable_family);
return -EINVAL;
}
@@ -1449,10 +1446,10 @@ static const VMStateDescription vmstate_slirp = {
static void slirp_state_save(QEMUFile *f, void *opaque)
{
Slirp *slirp = opaque;
- struct ex_list *ex_ptr;
+ struct gfwd_list *ex_ptr;
- for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_pty == 3) {
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+ if (ex_ptr->ex_chardev) {
struct socket *so;
so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
ntohs(ex_ptr->ex_fport));
@@ -1471,7 +1468,7 @@ static void slirp_state_save(QEMUFile *f, void *opaque)
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
{
Slirp *slirp = opaque;
- struct ex_list *ex_ptr;
+ struct gfwd_list *ex_ptr;
while (qemu_get_byte(f)) {
int ret;
@@ -1486,8 +1483,8 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
slirp->vnetwork_addr.s_addr) {
return -EINVAL;
}
- for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_pty == 3 &&
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ if (ex_ptr->ex_chardev &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
so->so_fport == ex_ptr->ex_fport) {
break;
@@ -1495,8 +1492,6 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
}
if (!ex_ptr)
return -EINVAL;
-
- so->extra = (void *)ex_ptr->ex_exec;
}
return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);
diff --git a/slirp/slirp.h b/slirp/slirp.h
index b80725a0d6..9aa245715d 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -1,8 +1,6 @@
#ifndef SLIRP_H
#define SLIRP_H
-#include "slirp_config.h"
-
#ifdef _WIN32
typedef char *caddr_t;
@@ -19,10 +17,6 @@ typedef char *caddr_t;
# endif
#endif
-#ifdef HAVE_SYS_BITYPES_H
-# include <sys/bitypes.h>
-#endif
-
#ifndef _WIN32
#include <sys/uio.h>
#endif
@@ -32,29 +26,15 @@ typedef char *caddr_t;
#include <arpa/inet.h>
#endif
-#ifndef NO_UNIX_SOCKETS
-#include <sys/un.h>
-#endif
-#ifdef HAVE_SYS_SIGNAL_H
-# include <sys/signal.h>
-#endif
#ifndef _WIN32
#include <sys/socket.h>
#endif
-#if defined(HAVE_SYS_IOCTL_H)
+#ifndef _WIN32
# include <sys/ioctl.h>
#endif
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-#ifdef HAVE_SYS_FILIO_H
+#ifdef __APPLE__
# include <sys/filio.h>
#endif
@@ -64,11 +44,6 @@ typedef char *caddr_t;
#define remque slirp_remque
#define quehead slirp_quehead
-#ifdef HAVE_SYS_STROPTS_H
-#include <sys/stropts.h>
-#endif
-
-
#include "debug.h"
#include "qemu/queue.h"
@@ -172,7 +147,7 @@ struct Slirp {
char client_hostname[33];
int restricted;
- struct ex_list *exec_list;
+ struct gfwd_list *guestfwd_list;
/* mbuf states */
struct quehead m_freelist;
@@ -220,17 +195,15 @@ struct Slirp {
GRand *grand;
QEMUTimer *ra_timer;
+ const SlirpCb *cb;
void *opaque;
};
-extern Slirp *slirp_instance;
-
-#ifndef NULL
-#define NULL (void *)0
-#endif
-
void if_start(Slirp *);
+int get_dns_addr(struct in_addr *pdns_addr);
+int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id);
+
/* ncsi.c */
void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
@@ -238,7 +211,9 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
#include <netdb.h>
#endif
-#define SO_OPTIONS DO_KEEPALIVE
+
+extern bool slirp_do_keepalive;
+
#define TCP_MAXIDLE (TCPTV_KEEPCNT * TCPTV_KEEPINTVL)
/* dnssearch.c */
diff --git a/slirp/slirp_config.h b/slirp/slirp_config.h
deleted file mode 100644
index c59f655207..0000000000
--- a/slirp/slirp_config.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * User definable configuration options
- */
-
-/* Define if you want the connection to be probed */
-/* XXX Not working yet, so ignore this for now */
-#undef PROBE_CONN
-
-/* Define to 1 if you want KEEPALIVE timers */
-#define DO_KEEPALIVE 0
-
-/* Define this if you want slirp to write to the tty as fast as it can */
-/* This should only be set if you are using load-balancing, slirp does a */
-/* pretty good job on single modems already, and seting this will make */
-/* interactive sessions less responsive */
-/* XXXXX Talk about having fast modem as unit 0 */
-#undef FULL_BOLT
-
-/*********************************************************/
-/*
- * Autoconf defined configuration options
- * You shouldn't need to touch any of these
- */
-
-/* Define if you have sys/ioctl.h */
-#undef HAVE_SYS_IOCTL_H
-#ifndef _WIN32
-#define HAVE_SYS_IOCTL_H
-#endif
-
-/* Define if you have sys/filio.h */
-#undef HAVE_SYS_FILIO_H
-#ifdef __APPLE__
-#define HAVE_SYS_FILIO_H
-#endif
-
-/* Define if you have sys/bitypes.h */
-#undef HAVE_SYS_BITYPES_H
-
-/* Define if the machine is big endian */
-//#undef HOST_WORDS_BIGENDIAN
-
-/* Define if you have readv */
-#undef HAVE_READV
-
-/* Define if iovec needs to be declared */
-#undef DECLARE_IOVEC
-#ifdef _WIN32
-#define DECLARE_IOVEC
-#endif
-
-/* Define if you have a POSIX.1 sys/wait.h */
-#undef HAVE_SYS_WAIT_H
-
-/* Define if you have sys/select.h */
-#undef HAVE_SYS_SELECT_H
-#ifndef _WIN32
-#define HAVE_SYS_SELECT_H
-#endif
-
-/* Define if you have arpa/inet.h */
-#undef HAVE_ARPA_INET_H
-#ifndef _WIN32
-#define HAVE_ARPA_INET_H
-#endif
-
-/* Define if you have sys/signal.h */
-#undef HAVE_SYS_SIGNAL_H
-
-/* Define if you have sys/stropts.h */
-#undef HAVE_SYS_STROPTS_H
-
-/* Define to sizeof(char *) */
-#define SIZEOF_CHAR_P (HOST_LONG_BITS / 8)
-
-/* Define if you have inet_aton */
-#undef HAVE_INET_ATON
-#ifndef _WIN32
-#define HAVE_INET_ATON
-#endif
-
-/* Define if you DON'T have unix-domain sockets */
-#undef NO_UNIX_SOCKETS
-#ifdef _WIN32
-#define NO_UNIX_SOCKETS
-#endif
diff --git a/slirp/socket.c b/slirp/socket.c
index c01d8696af..5ffbaa064a 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -89,10 +89,6 @@ sofree(struct socket *so)
soqfree(so, &slirp->if_fastq);
soqfree(so, &slirp->if_batchq);
- if (so->so_emu==EMU_RSH && so->extra) {
- sofree(so->extra);
- so->extra=NULL;
- }
if (so == slirp->tcp_last_so) {
slirp->tcp_last_so = &slirp->tcb;
} else if (so == slirp->udp_last_so) {
@@ -191,12 +187,7 @@ soread(struct socket *so)
*/
sopreprbuf(so, iov, &n);
-#ifdef HAVE_READV
- nn = readv(so->s, (struct iovec *)iov, n);
- DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
-#else
nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
-#endif
if (nn <= 0) {
if (nn < 0 && (errno == EINTR || errno == EAGAIN))
return 0;
@@ -217,7 +208,8 @@ soread(struct socket *so)
}
}
- DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno)));
+ DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s",
+ nn, errno,strerror(errno));
sofcantrcvmore(so);
if (err == ECONNRESET || err == ECONNREFUSED
@@ -230,7 +222,6 @@ soread(struct socket *so)
}
}
-#ifndef HAVE_READV
/*
* If there was no error, try and read the second time round
* We read again if n = 2 (ie, there's another part of the buffer)
@@ -247,8 +238,7 @@ soread(struct socket *so)
nn += ret;
}
- DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
-#endif
+ DEBUG_MISC(" ... read nn = %d bytes", nn);
/* Update fields */
sb->sb_cc += nn;
@@ -296,7 +286,7 @@ err:
sofcantrcvmore(so);
tcp_sockclosed(sototcpcb(so));
- fprintf(stderr, "soreadbuf buffer to small");
+ g_critical("soreadbuf buffer too small");
return -1;
}
@@ -381,7 +371,7 @@ sosendoob(struct socket *so)
n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */
#ifdef DEBUG
if (n != len) {
- DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
+ DEBUG_ERROR("Didn't send all data urgently XXXXX");
}
#endif
}
@@ -390,7 +380,7 @@ sosendoob(struct socket *so)
return n;
}
so->so_urgc -= n;
- DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
+ DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, so->so_urgc);
sb->sb_cc -= n;
sb->sb_rptr += n;
@@ -456,13 +446,7 @@ sowrite(struct socket *so)
}
/* Check if there's urgent data to send, and if so, send it */
-#ifdef HAVE_READV
- nn = writev(so->s, (const struct iovec *)iov, n);
-
- DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
-#else
nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0);
-#endif
/* This should never happen, but people tell me it does *shrug* */
if (nn < 0 && (errno == EAGAIN || errno == EINTR))
return 0;
@@ -471,15 +455,13 @@ sowrite(struct socket *so)
goto err_disconnected;
}
-#ifndef HAVE_READV
if (n == 2 && nn == iov[0].iov_len) {
int ret;
ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0);
if (ret > 0)
nn += ret;
}
- DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
-#endif
+ DEBUG_MISC(" ... wrote nn = %d bytes", nn);
/* Update sbuf */
sb->sb_cc -= nn;
@@ -497,8 +479,8 @@ sowrite(struct socket *so)
return nn;
err_disconnected:
- DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
- so->so_state, errno));
+ DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d",
+ so->so_state, errno);
sofcantsendmore(so);
tcp_sockclosed(sototcpcb(so));
return -1;
@@ -531,8 +513,8 @@ sorecvfrom(struct socket *so)
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
- DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
- errno,strerror(errno)));
+ DEBUG_MISC(" udp icmp rx errno = %d-%s",
+ errno,strerror(errno));
icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
} else {
icmp_reflect(so->so_m);
@@ -583,8 +565,8 @@ sorecvfrom(struct socket *so)
m->m_len = recvfrom(so->s, m->m_data, len, 0,
(struct sockaddr *)&addr, &addrlen);
- DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
- m->m_len, errno,strerror(errno)));
+ DEBUG_MISC(" did recvfrom %d, errno = %d-%s",
+ m->m_len, errno,strerror(errno));
if(m->m_len<0) {
/* Report error as ICMP */
switch (so->so_lfamily) {
@@ -598,7 +580,7 @@ sorecvfrom(struct socket *so)
code = ICMP_UNREACH_NET;
}
- DEBUG_MISC((dfd, " rx error, tx icmp ICMP_UNREACH:%i\n", code));
+ DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code);
icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
break;
case AF_INET6:
@@ -610,7 +592,7 @@ sorecvfrom(struct socket *so)
code = ICMP6_UNREACH_NO_ROUTE;
}
- DEBUG_MISC((dfd, " rx error, tx icmp6 ICMP_UNREACH:%i\n", code));
+ DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code);
icmp6_send_error(so->so_m, ICMP6_UNREACH, code);
break;
default:
@@ -858,9 +840,8 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
}
}
- DEBUG_MISC((dfd, " addr.sin_port=%d, "
- "addr.sin_addr.s_addr=%.16s\n",
- ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
+ DEBUG_MISC(" addr.sin_port=%d, addr.sin_addr.s_addr=%.16s",
+ ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
break;
case AF_INET6:
diff --git a/slirp/socket.h b/slirp/socket.h
index 2f224bc34f..930ed95972 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -67,7 +67,7 @@ struct socket {
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
- void * extra; /* Extra pointer */
+ void * chardev;
};
diff --git a/slirp/tcp.h b/slirp/tcp.h
index 174d3d960c..47aaea6c5b 100644
--- a/slirp/tcp.h
+++ b/slirp/tcp.h
@@ -33,6 +33,8 @@
#ifndef TCP_H
#define TCP_H
+#include <glib.h>
+
typedef uint32_t tcp_seq;
#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */
@@ -51,7 +53,7 @@ struct tcphdr {
uint16_t th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
-#ifdef HOST_WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
uint8_t th_off:4, /* data offset */
th_x2:4; /* (unused) */
#else
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index d073ef9525..de5b74a52b 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -60,27 +60,6 @@
* Set DELACK for segments received in order, but ack immediately
* when segments are out of order (so fast retransmit can work).
*/
-#ifdef TCP_ACK_HACK
-#define TCP_REASS(tp, ti, m, so, flags) {\
- if ((ti)->ti_seq == (tp)->rcv_nxt && \
- tcpfrag_list_empty(tp) && \
- (tp)->t_state == TCPS_ESTABLISHED) {\
- if (ti->ti_flags & TH_PUSH) \
- tp->t_flags |= TF_ACKNOW; \
- else \
- tp->t_flags |= TF_DELACK; \
- (tp)->rcv_nxt += (ti)->ti_len; \
- flags = (ti)->ti_flags & TH_FIN; \
- if (so->so_emu) { \
- if (tcp_emu((so),(m))) sbappend((so), (m)); \
- } else \
- sbappend((so), (m)); \
- } else {\
- (flags) = tcp_reass((tp), (ti), (m)); \
- tp->t_flags |= TF_ACKNOW; \
- } \
-}
-#else
#define TCP_REASS(tp, ti, m, so, flags) { \
if ((ti)->ti_seq == (tp)->rcv_nxt && \
tcpfrag_list_empty(tp) && \
@@ -97,7 +76,7 @@
tp->t_flags |= TF_ACKNOW; \
} \
}
-#endif
+
static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
struct tcpiphdr *ti);
static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
@@ -232,12 +211,12 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
struct sockaddr_storage lhost, fhost;
struct sockaddr_in *lhost4, *fhost4;
struct sockaddr_in6 *lhost6, *fhost6;
- struct ex_list *ex_ptr;
+ struct gfwd_list *ex_ptr;
Slirp *slirp;
DEBUG_CALL("tcp_input");
- DEBUG_ARGS((dfd, " m = %p iphlen = %2d inso = %p\n",
- m, iphlen, inso));
+ DEBUG_ARG("m = %p iphlen = %2d inso = %p",
+ m, iphlen, inso);
/*
* If called with m == 0, then we're continuing the connect
@@ -415,7 +394,7 @@ findso:
* for non-hostfwd connections. These should be dropped, unless it
* happens to be a guestfwd.
*/
- for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->ex_fport == ti->ti_dport &&
ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
break;
@@ -481,7 +460,7 @@ findso:
* Reset idle time and keep-alive timer.
*/
tp->t_idle = 0;
- if (SO_OPTIONS)
+ if (slirp_do_keepalive)
tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
else
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
@@ -637,7 +616,7 @@ findso:
if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
/* May be an add exec */
- for (ex_ptr = slirp->exec_list; ex_ptr;
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr;
ex_ptr = ex_ptr->ex_next) {
if(ex_ptr->ex_fport == so->so_fport &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
@@ -662,8 +641,7 @@ findso:
(errno != EINPROGRESS) && (errno != EWOULDBLOCK)
) {
uint8_t code;
- DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
- errno,strerror(errno)));
+ DEBUG_MISC(" tcp fconnect errno = %d-%s", errno, strerror(errno));
if(errno == ECONNREFUSED) {
/* ACK the SYN, send RST to refuse the connection */
tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq) 0,
@@ -1032,8 +1010,7 @@ trimthenstep6:
if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
- DEBUG_MISC((dfd, " dup ack m = %p so = %p\n",
- m, so));
+ DEBUG_MISC(" dup ack m = %p so = %p", m, so);
/*
* If we have outstanding data (other than
* a window probe), this is a completely
@@ -1175,7 +1152,7 @@ trimthenstep6:
}
break;
- /*
+ /*
* In CLOSING STATE in addition to the processing for
* the ESTABLISHED state if the ACK acknowledges our FIN
* then enter the TIME-WAIT state, otherwise ignore
@@ -1325,7 +1302,7 @@ dodata:
}
switch (tp->t_state) {
- /*
+ /*
* In SYN_RECEIVED and ESTABLISHED STATES
* enter the CLOSE_WAIT state.
*/
@@ -1337,7 +1314,7 @@ dodata:
tp->t_state = TCPS_CLOSE_WAIT;
break;
- /*
+ /*
* If still in FIN_WAIT_1 STATE FIN has not been acked so
* enter the CLOSING state.
*/
@@ -1345,7 +1322,7 @@ dodata:
tp->t_state = TCPS_CLOSING;
break;
- /*
+ /*
* In FIN_WAIT_2 state enter the TIME_WAIT state,
* starting the time-wait timer, turning off the other
* standard timers.
@@ -1411,7 +1388,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
int opt, optlen;
DEBUG_CALL("tcp_dooptions");
- DEBUG_ARGS((dfd, " tp = %p cnt=%i\n", tp, cnt));
+ DEBUG_ARG("tp = %p cnt=%i", tp, cnt);
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[0];
@@ -1442,45 +1419,6 @@ tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
}
}
-
-/*
- * Pull out of band byte out of a segment so
- * it doesn't appear in the user's data queue.
- * It is still reflected in the segment length for
- * sequencing purposes.
- */
-
-#ifdef notdef
-
-void
-tcp_pulloutofband(so, ti, m)
- struct socket *so;
- struct tcpiphdr *ti;
- register struct mbuf *m;
-{
- int cnt = ti->ti_urp - 1;
-
- while (cnt >= 0) {
- if (m->m_len > cnt) {
- char *cp = mtod(m, caddr_t) + cnt;
- struct tcpcb *tp = sototcpcb(so);
-
- tp->t_iobc = *cp;
- tp->t_oobflags |= TCPOOB_HAVEDATA;
- memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1));
- m->m_len--;
- return;
- }
- cnt -= m->m_len;
- m = m->m_next; /* XXX WRONG! Fix it! */
- if (m == 0)
- break;
- }
- panic("tcp_pulloutofband");
-}
-
-#endif /* notdef */
-
/*
* Collect new round-trip time estimate
* and update averages and current timeout.
@@ -1611,7 +1549,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
(mss - (TCP_RCVSPACE % mss)) :
0));
- DEBUG_MISC((dfd, " returning mss = %d\n", mss));
+ DEBUG_MISC(" returning mss = %d", mss);
return mss;
}
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 90b5c376f7..6dd1ecf5d9 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -92,7 +92,7 @@ again:
flags = tcp_outflags[tp->t_state];
- DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
+ DEBUG_MISC(" --- tcp_output flags = 0x%x", flags);
/*
* If in persist timeout with window of 0, send 1 byte.
@@ -275,9 +275,9 @@ send:
memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss));
optlen = 4;
}
- }
+ }
- hdrlen += optlen;
+ hdrlen += optlen;
/*
* Adjust data length if insertion of options will
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index fa61349cbb..23a841f26e 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -420,7 +420,7 @@ int tcp_fconnect(struct socket *so, unsigned short af)
qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
addr = so->fhost.ss;
- DEBUG_CALL(" connect()ing")
+ DEBUG_CALL(" connect()ing");
sotranslate_out(so, &addr);
/* We don't care what port we get */
@@ -541,7 +541,6 @@ static const struct tos_t tcptos[] = {
{0, 23, IPTOS_LOWDELAY, 0}, /* telnet */
{0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
{0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */
- {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */
{0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */
{0, 543, IPTOS_LOWDELAY, 0}, /* klogin */
{0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
@@ -635,6 +634,11 @@ tcp_emu(struct socket *so, struct mbuf *m)
socklen_t addrlen = sizeof(struct sockaddr_in);
struct sbuf *so_rcv = &so->so_rcv;
+ if (m->m_len > so_rcv->sb_datalen
+ - (so_rcv->sb_wptr - so_rcv->sb_data)) {
+ return 1;
+ }
+
memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
so_rcv->sb_wptr += m->m_len;
so_rcv->sb_rptr += m->m_len;
@@ -950,25 +954,23 @@ int tcp_ctl(struct socket *so)
{
Slirp *slirp = so->slirp;
struct sbuf *sb = &so->so_snd;
- struct ex_list *ex_ptr;
- int do_pty;
+ struct gfwd_list *ex_ptr;
DEBUG_CALL("tcp_ctl");
DEBUG_ARG("so = %p", so);
if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
/* Check if it's pty_exec */
- for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->ex_fport == so->so_fport &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
- if (ex_ptr->ex_pty == 3) {
+ if (ex_ptr->ex_chardev) {
so->s = -1;
- so->extra = (void *)ex_ptr->ex_exec;
+ so->chardev = ex_ptr->ex_chardev;
return 1;
}
- do_pty = ex_ptr->ex_pty;
- DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
- return fork_exec(so, ex_ptr->ex_exec, do_pty);
+ DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
+ return fork_exec(so, ex_ptr->ex_exec);
}
}
}
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index 52ef5f9100..a843e57a2b 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -262,8 +262,8 @@ tcp_timers(register struct tcpcb *tp, int timer)
if (tp->t_state < TCPS_ESTABLISHED)
goto dropit;
- if ((SO_OPTIONS) && tp->t_state <= TCPS_CLOSE_WAIT) {
- if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
+ if (slirp_do_keepalive && tp->t_state <= TCPS_CLOSE_WAIT) {
+ if (tp->t_idle >= TCPTV_KEEP_IDLE + TCP_MAXIDLE)
goto dropit;
/*
* Send a packet designed to force a response
diff --git a/slirp/tftp.c b/slirp/tftp.c
index a9bc4bb1b6..a9ba1480db 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -26,6 +26,7 @@
#include "slirp.h"
#include "qemu-common.h"
#include "qemu/cutils.h"
+#include "trace.h"
static inline int tftp_session_in_use(struct tftp_session *spt)
{
@@ -204,6 +205,7 @@ static void tftp_send_error(struct tftp_session *spt,
struct mbuf *m;
struct tftp_t *tp;
+ trace_slirp_tftp_error(msg);
m = m_get(spt->slirp);
if (!m) {
@@ -323,6 +325,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
break;
}
}
+ trace_slirp_tftp_rrq(req_fname);
/* check mode */
if ((pktlen - k) < 6) {
@@ -356,7 +359,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
return;
}
- while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
+ while (k < pktlen && nb_options < G_N_ELEMENTS(option_name)) {
const char *key, *value;
key = &tp->x.tp_buf[k];
@@ -400,7 +403,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
}
if (nb_options > 0) {
- assert(nb_options <= ARRAY_SIZE(option_name));
+ assert(nb_options <= G_N_ELEMENTS(option_name));
tftp_send_oack(spt, option_name, option_value, nb_options, tp);
return;
}
diff --git a/slirp/trace-events b/slirp/trace-events
new file mode 100644
index 0000000000..ff8f656e8c
--- /dev/null
+++ b/slirp/trace-events
@@ -0,0 +1,5 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# slirp/tftp.c
+slirp_tftp_rrq(const char *file) "file: %s"
+slirp_tftp_error(const char *file) "msg: %s"
diff --git a/slirp/udp.c b/slirp/udp.c
index c47870a61b..309feb9aae 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -172,8 +172,7 @@ udp_input(register struct mbuf *m, int iphlen)
*/
so = socreate(slirp);
if (udp_attach(so, AF_INET) == -1) {
- DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
- errno,strerror(errno)));
+ DEBUG_MISC(" udp_attach errno = %d-%s", errno, strerror(errno));
sofree(so);
goto bad;
}
@@ -209,7 +208,7 @@ udp_input(register struct mbuf *m, int iphlen)
m->m_len += iphlen;
m->m_data -= iphlen;
*ip=save_ip;
- DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
+ DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
strerror(errno));
goto bad;
@@ -310,7 +309,7 @@ udp_tos(struct socket *so)
while(udptos[i].tos) {
if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
- so->so_emu = udptos[i].emu;
+ so->so_emu = udptos[i].emu;
return udptos[i].tos;
}
i++;
diff --git a/slirp/udp6.c b/slirp/udp6.c
index 986010f0d3..fa531e03c4 100644
--- a/slirp/udp6.c
+++ b/slirp/udp6.c
@@ -20,7 +20,7 @@ void udp6_input(struct mbuf *m)
struct sockaddr_in6 lhost;
DEBUG_CALL("udp6_input");
- DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("m = %p", m);
if (slirp->restricted) {
goto bad;
@@ -92,8 +92,7 @@ void udp6_input(struct mbuf *m)
/* If there's no socket for this packet, create one. */
so = socreate(slirp);
if (udp_attach(so, AF_INET6) == -1) {
- DEBUG_MISC((dfd, " udp6_attach errno = %d-%s\n",
- errno, strerror(errno)));
+ DEBUG_MISC(" udp6_attach errno = %d-%s", errno, strerror(errno));
sofree(so);
goto bad;
}
@@ -119,7 +118,7 @@ void udp6_input(struct mbuf *m)
m->m_len += iphlen;
m->m_data -= iphlen;
*ip = save_ip;
- DEBUG_MISC((dfd, "udp tx errno = %d-%s\n", errno, strerror(errno)));
+ DEBUG_MISC("udp tx errno = %d-%s", errno, strerror(errno));
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
goto bad;
}
@@ -144,8 +143,8 @@ int udp6_output(struct socket *so, struct mbuf *m,
struct udphdr *uh;
DEBUG_CALL("udp6_output");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("so = %p", so);
+ DEBUG_ARG("m = %p", m);
/* adjust for header */
m->m_data -= sizeof(struct udphdr);
diff --git a/stubs/slirp.c b/stubs/slirp.c
index 42f7e1afd0..70704346fd 100644
--- a/stubs/slirp.c
+++ b/stubs/slirp.c
@@ -1,7 +1,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/host-utils.h"
-#include "slirp/slirp.h"
+#include "slirp/libslirp.h"
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
{
diff --git a/stubs/tpm.c b/stubs/tpm.c
index 80939cd3db..66c99d667d 100644
--- a/stubs/tpm.c
+++ b/stubs/tpm.c
@@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "qapi/qapi-commands-tpm.h"
#include "sysemu/tpm.h"
+#include "hw/acpi/tpm.h"
void tpm_init(void)
{
@@ -31,3 +32,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp)
{
return NULL;
}
+
+void tpm_build_ppi_acpi(TPMIf *tpm, Aml *dev)
+{
+}
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index a953897fcc..1fd95d6c0f 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -205,9 +205,9 @@ static void alpha_cpu_initfn(Object *obj)
env->lock_addr = -1;
#if defined(CONFIG_USER_ONLY)
env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
- cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
- | FPCR_UNFD | FPCR_INED | FPCR_DNOD
- | FPCR_DYN_NORMAL));
+ cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
+ | FPCR_UNFD | FPCR_INED | FPCR_DNOD
+ | FPCR_DYN_NORMAL) << 32);
#else
env->flags = ENV_FLAG_PAL_MODE | ENV_FLAG_FEN;
#endif
diff --git a/target/alpha/translate.c b/target/alpha/translate.c
index e5d62850c5..9d8f9b3eea 100644
--- a/target/alpha/translate.c
+++ b/target/alpha/translate.c
@@ -804,7 +804,7 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
static void gen_ieee_intcvt(DisasContext *ctx,
void (*helper)(TCGv, TCGv_ptr, TCGv),
- int rb, int rc, int fn11)
+ int rb, int rc, int fn11)
{
TCGv vb, vc;
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
index 11c7baf8a3..1a4fc06448 100644
--- a/target/arm/Makefile.objs
+++ b/target/arm/Makefile.objs
@@ -8,6 +8,7 @@ obj-y += translate.o op_helper.o helper.o cpu.o
obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o
obj-y += gdbstub.o
obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
+obj-$(TARGET_AARCH64) += pauth_helper.o
obj-y += crypto_helper.o
obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h
index d135ff8e06..2049fa9612 100644
--- a/target/arm/cpu-qom.h
+++ b/target/arm/cpu-qom.h
@@ -35,6 +35,8 @@ struct arm_boot_info;
#define TYPE_ARM_MAX_CPU "max-" TYPE_ARM_CPU
+typedef struct ARMCPUInfo ARMCPUInfo;
+
/**
* ARMCPUClass:
* @parent_realize: The parent class' realize handler.
@@ -47,6 +49,7 @@ typedef struct ARMCPUClass {
CPUClass parent_class;
/*< public >*/
+ const ARMCPUInfo *info;
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
} ARMCPUClass;
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 60411f6bfe..7e1f3dd637 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -162,6 +162,9 @@ static void arm_cpu_reset(CPUState *s)
env->pstate = PSTATE_MODE_EL0t;
/* Userspace expects access to DC ZVA, CTL_EL0 and the cache ops */
env->cp15.sctlr_el[1] |= SCTLR_UCT | SCTLR_UCI | SCTLR_DZE;
+ /* Enable all PAC instructions */
+ env->cp15.hcr_el2 |= HCR_API;
+ env->cp15.scr_el3 |= SCR_API;
/* and to the FP/Neon instructions */
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
/* and to the SVE instructions */
@@ -642,6 +645,20 @@ uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
return (Aff1 << ARM_AFF1_SHIFT) | Aff0;
}
+static void cpreg_hashtable_data_destroy(gpointer data)
+{
+ /*
+ * Destroy function for cpu->cp_regs hashtable data entries.
+ * We must free the name string because it was g_strdup()ed in
+ * add_cpreg_to_hashtable(). It's OK to cast away the 'const'
+ * from r->name because we know we definitely allocated it.
+ */
+ ARMCPRegInfo *r = data;
+
+ g_free((void *)r->name);
+ g_free(r);
+}
+
static void arm_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -649,7 +666,7 @@ static void arm_cpu_initfn(Object *obj)
cs->env_ptr = &cpu->env;
cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
- g_free, g_free);
+ g_free, cpreg_hashtable_data_destroy);
QLIST_INIT(&cpu->pre_el_change_hooks);
QLIST_INIT(&cpu->el_change_hooks);
@@ -665,14 +682,6 @@ static void arm_cpu_initfn(Object *obj)
qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 4);
}
- cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_ptimer_cb, cpu);
- cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_vtimer_cb, cpu);
- cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_htimer_cb, cpu);
- cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
- arm_gt_stimer_cb, cpu);
qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
ARRAY_SIZE(cpu->gt_timer_outputs));
@@ -734,7 +743,7 @@ static Property arm_cpu_pmsav7_dregion_property =
static Property arm_cpu_initsvtor_property =
DEFINE_PROP_UINT32("init-svtor", ARMCPU, init_svtor, 0);
-static void arm_cpu_post_init(Object *obj)
+void arm_cpu_post_init(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -868,6 +877,15 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
}
+
+ cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
+ arm_gt_ptimer_cb, cpu);
+ cpu->gt_timer[GTIMER_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
+ arm_gt_vtimer_cb, cpu);
+ cpu->gt_timer[GTIMER_HYP] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
+ arm_gt_htimer_cb, cpu);
+ cpu->gt_timer[GTIMER_SEC] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,
+ arm_gt_stimer_cb, cpu);
#endif
cpu_exec_realizefn(cs, &local_err);
@@ -1019,7 +1037,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
if (!cpu->has_pmu) {
unset_feature(env, ARM_FEATURE_PMU);
+ }
+ if (arm_feature(env, ARM_FEATURE_PMU)) {
+ cpu->pmceid0 = get_pmceid(&cpu->env, 0);
+ cpu->pmceid1 = get_pmceid(&cpu->env, 1);
+
+ if (!kvm_enabled()) {
+ arm_register_pre_el_change_hook(cpu, &pmu_pre_el_change, 0);
+ arm_register_el_change_hook(cpu, &pmu_post_el_change, 0);
+ }
+ } else {
cpu->id_aa64dfr0 &= ~0xf00;
+ cpu->pmceid0 = 0;
+ cpu->pmceid1 = 0;
}
if (!arm_feature(env, ARM_FEATURE_EL2)) {
@@ -1442,8 +1472,10 @@ static void cortex_m33_initfn(Object *obj)
static void arm_v7m_class_init(ObjectClass *oc, void *data)
{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
+ acc->info = data;
#ifndef CONFIG_USER_ONLY
cc->do_interrupt = arm_v7m_cpu_do_interrupt;
#endif
@@ -1662,8 +1694,6 @@ static void cortex_a7_initfn(Object *obj)
cpu->id_pfr0 = 0x00001131;
cpu->id_pfr1 = 0x00011011;
cpu->id_dfr0 = 0x02010555;
- cpu->pmceid0 = 0x00000000;
- cpu->pmceid1 = 0x00000000;
cpu->id_afr0 = 0x00000000;
cpu->id_mmfr0 = 0x10101105;
cpu->id_mmfr1 = 0x40000000;
@@ -1709,8 +1739,6 @@ static void cortex_a15_initfn(Object *obj)
cpu->id_pfr0 = 0x00001131;
cpu->id_pfr1 = 0x00011011;
cpu->id_dfr0 = 0x02010555;
- cpu->pmceid0 = 0x0000000;
- cpu->pmceid1 = 0x00000000;
cpu->id_afr0 = 0x00000000;
cpu->id_mmfr0 = 0x10201105;
cpu->id_mmfr1 = 0x20000000;
@@ -1932,6 +1960,10 @@ static void arm_max_initfn(Object *obj)
t = cpu->isar.id_isar6;
t = FIELD_DP32(t, ID_ISAR6, DP, 1);
cpu->isar.id_isar6 = t;
+
+ t = cpu->id_mmfr4;
+ t = FIELD_DP32(t, ID_MMFR4, HPDS, 1); /* AA32HPD */
+ cpu->id_mmfr4 = t;
}
#endif
}
@@ -1940,11 +1972,11 @@ static void arm_max_initfn(Object *obj)
#endif /* !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) */
-typedef struct ARMCPUInfo {
+struct ARMCPUInfo {
const char *name;
void (*initfn)(Object *obj);
void (*class_init)(ObjectClass *oc, void *data);
-} ARMCPUInfo;
+};
static const ARMCPUInfo arm_cpus[] = {
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
@@ -2094,6 +2126,7 @@ static void arm_host_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
kvm_arm_set_cpu_features_from_host(cpu);
+ arm_cpu_post_init(obj);
}
static const TypeInfo host_arm_cpu_type_info = {
@@ -2108,14 +2141,30 @@ static const TypeInfo host_arm_cpu_type_info = {
#endif
+static void arm_cpu_instance_init(Object *obj)
+{
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
+
+ acc->info->initfn(obj);
+ arm_cpu_post_init(obj);
+}
+
+static void cpu_register_class_init(ObjectClass *oc, void *data)
+{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+
+ acc->info = data;
+}
+
static void cpu_register(const ARMCPUInfo *info)
{
TypeInfo type_info = {
.parent = TYPE_ARM_CPU,
.instance_size = sizeof(ARMCPU),
- .instance_init = info->initfn,
+ .instance_init = arm_cpu_instance_init,
.class_size = sizeof(ARMCPUClass),
- .class_init = info->class_init,
+ .class_init = info->class_init ?: cpu_register_class_init,
+ .class_data = (void *)info,
};
type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name);
@@ -2128,7 +2177,6 @@ static const TypeInfo arm_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(ARMCPU),
.instance_init = arm_cpu_initfn,
- .instance_post_init = arm_cpu_post_init,
.instance_finalize = arm_cpu_finalizefn,
.abstract = true,
.class_size = sizeof(ARMCPUClass),
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 2a73fed9a0..ff81db420d 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -201,11 +201,16 @@ typedef struct ARMVectorReg {
uint64_t d[2 * ARM_MAX_VQ] QEMU_ALIGNED(16);
} ARMVectorReg;
-/* In AArch32 mode, predicate registers do not exist at all. */
#ifdef TARGET_AARCH64
+/* In AArch32 mode, predicate registers do not exist at all. */
typedef struct ARMPredicateReg {
uint64_t p[2 * ARM_MAX_VQ / 8] QEMU_ALIGNED(16);
} ARMPredicateReg;
+
+/* In AArch32 mode, PAC keys do not exist at all. */
+typedef struct ARMPACKey {
+ uint64_t lo, hi;
+} ARMPACKey;
#endif
@@ -468,10 +473,23 @@ typedef struct CPUARMState {
uint64_t oslsr_el1; /* OS Lock Status */
uint64_t mdcr_el2;
uint64_t mdcr_el3;
- /* If the counter is enabled, this stores the last time the counter
- * was reset. Otherwise it stores the counter value
+ /* Stores the architectural value of the counter *the last time it was
+ * updated* by pmccntr_op_start. Accesses should always be surrounded
+ * by pmccntr_op_start/pmccntr_op_finish to guarantee the latest
+ * architecturally-correct value is being read/set.
*/
uint64_t c15_ccnt;
+ /* Stores the delta between the architectural value and the underlying
+ * cycle count during normal operation. It is used to update c15_ccnt
+ * to be the correct architectural value before accesses. During
+ * accesses, c15_ccnt_delta contains the underlying count being used
+ * for the access, after which it reverts to the delta value in
+ * pmccntr_op_finish.
+ */
+ uint64_t c15_ccnt_delta;
+ uint64_t c14_pmevcntr[31];
+ uint64_t c14_pmevcntr_delta[31];
+ uint64_t c14_pmevtyper[31];
uint64_t pmccfiltr_el0; /* Performance Monitor Filter Register */
uint64_t vpidr_el2; /* Virtualization Processor ID Register */
uint64_t vmpidr_el2; /* Virtualization Multiprocessor ID Register */
@@ -605,6 +623,14 @@ typedef struct CPUARMState {
uint32_t cregs[16];
} iwmmxt;
+#ifdef TARGET_AARCH64
+ ARMPACKey apia_key;
+ ARMPACKey apib_key;
+ ARMPACKey apda_key;
+ ARMPACKey apdb_key;
+ ARMPACKey apga_key;
+#endif
+
#if defined(CONFIG_USER_ONLY)
/* For usermode syscall translation. */
int eabi;
@@ -818,6 +844,8 @@ struct ARMCPU {
uint64_t id_aa64isar1;
uint64_t id_aa64pfr0;
uint64_t id_aa64pfr1;
+ uint64_t id_aa64mmfr0;
+ uint64_t id_aa64mmfr1;
} isar;
uint32_t midr;
uint32_t revidr;
@@ -827,8 +855,8 @@ struct ARMCPU {
uint32_t id_pfr0;
uint32_t id_pfr1;
uint32_t id_dfr0;
- uint32_t pmceid0;
- uint32_t pmceid1;
+ uint64_t pmceid0;
+ uint64_t pmceid1;
uint32_t id_afr0;
uint32_t id_mmfr0;
uint32_t id_mmfr1;
@@ -839,8 +867,6 @@ struct ARMCPU {
uint64_t id_aa64dfr1;
uint64_t id_aa64afr0;
uint64_t id_aa64afr1;
- uint64_t id_aa64mmfr0;
- uint64_t id_aa64mmfr1;
uint32_t dbgdidr;
uint32_t clidr;
uint64_t mp_affinity; /* MP ID without feature bits */
@@ -884,6 +910,8 @@ static inline ARMCPU *arm_env_get_cpu(CPUARMState *env)
return container_of(env, ARMCPU, env);
}
+void arm_cpu_post_init(Object *obj);
+
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz);
#define ENV_GET_CPU(e) CPU(arm_env_get_cpu(e))
@@ -956,15 +984,42 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo,
void *puc);
/**
- * pmccntr_sync
+ * pmccntr_op_start/finish
+ * @env: CPUARMState
+ *
+ * Convert the counter in the PMCCNTR between its delta form (the typical mode
+ * when it's enabled) and the guest-visible value. These two calls must always
+ * surround any action which might affect the counter.
+ */
+void pmccntr_op_start(CPUARMState *env);
+void pmccntr_op_finish(CPUARMState *env);
+
+/**
+ * pmu_op_start/finish
+ * @env: CPUARMState
+ *
+ * Convert all PMU counters between their delta form (the typical mode when
+ * they are enabled) and the guest-visible values. These two calls must
+ * surround any action which might affect the counters.
+ */
+void pmu_op_start(CPUARMState *env);
+void pmu_op_finish(CPUARMState *env);
+
+/**
+ * Functions to register as EL change hooks for PMU mode filtering
+ */
+void pmu_pre_el_change(ARMCPU *cpu, void *ignored);
+void pmu_post_el_change(ARMCPU *cpu, void *ignored);
+
+/*
+ * get_pmceid
* @env: CPUARMState
+ * @which: which PMCEID register to return (0 or 1)
*
- * Synchronises the counter in the PMCCNTR. This must always be called twice,
- * once before any action that might affect the timer and again afterwards.
- * The function is used to swap the state of the register if required.
- * This only happens when not in user mode (!CONFIG_USER_ONLY)
+ * Return the PMCEID[01]_EL0 register values corresponding to the counters
+ * which are supported given the current configuration
*/
-void pmccntr_sync(CPUARMState *env);
+uint64_t get_pmceid(CPUARMState *env, unsigned which);
/* SCTLR bit meanings. Several bits have been reused in newer
* versions of the architecture; in that case we define constants
@@ -976,12 +1031,15 @@ void pmccntr_sync(CPUARMState *env);
#define SCTLR_A (1U << 1)
#define SCTLR_C (1U << 2)
#define SCTLR_W (1U << 3) /* up to v6; RAO in v7 */
-#define SCTLR_SA (1U << 3)
+#define SCTLR_nTLSMD_32 (1U << 3) /* v8.2-LSMAOC, AArch32 only */
+#define SCTLR_SA (1U << 3) /* AArch64 only */
#define SCTLR_P (1U << 4) /* up to v5; RAO in v6 and v7 */
+#define SCTLR_LSMAOE_32 (1U << 4) /* v8.2-LSMAOC, AArch32 only */
#define SCTLR_SA0 (1U << 4) /* v8 onward, AArch64 only */
#define SCTLR_D (1U << 5) /* up to v5; RAO in v6 */
#define SCTLR_CP15BEN (1U << 5) /* v7 onward */
#define SCTLR_L (1U << 6) /* up to v5; RAO in v6 and v7; RAZ in v8 */
+#define SCTLR_nAA (1U << 6) /* when v8.4-LSE is implemented */
#define SCTLR_B (1U << 7) /* up to v6; RAZ in v7 */
#define SCTLR_ITD (1U << 7) /* v8 onward */
#define SCTLR_S (1U << 8) /* up to v6; RAZ in v7 */
@@ -989,35 +1047,53 @@ void pmccntr_sync(CPUARMState *env);
#define SCTLR_R (1U << 9) /* up to v6; RAZ in v7 */
#define SCTLR_UMA (1U << 9) /* v8 onward, AArch64 only */
#define SCTLR_F (1U << 10) /* up to v6 */
-#define SCTLR_SW (1U << 10) /* v7 onward */
-#define SCTLR_Z (1U << 11)
+#define SCTLR_SW (1U << 10) /* v7, RES0 in v8 */
+#define SCTLR_Z (1U << 11) /* in v7, RES1 in v8 */
+#define SCTLR_EOS (1U << 11) /* v8.5-ExS */
#define SCTLR_I (1U << 12)
-#define SCTLR_V (1U << 13)
+#define SCTLR_V (1U << 13) /* AArch32 only */
+#define SCTLR_EnDB (1U << 13) /* v8.3, AArch64 only */
#define SCTLR_RR (1U << 14) /* up to v7 */
#define SCTLR_DZE (1U << 14) /* v8 onward, AArch64 only */
#define SCTLR_L4 (1U << 15) /* up to v6; RAZ in v7 */
#define SCTLR_UCT (1U << 15) /* v8 onward, AArch64 only */
#define SCTLR_DT (1U << 16) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWI (1U << 16) /* v8 onward */
-#define SCTLR_HA (1U << 17)
+#define SCTLR_HA (1U << 17) /* up to v7, RES0 in v8 */
#define SCTLR_BR (1U << 17) /* PMSA only */
#define SCTLR_IT (1U << 18) /* up to ??, RAO in v6 and v7 */
#define SCTLR_nTWE (1U << 18) /* v8 onward */
#define SCTLR_WXN (1U << 19)
#define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */
-#define SCTLR_UWXN (1U << 20) /* v7 onward */
-#define SCTLR_FI (1U << 21)
-#define SCTLR_U (1U << 22)
+#define SCTLR_UWXN (1U << 20) /* v7 onward, AArch32 only */
+#define SCTLR_FI (1U << 21) /* up to v7, v8 RES0 */
+#define SCTLR_IESB (1U << 21) /* v8.2-IESB, AArch64 only */
+#define SCTLR_U (1U << 22) /* up to v6, RAO in v7 */
+#define SCTLR_EIS (1U << 22) /* v8.5-ExS */
#define SCTLR_XP (1U << 23) /* up to v6; v7 onward RAO */
+#define SCTLR_SPAN (1U << 23) /* v8.1-PAN */
#define SCTLR_VE (1U << 24) /* up to v7 */
#define SCTLR_E0E (1U << 24) /* v8 onward, AArch64 only */
#define SCTLR_EE (1U << 25)
#define SCTLR_L2 (1U << 26) /* up to v6, RAZ in v7 */
#define SCTLR_UCI (1U << 26) /* v8 onward, AArch64 only */
-#define SCTLR_NMFI (1U << 27)
-#define SCTLR_TRE (1U << 28)
-#define SCTLR_AFE (1U << 29)
-#define SCTLR_TE (1U << 30)
+#define SCTLR_NMFI (1U << 27) /* up to v7, RAZ in v7VE and v8 */
+#define SCTLR_EnDA (1U << 27) /* v8.3, AArch64 only */
+#define SCTLR_TRE (1U << 28) /* AArch32 only */
+#define SCTLR_nTLSMD_64 (1U << 28) /* v8.2-LSMAOC, AArch64 only */
+#define SCTLR_AFE (1U << 29) /* AArch32 only */
+#define SCTLR_LSMAOE_64 (1U << 29) /* v8.2-LSMAOC, AArch64 only */
+#define SCTLR_TE (1U << 30) /* AArch32 only */
+#define SCTLR_EnIB (1U << 30) /* v8.3, AArch64 only */
+#define SCTLR_EnIA (1U << 31) /* v8.3, AArch64 only */
+#define SCTLR_BT0 (1ULL << 35) /* v8.5-BTI */
+#define SCTLR_BT1 (1ULL << 36) /* v8.5-BTI */
+#define SCTLR_ITFSB (1ULL << 37) /* v8.5-MemTag */
+#define SCTLR_TCF0 (3ULL << 38) /* v8.5-MemTag */
+#define SCTLR_TCF (3ULL << 40) /* v8.5-MemTag */
+#define SCTLR_ATA0 (1ULL << 42) /* v8.5-MemTag */
+#define SCTLR_ATA (1ULL << 43) /* v8.5-MemTag */
+#define SCTLR_DSSBS (1ULL << 44) /* v8.5 */
#define CPTR_TCPAC (1U << 31)
#define CPTR_TTA (1U << 20)
@@ -1027,7 +1103,8 @@ void pmccntr_sync(CPUARMState *env);
#define MDCR_EPMAD (1U << 21)
#define MDCR_EDAD (1U << 20)
-#define MDCR_SPME (1U << 17)
+#define MDCR_SPME (1U << 17) /* MDCR_EL3 */
+#define MDCR_HPMD (1U << 17) /* MDCR_EL2 */
#define MDCR_SDD (1U << 16)
#define MDCR_SPD (3U << 14)
#define MDCR_TDRA (1U << 11)
@@ -1037,6 +1114,7 @@ void pmccntr_sync(CPUARMState *env);
#define MDCR_HPME (1U << 7)
#define MDCR_TPM (1U << 6)
#define MDCR_TPMCR (1U << 5)
+#define MDCR_HPMN (0x1fU)
/* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */
#define SDCR_VALID_MASK (MDCR_EPMAD | MDCR_EDAD | MDCR_SPME | MDCR_SPD)
@@ -1249,7 +1327,7 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define HCR_TIDCP (1ULL << 20)
#define HCR_TACR (1ULL << 21)
#define HCR_TSW (1ULL << 22)
-#define HCR_TPC (1ULL << 23)
+#define HCR_TPCP (1ULL << 23)
#define HCR_TPU (1ULL << 24)
#define HCR_TTLB (1ULL << 25)
#define HCR_TVM (1ULL << 26)
@@ -1261,6 +1339,26 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define HCR_CD (1ULL << 32)
#define HCR_ID (1ULL << 33)
#define HCR_E2H (1ULL << 34)
+#define HCR_TLOR (1ULL << 35)
+#define HCR_TERR (1ULL << 36)
+#define HCR_TEA (1ULL << 37)
+#define HCR_MIOCNCE (1ULL << 38)
+#define HCR_APK (1ULL << 40)
+#define HCR_API (1ULL << 41)
+#define HCR_NV (1ULL << 42)
+#define HCR_NV1 (1ULL << 43)
+#define HCR_AT (1ULL << 44)
+#define HCR_NV2 (1ULL << 45)
+#define HCR_FWB (1ULL << 46)
+#define HCR_FIEN (1ULL << 47)
+#define HCR_TID4 (1ULL << 49)
+#define HCR_TICAB (1ULL << 50)
+#define HCR_TOCU (1ULL << 52)
+#define HCR_TTLBIS (1ULL << 54)
+#define HCR_TTLBOS (1ULL << 55)
+#define HCR_ATA (1ULL << 56)
+#define HCR_DCT (1ULL << 57)
+
/*
* When we actually implement ARMv8.1-VHE we should add HCR_E2H to
* HCR_MASK and then clear it again if the feature bit is not set in
@@ -1282,8 +1380,16 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define SCR_ST (1U << 11)
#define SCR_TWI (1U << 12)
#define SCR_TWE (1U << 13)
-#define SCR_AARCH32_MASK (0x3fff & ~(SCR_RW | SCR_ST))
-#define SCR_AARCH64_MASK (0x3fff & ~SCR_NET)
+#define SCR_TLOR (1U << 14)
+#define SCR_TERR (1U << 15)
+#define SCR_APK (1U << 16)
+#define SCR_API (1U << 17)
+#define SCR_EEL2 (1U << 18)
+#define SCR_EASE (1U << 19)
+#define SCR_NMEA (1U << 20)
+#define SCR_FIEN (1U << 21)
+#define SCR_ENSCXT (1U << 25)
+#define SCR_ATA (1U << 26)
/* Return the current FPSCR value. */
uint32_t vfp_get_fpscr(CPUARMState *env);
@@ -1520,6 +1626,15 @@ FIELD(ID_ISAR6, FHM, 8, 4)
FIELD(ID_ISAR6, SB, 12, 4)
FIELD(ID_ISAR6, SPECRES, 16, 4)
+FIELD(ID_MMFR4, SPECSEI, 0, 4)
+FIELD(ID_MMFR4, AC2, 4, 4)
+FIELD(ID_MMFR4, XNX, 8, 4)
+FIELD(ID_MMFR4, CNP, 12, 4)
+FIELD(ID_MMFR4, HPDS, 16, 4)
+FIELD(ID_MMFR4, LSM, 20, 4)
+FIELD(ID_MMFR4, CCIDX, 24, 4)
+FIELD(ID_MMFR4, EVT, 28, 4)
+
FIELD(ID_AA64ISAR0, AES, 4, 4)
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
@@ -1557,6 +1672,37 @@ FIELD(ID_AA64PFR0, GIC, 24, 4)
FIELD(ID_AA64PFR0, RAS, 28, 4)
FIELD(ID_AA64PFR0, SVE, 32, 4)
+FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
+FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
+FIELD(ID_AA64MMFR0, BIGEND, 8, 4)
+FIELD(ID_AA64MMFR0, SNSMEM, 12, 4)
+FIELD(ID_AA64MMFR0, BIGENDEL0, 16, 4)
+FIELD(ID_AA64MMFR0, TGRAN16, 20, 4)
+FIELD(ID_AA64MMFR0, TGRAN64, 24, 4)
+FIELD(ID_AA64MMFR0, TGRAN4, 28, 4)
+FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
+FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
+FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
+FIELD(ID_AA64MMFR0, EXS, 44, 4)
+
+FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
+FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
+FIELD(ID_AA64MMFR1, VH, 8, 4)
+FIELD(ID_AA64MMFR1, HPDS, 12, 4)
+FIELD(ID_AA64MMFR1, LO, 16, 4)
+FIELD(ID_AA64MMFR1, PAN, 20, 4)
+FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
+FIELD(ID_AA64MMFR1, XNX, 28, 4)
+
+FIELD(ID_DFR0, COPDBG, 0, 4)
+FIELD(ID_DFR0, COPSDBG, 4, 4)
+FIELD(ID_DFR0, MMAPDBG, 8, 4)
+FIELD(ID_DFR0, COPTRC, 12, 4)
+FIELD(ID_DFR0, MMAPTRC, 16, 4)
+FIELD(ID_DFR0, MPROFDBG, 20, 4)
+FIELD(ID_DFR0, PERFMON, 24, 4)
+FIELD(ID_DFR0, TRACEFILT, 28, 4)
+
QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK);
/* If adding a feature bit which corresponds to a Linux ELF
@@ -1670,6 +1816,14 @@ static inline bool arm_is_secure(CPUARMState *env)
}
#endif
+/**
+ * arm_hcr_el2_eff(): Return the effective value of HCR_EL2.
+ * E.g. when in secure state, fields in HCR_EL2 are suppressed,
+ * "for all purposes other than a direct read or write access of HCR_EL2."
+ * Not included here is HCR_RW.
+ */
+uint64_t arm_hcr_el2_eff(CPUARMState *env);
+
/* Return true if the specified exception level is running in AArch64 state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{
@@ -2355,54 +2509,6 @@ bool write_cpustate_to_list(ARMCPU *cpu);
# define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif
-/**
- * arm_hcr_el2_imo(): Return the effective value of HCR_EL2.IMO.
- * Depending on the values of HCR_EL2.E2H and TGE, this may be
- * "behaves as 1 for all purposes other than direct read/write" or
- * "behaves as 0 for all purposes other than direct read/write"
- */
-static inline bool arm_hcr_el2_imo(CPUARMState *env)
-{
- switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
- case HCR_TGE:
- return true;
- case HCR_TGE | HCR_E2H:
- return false;
- default:
- return env->cp15.hcr_el2 & HCR_IMO;
- }
-}
-
-/**
- * arm_hcr_el2_fmo(): Return the effective value of HCR_EL2.FMO.
- */
-static inline bool arm_hcr_el2_fmo(CPUARMState *env)
-{
- switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
- case HCR_TGE:
- return true;
- case HCR_TGE | HCR_E2H:
- return false;
- default:
- return env->cp15.hcr_el2 & HCR_FMO;
- }
-}
-
-/**
- * arm_hcr_el2_amo(): Return the effective value of HCR_EL2.AMO.
- */
-static inline bool arm_hcr_el2_amo(CPUARMState *env)
-{
- switch (env->cp15.hcr_el2 & (HCR_TGE | HCR_E2H)) {
- case HCR_TGE:
- return true;
- case HCR_TGE | HCR_E2H:
- return false;
- default:
- return env->cp15.hcr_el2 & HCR_AMO;
- }
-}
-
static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
unsigned int target_el)
{
@@ -2411,6 +2517,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
bool secure = arm_is_secure(env);
bool pstate_unmasked;
int8_t unmasked = 0;
+ uint64_t hcr_el2;
/* Don't take exceptions if they target a lower EL.
* This check should catch any exceptions that would not be taken but left
@@ -2420,6 +2527,8 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
return false;
}
+ hcr_el2 = arm_hcr_el2_eff(env);
+
switch (excp_idx) {
case EXCP_FIQ:
pstate_unmasked = !(env->daif & PSTATE_F);
@@ -2430,13 +2539,13 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
break;
case EXCP_VFIQ:
- if (secure || !arm_hcr_el2_fmo(env) || (env->cp15.hcr_el2 & HCR_TGE)) {
+ if (secure || !(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
/* VFIQs are only taken when hypervized and non-secure. */
return false;
}
return !(env->daif & PSTATE_F);
case EXCP_VIRQ:
- if (secure || !arm_hcr_el2_imo(env) || (env->cp15.hcr_el2 & HCR_TGE)) {
+ if (secure || !(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
/* VIRQs are only taken when hypervized and non-secure. */
return false;
}
@@ -2475,7 +2584,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
* to the CPSR.F setting otherwise we further assess the state
* below.
*/
- hcr = arm_hcr_el2_fmo(env);
+ hcr = hcr_el2 & HCR_FMO;
scr = (env->cp15.scr_el3 & SCR_FIQ);
/* When EL3 is 32-bit, the SCR.FW bit controls whether the
@@ -2492,7 +2601,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
* when setting the target EL, so it does not have a further
* affect here.
*/
- hcr = arm_hcr_el2_imo(env);
+ hcr = hcr_el2 & HCR_IMO;
scr = false;
break;
default:
@@ -2683,54 +2792,23 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
}
/* Return the MMU index for a v7M CPU in the specified security and
- * privilege state
+ * privilege state.
*/
-static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
- bool secstate,
- bool priv)
-{
- ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
-
- if (priv) {
- mmu_idx |= ARM_MMU_IDX_M_PRIV;
- }
-
- if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
- mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
- }
-
- if (secstate) {
- mmu_idx |= ARM_MMU_IDX_M_S;
- }
-
- return mmu_idx;
-}
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
+ bool secstate, bool priv);
/* Return the MMU index for a v7M CPU in the specified security state */
-static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env,
- bool secstate)
-{
- bool priv = arm_current_el(env) != 0;
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
- return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
-}
-
-/* Determine the current mmu_idx to use for normal loads/stores */
-static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
-{
- int el = arm_current_el(env);
-
- if (arm_feature(env, ARM_FEATURE_M)) {
- ARMMMUIdx mmu_idx = arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
-
- return arm_to_core_mmu_idx(mmu_idx);
- }
-
- if (el < 2 && arm_is_secure_below_el3(env)) {
- return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0 + el);
- }
- return el;
-}
+/**
+ * cpu_mmu_index:
+ * @env: The cpu environment
+ * @ifetch: True for code access, false for data access.
+ *
+ * Return the core mmu index for the current translation regime.
+ * This function is used by generic TCG code paths.
+ */
+int cpu_mmu_index(CPUARMState *env, bool ifetch);
/* Indexes used when registering address spaces with cpu_address_space_init */
typedef enum ARMASIdx {
@@ -2922,102 +3000,40 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
* We put flags which are shared between 32 and 64 bit mode at the top
* of the word, and flags which apply to only one mode at the bottom.
*/
-#define ARM_TBFLAG_AARCH64_STATE_SHIFT 31
-#define ARM_TBFLAG_AARCH64_STATE_MASK (1U << ARM_TBFLAG_AARCH64_STATE_SHIFT)
-#define ARM_TBFLAG_MMUIDX_SHIFT 28
-#define ARM_TBFLAG_MMUIDX_MASK (0x7 << ARM_TBFLAG_MMUIDX_SHIFT)
-#define ARM_TBFLAG_SS_ACTIVE_SHIFT 27
-#define ARM_TBFLAG_SS_ACTIVE_MASK (1 << ARM_TBFLAG_SS_ACTIVE_SHIFT)
-#define ARM_TBFLAG_PSTATE_SS_SHIFT 26
-#define ARM_TBFLAG_PSTATE_SS_MASK (1 << ARM_TBFLAG_PSTATE_SS_SHIFT)
+FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1)
+FIELD(TBFLAG_ANY, MMUIDX, 28, 3)
+FIELD(TBFLAG_ANY, SS_ACTIVE, 27, 1)
+FIELD(TBFLAG_ANY, PSTATE_SS, 26, 1)
/* Target EL if we take a floating-point-disabled exception */
-#define ARM_TBFLAG_FPEXC_EL_SHIFT 24
-#define ARM_TBFLAG_FPEXC_EL_MASK (0x3 << ARM_TBFLAG_FPEXC_EL_SHIFT)
+FIELD(TBFLAG_ANY, FPEXC_EL, 24, 2)
+FIELD(TBFLAG_ANY, BE_DATA, 23, 1)
/* Bit usage when in AArch32 state: */
-#define ARM_TBFLAG_THUMB_SHIFT 0
-#define ARM_TBFLAG_THUMB_MASK (1 << ARM_TBFLAG_THUMB_SHIFT)
-#define ARM_TBFLAG_VECLEN_SHIFT 1
-#define ARM_TBFLAG_VECLEN_MASK (0x7 << ARM_TBFLAG_VECLEN_SHIFT)
-#define ARM_TBFLAG_VECSTRIDE_SHIFT 4
-#define ARM_TBFLAG_VECSTRIDE_MASK (0x3 << ARM_TBFLAG_VECSTRIDE_SHIFT)
-#define ARM_TBFLAG_VFPEN_SHIFT 7
-#define ARM_TBFLAG_VFPEN_MASK (1 << ARM_TBFLAG_VFPEN_SHIFT)
-#define ARM_TBFLAG_CONDEXEC_SHIFT 8
-#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
-#define ARM_TBFLAG_SCTLR_B_SHIFT 16
-#define ARM_TBFLAG_SCTLR_B_MASK (1 << ARM_TBFLAG_SCTLR_B_SHIFT)
+FIELD(TBFLAG_A32, THUMB, 0, 1)
+FIELD(TBFLAG_A32, VECLEN, 1, 3)
+FIELD(TBFLAG_A32, VECSTRIDE, 4, 2)
+FIELD(TBFLAG_A32, VFPEN, 7, 1)
+FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
+FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
/* We store the bottom two bits of the CPAR as TB flags and handle
* checks on the other bits at runtime
*/
-#define ARM_TBFLAG_XSCALE_CPAR_SHIFT 17
-#define ARM_TBFLAG_XSCALE_CPAR_MASK (3 << ARM_TBFLAG_XSCALE_CPAR_SHIFT)
+FIELD(TBFLAG_A32, XSCALE_CPAR, 17, 2)
/* Indicates whether cp register reads and writes by guest code should access
* the secure or nonsecure bank of banked registers; note that this is not
* the same thing as the current security state of the processor!
*/
-#define ARM_TBFLAG_NS_SHIFT 19
-#define ARM_TBFLAG_NS_MASK (1 << ARM_TBFLAG_NS_SHIFT)
-#define ARM_TBFLAG_BE_DATA_SHIFT 20
-#define ARM_TBFLAG_BE_DATA_MASK (1 << ARM_TBFLAG_BE_DATA_SHIFT)
+FIELD(TBFLAG_A32, NS, 19, 1)
/* For M profile only, Handler (ie not Thread) mode */
-#define ARM_TBFLAG_HANDLER_SHIFT 21
-#define ARM_TBFLAG_HANDLER_MASK (1 << ARM_TBFLAG_HANDLER_SHIFT)
+FIELD(TBFLAG_A32, HANDLER, 21, 1)
/* For M profile only, whether we should generate stack-limit checks */
-#define ARM_TBFLAG_STACKCHECK_SHIFT 22
-#define ARM_TBFLAG_STACKCHECK_MASK (1 << ARM_TBFLAG_STACKCHECK_SHIFT)
+FIELD(TBFLAG_A32, STACKCHECK, 22, 1)
/* Bit usage when in AArch64 state */
-#define ARM_TBFLAG_TBI0_SHIFT 0 /* TBI0 for EL0/1 or TBI for EL2/3 */
-#define ARM_TBFLAG_TBI0_MASK (0x1ull << ARM_TBFLAG_TBI0_SHIFT)
-#define ARM_TBFLAG_TBI1_SHIFT 1 /* TBI1 for EL0/1 */
-#define ARM_TBFLAG_TBI1_MASK (0x1ull << ARM_TBFLAG_TBI1_SHIFT)
-#define ARM_TBFLAG_SVEEXC_EL_SHIFT 2
-#define ARM_TBFLAG_SVEEXC_EL_MASK (0x3 << ARM_TBFLAG_SVEEXC_EL_SHIFT)
-#define ARM_TBFLAG_ZCR_LEN_SHIFT 4
-#define ARM_TBFLAG_ZCR_LEN_MASK (0xf << ARM_TBFLAG_ZCR_LEN_SHIFT)
-
-/* some convenience accessor macros */
-#define ARM_TBFLAG_AARCH64_STATE(F) \
- (((F) & ARM_TBFLAG_AARCH64_STATE_MASK) >> ARM_TBFLAG_AARCH64_STATE_SHIFT)
-#define ARM_TBFLAG_MMUIDX(F) \
- (((F) & ARM_TBFLAG_MMUIDX_MASK) >> ARM_TBFLAG_MMUIDX_SHIFT)
-#define ARM_TBFLAG_SS_ACTIVE(F) \
- (((F) & ARM_TBFLAG_SS_ACTIVE_MASK) >> ARM_TBFLAG_SS_ACTIVE_SHIFT)
-#define ARM_TBFLAG_PSTATE_SS(F) \
- (((F) & ARM_TBFLAG_PSTATE_SS_MASK) >> ARM_TBFLAG_PSTATE_SS_SHIFT)
-#define ARM_TBFLAG_FPEXC_EL(F) \
- (((F) & ARM_TBFLAG_FPEXC_EL_MASK) >> ARM_TBFLAG_FPEXC_EL_SHIFT)
-#define ARM_TBFLAG_THUMB(F) \
- (((F) & ARM_TBFLAG_THUMB_MASK) >> ARM_TBFLAG_THUMB_SHIFT)
-#define ARM_TBFLAG_VECLEN(F) \
- (((F) & ARM_TBFLAG_VECLEN_MASK) >> ARM_TBFLAG_VECLEN_SHIFT)
-#define ARM_TBFLAG_VECSTRIDE(F) \
- (((F) & ARM_TBFLAG_VECSTRIDE_MASK) >> ARM_TBFLAG_VECSTRIDE_SHIFT)
-#define ARM_TBFLAG_VFPEN(F) \
- (((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
-#define ARM_TBFLAG_CONDEXEC(F) \
- (((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
-#define ARM_TBFLAG_SCTLR_B(F) \
- (((F) & ARM_TBFLAG_SCTLR_B_MASK) >> ARM_TBFLAG_SCTLR_B_SHIFT)
-#define ARM_TBFLAG_XSCALE_CPAR(F) \
- (((F) & ARM_TBFLAG_XSCALE_CPAR_MASK) >> ARM_TBFLAG_XSCALE_CPAR_SHIFT)
-#define ARM_TBFLAG_NS(F) \
- (((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT)
-#define ARM_TBFLAG_BE_DATA(F) \
- (((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT)
-#define ARM_TBFLAG_HANDLER(F) \
- (((F) & ARM_TBFLAG_HANDLER_MASK) >> ARM_TBFLAG_HANDLER_SHIFT)
-#define ARM_TBFLAG_STACKCHECK(F) \
- (((F) & ARM_TBFLAG_STACKCHECK_MASK) >> ARM_TBFLAG_STACKCHECK_SHIFT)
-#define ARM_TBFLAG_TBI0(F) \
- (((F) & ARM_TBFLAG_TBI0_MASK) >> ARM_TBFLAG_TBI0_SHIFT)
-#define ARM_TBFLAG_TBI1(F) \
- (((F) & ARM_TBFLAG_TBI1_MASK) >> ARM_TBFLAG_TBI1_SHIFT)
-#define ARM_TBFLAG_SVEEXC_EL(F) \
- (((F) & ARM_TBFLAG_SVEEXC_EL_MASK) >> ARM_TBFLAG_SVEEXC_EL_SHIFT)
-#define ARM_TBFLAG_ZCR_LEN(F) \
- (((F) & ARM_TBFLAG_ZCR_LEN_MASK) >> ARM_TBFLAG_ZCR_LEN_SHIFT)
+FIELD(TBFLAG_A64, TBII, 0, 2)
+FIELD(TBFLAG_A64, SVEEXC_EL, 2, 2)
+FIELD(TBFLAG_A64, ZCR_LEN, 4, 4)
+FIELD(TBFLAG_A64, PAUTH_ACTIVE, 8, 1)
static inline bool bswap_code(bool sctlr_b)
{
@@ -3050,41 +3066,6 @@ static inline bool arm_cpu_bswap_data(CPUARMState *env)
}
#endif
-#ifndef CONFIG_USER_ONLY
-/**
- * arm_regime_tbi0:
- * @env: CPUARMState
- * @mmu_idx: MMU index indicating required translation regime
- *
- * Extracts the TBI0 value from the appropriate TCR for the current EL
- *
- * Returns: the TBI0 value.
- */
-uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx);
-
-/**
- * arm_regime_tbi1:
- * @env: CPUARMState
- * @mmu_idx: MMU index indicating required translation regime
- *
- * Extracts the TBI1 value from the appropriate TCR for the current EL
- *
- * Returns: the TBI1 value.
- */
-uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx);
-#else
-/* We can't handle tagged addresses properly in user-only mode */
-static inline uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx)
-{
- return 0;
-}
-
-static inline uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx)
-{
- return 0;
-}
-#endif
-
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags);
@@ -3302,6 +3283,21 @@ static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0;
}
+static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
+{
+ /*
+ * Note that while QEMU will only implement the architected algorithm
+ * QARMA, and thus APA+GPA, the host cpu for kvm may use implementation
+ * defined algorithms, and thus API+GPI, and this predicate controls
+ * migration of the 128-bit keys.
+ */
+ return (id->id_aa64isar1 &
+ (FIELD_DP64(0, ID_AA64ISAR1, APA, 0xf) |
+ FIELD_DP64(0, ID_AA64ISAR1, API, 0xf) |
+ FIELD_DP64(0, ID_AA64ISAR1, GPA, 0xf) |
+ FIELD_DP64(0, ID_AA64ISAR1, GPI, 0xf))) != 0;
+}
+
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically wrt FP16. */
@@ -3318,6 +3314,11 @@ static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
}
+static inline bool isar_feature_aa64_lor(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, LO) != 0;
+}
+
/*
* Forward to the above feature tests given an ARMCPU pointer.
*/
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 873f059bf2..e9bc461c36 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -138,10 +138,8 @@ static void aarch64_a57_initfn(Object *obj)
cpu->isar.id_isar6 = 0;
cpu->isar.id_aa64pfr0 = 0x00002222;
cpu->id_aa64dfr0 = 0x10305106;
- cpu->pmceid0 = 0x00000000;
- cpu->pmceid1 = 0x00000000;
cpu->isar.id_aa64isar0 = 0x00011120;
- cpu->id_aa64mmfr0 = 0x00001124;
+ cpu->isar.id_aa64mmfr0 = 0x00001124;
cpu->dbgdidr = 0x3516d000;
cpu->clidr = 0x0a200023;
cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
@@ -195,7 +193,7 @@ static void aarch64_a53_initfn(Object *obj)
cpu->isar.id_aa64pfr0 = 0x00002222;
cpu->id_aa64dfr0 = 0x10305106;
cpu->isar.id_aa64isar0 = 0x00011120;
- cpu->id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */
+ cpu->isar.id_aa64mmfr0 = 0x00001122; /* 40 bit physical addr */
cpu->dbgdidr = 0x3516d000;
cpu->clidr = 0x0a200023;
cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
@@ -246,10 +244,8 @@ static void aarch64_a72_initfn(Object *obj)
cpu->isar.id_isar5 = 0x00011121;
cpu->isar.id_aa64pfr0 = 0x00002222;
cpu->id_aa64dfr0 = 0x10305106;
- cpu->pmceid0 = 0x00000000;
- cpu->pmceid1 = 0x00000000;
cpu->isar.id_aa64isar0 = 0x00011120;
- cpu->id_aa64mmfr0 = 0x00001124;
+ cpu->isar.id_aa64mmfr0 = 0x00001124;
cpu->dbgdidr = 0x3516d000;
cpu->clidr = 0x0a200023;
cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
@@ -285,6 +281,38 @@ static void cpu_max_set_sve_vq(Object *obj, Visitor *v, const char *name,
error_propagate(errp, err);
}
+#ifdef CONFIG_USER_ONLY
+static void cpu_max_get_packey(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ const uint64_t *bit = opaque;
+ bool enabled = (cpu->env.cp15.sctlr_el[1] & *bit) != 0;
+
+ visit_type_bool(v, name, &enabled, errp);
+}
+
+static void cpu_max_set_packey(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ ARMCPU *cpu = ARM_CPU(obj);
+ Error *err = NULL;
+ const uint64_t *bit = opaque;
+ bool enabled;
+
+ visit_type_bool(v, name, &enabled, errp);
+
+ if (!err) {
+ if (enabled) {
+ cpu->env.cp15.sctlr_el[1] |= *bit;
+ } else {
+ cpu->env.cp15.sctlr_el[1] &= ~*bit;
+ }
+ }
+ error_propagate(errp, err);
+}
+#endif
+
/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
* otherwise, a CPU with as many features enabled as our emulation supports.
* The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
@@ -316,6 +344,10 @@ static void aarch64_max_initfn(Object *obj)
t = cpu->isar.id_aa64isar1;
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
+ t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */
+ t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
+ t = FIELD_DP64(t, ID_AA64ISAR1, GPA, 1);
+ t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0);
cpu->isar.id_aa64isar1 = t;
t = cpu->isar.id_aa64pfr0;
@@ -324,6 +356,11 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1);
cpu->isar.id_aa64pfr0 = t;
+ t = cpu->isar.id_aa64mmfr1;
+ t = FIELD_DP64(t, ID_AA64MMFR1, HPDS, 1); /* HPD */
+ t = FIELD_DP64(t, ID_AA64MMFR1, LO, 1);
+ cpu->isar.id_aa64mmfr1 = t;
+
/* Replicate the same data to the 32-bit id registers. */
u = cpu->isar.id_isar5;
u = FIELD_DP32(u, ID_ISAR5, AES, 2); /* AES + PMULL */
@@ -351,6 +388,34 @@ static void aarch64_max_initfn(Object *obj)
*/
cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
cpu->dcz_blocksize = 7; /* 512 bytes */
+
+ /*
+ * Note that Linux will enable enable all of the keys at once.
+ * But doing it this way will allow experimentation beyond that.
+ */
+ {
+ static const uint64_t apia_bit = SCTLR_EnIA;
+ static const uint64_t apib_bit = SCTLR_EnIB;
+ static const uint64_t apda_bit = SCTLR_EnDA;
+ static const uint64_t apdb_bit = SCTLR_EnDB;
+
+ object_property_add(obj, "apia", "bool", cpu_max_get_packey,
+ cpu_max_set_packey, NULL,
+ (void *)&apia_bit, &error_fatal);
+ object_property_add(obj, "apib", "bool", cpu_max_get_packey,
+ cpu_max_set_packey, NULL,
+ (void *)&apib_bit, &error_fatal);
+ object_property_add(obj, "apda", "bool", cpu_max_get_packey,
+ cpu_max_set_packey, NULL,
+ (void *)&apda_bit, &error_fatal);
+ object_property_add(obj, "apdb", "bool", cpu_max_get_packey,
+ cpu_max_set_packey, NULL,
+ (void *)&apdb_bit, &error_fatal);
+
+ /* Enable all PAC keys by default. */
+ cpu->env.cp15.sctlr_el[1] |= SCTLR_EnIA | SCTLR_EnIB;
+ cpu->env.cp15.sctlr_el[1] |= SCTLR_EnDA | SCTLR_EnDB;
+ }
#endif
cpu->sve_max_vq = ARM_MAX_VQ;
@@ -359,11 +424,11 @@ static void aarch64_max_initfn(Object *obj)
}
}
-typedef struct ARMCPUInfo {
+struct ARMCPUInfo {
const char *name;
void (*initfn)(Object *obj);
void (*class_init)(ObjectClass *oc, void *data);
-} ARMCPUInfo;
+};
static const ARMCPUInfo aarch64_cpus[] = {
{ .name = "cortex-a57", .initfn = aarch64_a57_initfn },
@@ -447,14 +512,30 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_arch_name = aarch64_gdb_arch_name;
}
+static void aarch64_cpu_instance_init(Object *obj)
+{
+ ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj);
+
+ acc->info->initfn(obj);
+ arm_cpu_post_init(obj);
+}
+
+static void cpu_register_class_init(ObjectClass *oc, void *data)
+{
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
+
+ acc->info = data;
+}
+
static void aarch64_cpu_register(const ARMCPUInfo *info)
{
TypeInfo type_info = {
.parent = TYPE_AARCH64_CPU,
.instance_size = sizeof(ARMCPU),
- .instance_init = info->initfn,
+ .instance_init = aarch64_cpu_instance_init,
.class_size = sizeof(ARMCPUClass),
- .class_init = info->class_init,
+ .class_init = info->class_init ?: cpu_register_class_init,
+ .class_data = (void *)info,
};
type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name);
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 61799d20e1..101fa6d3ea 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -887,6 +887,161 @@ uint32_t HELPER(advsimd_f16touinth)(uint32_t a, void *fpstp)
return float16_to_uint16(a, fpst);
}
+static int el_from_spsr(uint32_t spsr)
+{
+ /* Return the exception level that this SPSR is requesting a return to,
+ * or -1 if it is invalid (an illegal return)
+ */
+ if (spsr & PSTATE_nRW) {
+ switch (spsr & CPSR_M) {
+ case ARM_CPU_MODE_USR:
+ return 0;
+ case ARM_CPU_MODE_HYP:
+ return 2;
+ case ARM_CPU_MODE_FIQ:
+ case ARM_CPU_MODE_IRQ:
+ case ARM_CPU_MODE_SVC:
+ case ARM_CPU_MODE_ABT:
+ case ARM_CPU_MODE_UND:
+ case ARM_CPU_MODE_SYS:
+ return 1;
+ case ARM_CPU_MODE_MON:
+ /* Returning to Mon from AArch64 is never possible,
+ * so this is an illegal return.
+ */
+ default:
+ return -1;
+ }
+ } else {
+ if (extract32(spsr, 1, 1)) {
+ /* Return with reserved M[1] bit set */
+ return -1;
+ }
+ if (extract32(spsr, 0, 4) == 1) {
+ /* return to EL0 with M[0] bit set */
+ return -1;
+ }
+ return extract32(spsr, 2, 2);
+ }
+}
+
+void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
+{
+ int cur_el = arm_current_el(env);
+ unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
+ uint32_t spsr = env->banked_spsr[spsr_idx];
+ int new_el;
+ bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
+
+ aarch64_save_sp(env, cur_el);
+
+ arm_clear_exclusive(env);
+
+ /* We must squash the PSTATE.SS bit to zero unless both of the
+ * following hold:
+ * 1. debug exceptions are currently disabled
+ * 2. singlestep will be active in the EL we return to
+ * We check 1 here and 2 after we've done the pstate/cpsr write() to
+ * transition to the EL we're going to.
+ */
+ if (arm_generate_debug_exceptions(env)) {
+ spsr &= ~PSTATE_SS;
+ }
+
+ new_el = el_from_spsr(spsr);
+ if (new_el == -1) {
+ goto illegal_return;
+ }
+ if (new_el > cur_el
+ || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
+ /* Disallow return to an EL which is unimplemented or higher
+ * than the current one.
+ */
+ goto illegal_return;
+ }
+
+ if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) {
+ /* Return to an EL which is configured for a different register width */
+ goto illegal_return;
+ }
+
+ if (new_el == 2 && arm_is_secure_below_el3(env)) {
+ /* Return to the non-existent secure-EL2 */
+ goto illegal_return;
+ }
+
+ if (new_el == 1 && (arm_hcr_el2_eff(env) & HCR_TGE)) {
+ goto illegal_return;
+ }
+
+ qemu_mutex_lock_iothread();
+ arm_call_pre_el_change_hook(arm_env_get_cpu(env));
+ qemu_mutex_unlock_iothread();
+
+ if (!return_to_aa64) {
+ env->aarch64 = 0;
+ /* We do a raw CPSR write because aarch64_sync_64_to_32()
+ * will sort the register banks out for us, and we've already
+ * caught all the bad-mode cases in el_from_spsr().
+ */
+ cpsr_write(env, spsr, ~0, CPSRWriteRaw);
+ if (!arm_singlestep_active(env)) {
+ env->uncached_cpsr &= ~PSTATE_SS;
+ }
+ aarch64_sync_64_to_32(env);
+
+ if (spsr & CPSR_T) {
+ env->regs[15] = new_pc & ~0x1;
+ } else {
+ env->regs[15] = new_pc & ~0x3;
+ }
+ qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
+ "AArch32 EL%d PC 0x%" PRIx32 "\n",
+ cur_el, new_el, env->regs[15]);
+ } else {
+ env->aarch64 = 1;
+ pstate_write(env, spsr);
+ if (!arm_singlestep_active(env)) {
+ env->pstate &= ~PSTATE_SS;
+ }
+ aarch64_restore_sp(env, new_el);
+ env->pc = new_pc;
+ qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
+ "AArch64 EL%d PC 0x%" PRIx64 "\n",
+ cur_el, new_el, env->pc);
+ }
+ /*
+ * Note that cur_el can never be 0. If new_el is 0, then
+ * el0_a64 is return_to_aa64, else el0_a64 is ignored.
+ */
+ aarch64_sve_change_el(env, cur_el, new_el, return_to_aa64);
+
+ qemu_mutex_lock_iothread();
+ arm_call_el_change_hook(arm_env_get_cpu(env));
+ qemu_mutex_unlock_iothread();
+
+ return;
+
+illegal_return:
+ /* Illegal return events of various kinds have architecturally
+ * mandated behaviour:
+ * restore NZCV and DAIF from SPSR_ELx
+ * set PSTATE.IL
+ * restore PC from ELR_ELx
+ * no change to exception level, execution state or stack pointer
+ */
+ env->pstate |= PSTATE_IL;
+ env->pc = new_pc;
+ spsr &= PSTATE_NZCV | PSTATE_DAIF;
+ spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
+ pstate_write(env, spsr);
+ if (!arm_singlestep_active(env)) {
+ env->pstate &= ~PSTATE_SS;
+ }
+ qemu_log_mask(LOG_GUEST_ERROR, "Illegal exception return at EL%d: "
+ "resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc);
+}
+
/*
* Square Root and Reciprocal square root
*/
diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h
index 9d3a907049..aff8d6c9f3 100644
--- a/target/arm/helper-a64.h
+++ b/target/arm/helper-a64.h
@@ -85,3 +85,17 @@ DEF_HELPER_2(advsimd_rinth, f16, f16, ptr)
DEF_HELPER_2(advsimd_f16tosinth, i32, f16, ptr)
DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr)
DEF_HELPER_2(sqrt_f16, f16, f16, ptr)
+
+DEF_HELPER_2(exception_return, void, env, i64)
+
+DEF_HELPER_FLAGS_3(pacia, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(pacib, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(pacda, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(pacdb, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(pacga, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(autia, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(autib, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(autda, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64)
+DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0da1424f72..92666e5208 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -15,6 +15,7 @@
#include "arm_ldst.h"
#include <zlib.h> /* For crc32 */
#include "exec/semihost.h"
+#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "fpu/softfloat.h"
#include "qemu/range.h"
@@ -448,7 +449,7 @@ static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri,
int el = arm_current_el(env);
bool mdcr_el2_tdosa = (env->cp15.mdcr_el2 & MDCR_TDOSA) ||
(env->cp15.mdcr_el2 & MDCR_TDE) ||
- (env->cp15.hcr_el2 & HCR_TGE);
+ (arm_hcr_el2_eff(env) & HCR_TGE);
if (el < 2 && mdcr_el2_tdosa && !arm_is_secure_below_el3(env)) {
return CP_ACCESS_TRAP_EL2;
@@ -468,7 +469,7 @@ static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
int el = arm_current_el(env);
bool mdcr_el2_tdra = (env->cp15.mdcr_el2 & MDCR_TDRA) ||
(env->cp15.mdcr_el2 & MDCR_TDE) ||
- (env->cp15.hcr_el2 & HCR_TGE);
+ (arm_hcr_el2_eff(env) & HCR_TGE);
if (el < 2 && mdcr_el2_tdra && !arm_is_secure_below_el3(env)) {
return CP_ACCESS_TRAP_EL2;
@@ -488,7 +489,7 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
int el = arm_current_el(env);
bool mdcr_el2_tda = (env->cp15.mdcr_el2 & MDCR_TDA) ||
(env->cp15.mdcr_el2 & MDCR_TDE) ||
- (env->cp15.hcr_el2 & HCR_TGE);
+ (arm_hcr_el2_eff(env) & HCR_TGE);
if (el < 2 && mdcr_el2_tda && !arm_is_secure_below_el3(env)) {
return CP_ACCESS_TRAP_EL2;
@@ -976,10 +977,29 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
/* Definitions for the PMU registers */
#define PMCRN_MASK 0xf800
#define PMCRN_SHIFT 11
+#define PMCRDP 0x10
#define PMCRD 0x8
#define PMCRC 0x4
+#define PMCRP 0x2
#define PMCRE 0x1
+#define PMXEVTYPER_P 0x80000000
+#define PMXEVTYPER_U 0x40000000
+#define PMXEVTYPER_NSK 0x20000000
+#define PMXEVTYPER_NSU 0x10000000
+#define PMXEVTYPER_NSH 0x08000000
+#define PMXEVTYPER_M 0x04000000
+#define PMXEVTYPER_MT 0x02000000
+#define PMXEVTYPER_EVTCOUNT 0x0000ffff
+#define PMXEVTYPER_MASK (PMXEVTYPER_P | PMXEVTYPER_U | PMXEVTYPER_NSK | \
+ PMXEVTYPER_NSU | PMXEVTYPER_NSH | \
+ PMXEVTYPER_M | PMXEVTYPER_MT | \
+ PMXEVTYPER_EVTCOUNT)
+
+#define PMCCFILTR 0xf8000000
+#define PMCCFILTR_M PMXEVTYPER_M
+#define PMCCFILTR_EL0 (PMCCFILTR | PMCCFILTR_M)
+
static inline uint32_t pmu_num_counters(CPUARMState *env)
{
return (env->cp15.c9_pmcr & PMCRN_MASK) >> PMCRN_SHIFT;
@@ -991,6 +1011,128 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
return (1 << 31) | ((1 << pmu_num_counters(env)) - 1);
}
+typedef struct pm_event {
+ uint16_t number; /* PMEVTYPER.evtCount is 16 bits wide */
+ /* If the event is supported on this CPU (used to generate PMCEID[01]) */
+ bool (*supported)(CPUARMState *);
+ /*
+ * Retrieve the current count of the underlying event. The programmed
+ * counters hold a difference from the return value from this function
+ */
+ uint64_t (*get_count)(CPUARMState *);
+} pm_event;
+
+static bool event_always_supported(CPUARMState *env)
+{
+ return true;
+}
+
+static uint64_t swinc_get_count(CPUARMState *env)
+{
+ /*
+ * SW_INCR events are written directly to the pmevcntr's by writes to
+ * PMSWINC, so there is no underlying count maintained by the PMU itself
+ */
+ return 0;
+}
+
+/*
+ * Return the underlying cycle count for the PMU cycle counters. If we're in
+ * usermode, simply return 0.
+ */
+static uint64_t cycles_get_count(CPUARMState *env)
+{
+#ifndef CONFIG_USER_ONLY
+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
+#else
+ return cpu_get_host_ticks();
+#endif
+}
+
+#ifndef CONFIG_USER_ONLY
+static bool instructions_supported(CPUARMState *env)
+{
+ return use_icount == 1 /* Precise instruction counting */;
+}
+
+static uint64_t instructions_get_count(CPUARMState *env)
+{
+ return (uint64_t)cpu_get_icount_raw();
+}
+#endif
+
+static const pm_event pm_events[] = {
+ { .number = 0x000, /* SW_INCR */
+ .supported = event_always_supported,
+ .get_count = swinc_get_count,
+ },
+#ifndef CONFIG_USER_ONLY
+ { .number = 0x008, /* INST_RETIRED, Instruction architecturally executed */
+ .supported = instructions_supported,
+ .get_count = instructions_get_count,
+ },
+ { .number = 0x011, /* CPU_CYCLES, Cycle */
+ .supported = event_always_supported,
+ .get_count = cycles_get_count,
+ }
+#endif
+};
+
+/*
+ * Note: Before increasing MAX_EVENT_ID beyond 0x3f into the 0x40xx range of
+ * events (i.e. the statistical profiling extension), this implementation
+ * should first be updated to something sparse instead of the current
+ * supported_event_map[] array.
+ */
+#define MAX_EVENT_ID 0x11
+#define UNSUPPORTED_EVENT UINT16_MAX
+static uint16_t supported_event_map[MAX_EVENT_ID + 1];
+
+/*
+ * Called upon initialization to build PMCEID0_EL0 or PMCEID1_EL0 (indicated by
+ * 'which'). We also use it to build a map of ARM event numbers to indices in
+ * our pm_events array.
+ *
+ * Note: Events in the 0x40XX range are not currently supported.
+ */
+uint64_t get_pmceid(CPUARMState *env, unsigned which)
+{
+ uint64_t pmceid = 0;
+ unsigned int i;
+
+ assert(which <= 1);
+
+ for (i = 0; i < ARRAY_SIZE(supported_event_map); i++) {
+ supported_event_map[i] = UNSUPPORTED_EVENT;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pm_events); i++) {
+ const pm_event *cnt = &pm_events[i];
+ assert(cnt->number <= MAX_EVENT_ID);
+ /* We do not currently support events in the 0x40xx range */
+ assert(cnt->number <= 0x3f);
+
+ if ((cnt->number & 0x20) == (which << 6) &&
+ cnt->supported(env)) {
+ pmceid |= (1 << (cnt->number & 0x1f));
+ supported_event_map[cnt->number] = i;
+ }
+ }
+ return pmceid;
+}
+
+/*
+ * Check at runtime whether a PMU event is supported for the current machine
+ */
+static bool event_supported(uint16_t number)
+{
+ if (number > MAX_EVENT_ID) {
+ return false;
+ }
+ return supported_event_map[number] != UNSUPPORTED_EVENT;
+}
+
static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -1044,8 +1186,6 @@ static CPAccessResult pmreg_access_swinc(CPUARMState *env,
return pmreg_access(env, ri, isread);
}
-#ifndef CONFIG_USER_ONLY
-
static CPAccessResult pmreg_access_selr(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
@@ -1075,68 +1215,222 @@ static CPAccessResult pmreg_access_ccntr(CPUARMState *env,
return pmreg_access(env, ri, isread);
}
-static inline bool arm_ccnt_enabled(CPUARMState *env)
+/* Returns true if the counter (pass 31 for PMCCNTR) should count events using
+ * the current EL, security state, and register configuration.
+ */
+static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
{
- /* This does not support checking PMCCFILTR_EL0 register */
+ uint64_t filter;
+ bool e, p, u, nsk, nsu, nsh, m;
+ bool enabled, prohibited, filtered;
+ bool secure = arm_is_secure(env);
+ int el = arm_current_el(env);
+ uint8_t hpmn = env->cp15.mdcr_el2 & MDCR_HPMN;
- if (!(env->cp15.c9_pmcr & PMCRE) || !(env->cp15.c9_pmcnten & (1 << 31))) {
- return false;
+ if (!arm_feature(env, ARM_FEATURE_EL2) ||
+ (counter < hpmn || counter == 31)) {
+ e = env->cp15.c9_pmcr & PMCRE;
+ } else {
+ e = env->cp15.mdcr_el2 & MDCR_HPME;
}
+ enabled = e && (env->cp15.c9_pmcnten & (1 << counter));
- return true;
+ if (!secure) {
+ if (el == 2 && (counter < hpmn || counter == 31)) {
+ prohibited = env->cp15.mdcr_el2 & MDCR_HPMD;
+ } else {
+ prohibited = false;
+ }
+ } else {
+ prohibited = arm_feature(env, ARM_FEATURE_EL3) &&
+ (env->cp15.mdcr_el3 & MDCR_SPME);
+ }
+
+ if (prohibited && counter == 31) {
+ prohibited = env->cp15.c9_pmcr & PMCRDP;
+ }
+
+ if (counter == 31) {
+ filter = env->cp15.pmccfiltr_el0;
+ } else {
+ filter = env->cp15.c14_pmevtyper[counter];
+ }
+
+ p = filter & PMXEVTYPER_P;
+ u = filter & PMXEVTYPER_U;
+ nsk = arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSK);
+ nsu = arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_NSU);
+ nsh = arm_feature(env, ARM_FEATURE_EL2) && (filter & PMXEVTYPER_NSH);
+ m = arm_el_is_aa64(env, 1) &&
+ arm_feature(env, ARM_FEATURE_EL3) && (filter & PMXEVTYPER_M);
+
+ if (el == 0) {
+ filtered = secure ? u : u != nsu;
+ } else if (el == 1) {
+ filtered = secure ? p : p != nsk;
+ } else if (el == 2) {
+ filtered = !nsh;
+ } else { /* EL3 */
+ filtered = m != p;
+ }
+
+ if (counter != 31) {
+ /*
+ * If not checking PMCCNTR, ensure the counter is setup to an event we
+ * support
+ */
+ uint16_t event = filter & PMXEVTYPER_EVTCOUNT;
+ if (!event_supported(event)) {
+ return false;
+ }
+ }
+
+ return enabled && !prohibited && !filtered;
}
-void pmccntr_sync(CPUARMState *env)
+/*
+ * Ensure c15_ccnt is the guest-visible count so that operations such as
+ * enabling/disabling the counter or filtering, modifying the count itself,
+ * etc. can be done logically. This is essentially a no-op if the counter is
+ * not enabled at the time of the call.
+ */
+void pmccntr_op_start(CPUARMState *env)
{
- uint64_t temp_ticks;
+ uint64_t cycles = cycles_get_count(env);
- temp_ticks = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
+ if (pmu_counter_enabled(env, 31)) {
+ uint64_t eff_cycles = cycles;
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ eff_cycles /= 64;
+ }
- if (env->cp15.c9_pmcr & PMCRD) {
- /* Increment once every 64 processor clock cycles */
- temp_ticks /= 64;
+ env->cp15.c15_ccnt = eff_cycles - env->cp15.c15_ccnt_delta;
}
+ env->cp15.c15_ccnt_delta = cycles;
+}
- if (arm_ccnt_enabled(env)) {
- env->cp15.c15_ccnt = temp_ticks - env->cp15.c15_ccnt;
+/*
+ * If PMCCNTR is enabled, recalculate the delta between the clock and the
+ * guest-visible count. A call to pmccntr_op_finish should follow every call to
+ * pmccntr_op_start.
+ */
+void pmccntr_op_finish(CPUARMState *env)
+{
+ if (pmu_counter_enabled(env, 31)) {
+ uint64_t prev_cycles = env->cp15.c15_ccnt_delta;
+
+ if (env->cp15.c9_pmcr & PMCRD) {
+ /* Increment once every 64 processor clock cycles */
+ prev_cycles /= 64;
+ }
+
+ env->cp15.c15_ccnt_delta = prev_cycles - env->cp15.c15_ccnt;
+ }
+}
+
+static void pmevcntr_op_start(CPUARMState *env, uint8_t counter)
+{
+
+ uint16_t event = env->cp15.c14_pmevtyper[counter] & PMXEVTYPER_EVTCOUNT;
+ uint64_t count = 0;
+ if (event_supported(event)) {
+ uint16_t event_idx = supported_event_map[event];
+ count = pm_events[event_idx].get_count(env);
+ }
+
+ if (pmu_counter_enabled(env, counter)) {
+ env->cp15.c14_pmevcntr[counter] =
+ count - env->cp15.c14_pmevcntr_delta[counter];
+ }
+ env->cp15.c14_pmevcntr_delta[counter] = count;
+}
+
+static void pmevcntr_op_finish(CPUARMState *env, uint8_t counter)
+{
+ if (pmu_counter_enabled(env, counter)) {
+ env->cp15.c14_pmevcntr_delta[counter] -=
+ env->cp15.c14_pmevcntr[counter];
+ }
+}
+
+void pmu_op_start(CPUARMState *env)
+{
+ unsigned int i;
+ pmccntr_op_start(env);
+ for (i = 0; i < pmu_num_counters(env); i++) {
+ pmevcntr_op_start(env, i);
}
}
+void pmu_op_finish(CPUARMState *env)
+{
+ unsigned int i;
+ pmccntr_op_finish(env);
+ for (i = 0; i < pmu_num_counters(env); i++) {
+ pmevcntr_op_finish(env, i);
+ }
+}
+
+void pmu_pre_el_change(ARMCPU *cpu, void *ignored)
+{
+ pmu_op_start(&cpu->env);
+}
+
+void pmu_post_el_change(ARMCPU *cpu, void *ignored)
+{
+ pmu_op_finish(&cpu->env);
+}
+
static void pmcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- pmccntr_sync(env);
+ pmu_op_start(env);
if (value & PMCRC) {
/* The counter has been reset */
env->cp15.c15_ccnt = 0;
}
+ if (value & PMCRP) {
+ unsigned int i;
+ for (i = 0; i < pmu_num_counters(env); i++) {
+ env->cp15.c14_pmevcntr[i] = 0;
+ }
+ }
+
/* only the DP, X, D and E bits are writable */
env->cp15.c9_pmcr &= ~0x39;
env->cp15.c9_pmcr |= (value & 0x39);
- pmccntr_sync(env);
+ pmu_op_finish(env);
}
-static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+static void pmswinc_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
{
- uint64_t total_ticks;
-
- if (!arm_ccnt_enabled(env)) {
- /* Counter is disabled, do not change value */
- return env->cp15.c15_ccnt;
+ unsigned int i;
+ for (i = 0; i < pmu_num_counters(env); i++) {
+ /* Increment a counter's count iff: */
+ if ((value & (1 << i)) && /* counter's bit is set */
+ /* counter is enabled and not filtered */
+ pmu_counter_enabled(env, i) &&
+ /* counter is SW_INCR */
+ (env->cp15.c14_pmevtyper[i] & PMXEVTYPER_EVTCOUNT) == 0x0) {
+ pmevcntr_op_start(env, i);
+ env->cp15.c14_pmevcntr[i]++;
+ pmevcntr_op_finish(env, i);
+ }
}
+}
- total_ticks = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
-
- if (env->cp15.c9_pmcr & PMCRD) {
- /* Increment once every 64 processor clock cycles */
- total_ticks /= 64;
- }
- return total_ticks - env->cp15.c15_ccnt;
+static uint64_t pmccntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ uint64_t ret;
+ pmccntr_op_start(env);
+ ret = env->cp15.c15_ccnt;
+ pmccntr_op_finish(env);
+ return ret;
}
static void pmselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -1153,22 +1447,9 @@ static void pmselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static void pmccntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- uint64_t total_ticks;
-
- if (!arm_ccnt_enabled(env)) {
- /* Counter is disabled, set the absolute value */
- env->cp15.c15_ccnt = value;
- return;
- }
-
- total_ticks = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
- ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
-
- if (env->cp15.c9_pmcr & PMCRD) {
- /* Increment once every 64 processor clock cycles */
- total_ticks /= 64;
- }
- env->cp15.c15_ccnt = total_ticks - value;
+ pmccntr_op_start(env);
+ env->cp15.c15_ccnt = value;
+ pmccntr_op_finish(env);
}
static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -1179,20 +1460,28 @@ static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri,
pmccntr_write(env, ri, deposit64(cur_val, 0, 32, value));
}
-#else /* CONFIG_USER_ONLY */
-
-void pmccntr_sync(CPUARMState *env)
+static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
{
+ pmccntr_op_start(env);
+ env->cp15.pmccfiltr_el0 = value & PMCCFILTR_EL0;
+ pmccntr_op_finish(env);
}
-#endif
-
-static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+static void pmccfiltr_write_a32(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
- pmccntr_sync(env);
- env->cp15.pmccfiltr_el0 = value & 0xfc000000;
- pmccntr_sync(env);
+ pmccntr_op_start(env);
+ /* M is not accessible from AArch32 */
+ env->cp15.pmccfiltr_el0 = (env->cp15.pmccfiltr_el0 & PMCCFILTR_M) |
+ (value & PMCCFILTR);
+ pmccntr_op_finish(env);
+}
+
+static uint64_t pmccfiltr_read_a32(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ /* M is not visible in AArch32 */
+ return env->cp15.pmccfiltr_el0 & PMCCFILTR;
}
static void pmcntenset_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -1216,30 +1505,181 @@ static void pmovsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
env->cp15.c9_pmovsr &= ~value;
}
-static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
+static void pmovsset_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ value &= pmu_counter_mask(env);
+ env->cp15.c9_pmovsr |= value;
+}
+
+static void pmevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value, const uint8_t counter)
{
+ if (counter == 31) {
+ pmccfiltr_write(env, ri, value);
+ } else if (counter < pmu_num_counters(env)) {
+ pmevcntr_op_start(env, counter);
+
+ /*
+ * If this counter's event type is changing, store the current
+ * underlying count for the new type in c14_pmevcntr_delta[counter] so
+ * pmevcntr_op_finish has the correct baseline when it converts back to
+ * a delta.
+ */
+ uint16_t old_event = env->cp15.c14_pmevtyper[counter] &
+ PMXEVTYPER_EVTCOUNT;
+ uint16_t new_event = value & PMXEVTYPER_EVTCOUNT;
+ if (old_event != new_event) {
+ uint64_t count = 0;
+ if (event_supported(new_event)) {
+ uint16_t event_idx = supported_event_map[new_event];
+ count = pm_events[event_idx].get_count(env);
+ }
+ env->cp15.c14_pmevcntr_delta[counter] = count;
+ }
+
+ env->cp15.c14_pmevtyper[counter] = value & PMXEVTYPER_MASK;
+ pmevcntr_op_finish(env, counter);
+ }
/* Attempts to access PMXEVTYPER are CONSTRAINED UNPREDICTABLE when
* PMSELR value is equal to or greater than the number of implemented
* counters, but not equal to 0x1f. We opt to behave as a RAZ/WI.
*/
- if (env->cp15.c9_pmselr == 0x1f) {
- pmccfiltr_write(env, ri, value);
+}
+
+static uint64_t pmevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri,
+ const uint8_t counter)
+{
+ if (counter == 31) {
+ return env->cp15.pmccfiltr_el0;
+ } else if (counter < pmu_num_counters(env)) {
+ return env->cp15.c14_pmevtyper[counter];
+ } else {
+ /*
+ * We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER
+ * are CONSTRAINED UNPREDICTABLE. See comments in pmevtyper_write().
+ */
+ return 0;
+ }
+}
+
+static void pmevtyper_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ pmevtyper_write(env, ri, value, counter);
+}
+
+static void pmevtyper_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ env->cp15.c14_pmevtyper[counter] = value;
+
+ /*
+ * pmevtyper_rawwrite is called between a pair of pmu_op_start and
+ * pmu_op_finish calls when loading saved state for a migration. Because
+ * we're potentially updating the type of event here, the value written to
+ * c14_pmevcntr_delta by the preceeding pmu_op_start call may be for a
+ * different counter type. Therefore, we need to set this value to the
+ * current count for the counter type we're writing so that pmu_op_finish
+ * has the correct count for its calculation.
+ */
+ uint16_t event = value & PMXEVTYPER_EVTCOUNT;
+ if (event_supported(event)) {
+ uint16_t event_idx = supported_event_map[event];
+ env->cp15.c14_pmevcntr_delta[counter] =
+ pm_events[event_idx].get_count(env);
}
}
+static uint64_t pmevtyper_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ return pmevtyper_read(env, ri, counter);
+}
+
+static void pmxevtyper_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ pmevtyper_write(env, ri, value, env->cp15.c9_pmselr & 31);
+}
+
static uint64_t pmxevtyper_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- /* We opt to behave as a RAZ/WI when attempts to access PMXEVTYPER
- * are CONSTRAINED UNPREDICTABLE. See comments in pmxevtyper_write().
+ return pmevtyper_read(env, ri, env->cp15.c9_pmselr & 31);
+}
+
+static void pmevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value, uint8_t counter)
+{
+ if (counter < pmu_num_counters(env)) {
+ pmevcntr_op_start(env, counter);
+ env->cp15.c14_pmevcntr[counter] = value;
+ pmevcntr_op_finish(env, counter);
+ }
+ /*
+ * We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR
+ * are CONSTRAINED UNPREDICTABLE.
*/
- if (env->cp15.c9_pmselr == 0x1f) {
- return env->cp15.pmccfiltr_el0;
+}
+
+static uint64_t pmevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint8_t counter)
+{
+ if (counter < pmu_num_counters(env)) {
+ uint64_t ret;
+ pmevcntr_op_start(env, counter);
+ ret = env->cp15.c14_pmevcntr[counter];
+ pmevcntr_op_finish(env, counter);
+ return ret;
} else {
+ /* We opt to behave as a RAZ/WI when attempts to access PM[X]EVCNTR
+ * are CONSTRAINED UNPREDICTABLE. */
return 0;
}
}
+static void pmevcntr_writefn(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ pmevcntr_write(env, ri, value, counter);
+}
+
+static uint64_t pmevcntr_readfn(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ return pmevcntr_read(env, ri, counter);
+}
+
+static void pmevcntr_rawwrite(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ assert(counter < pmu_num_counters(env));
+ env->cp15.c14_pmevcntr[counter] = value;
+ pmevcntr_write(env, ri, value, counter);
+}
+
+static uint64_t pmevcntr_rawread(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ uint8_t counter = ((ri->crm & 3) << 3) | (ri->opc2 & 7);
+ assert(counter < pmu_num_counters(env));
+ return env->cp15.c14_pmevcntr[counter];
+}
+
+static void pmxevcntr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ pmevcntr_write(env, ri, value, env->cp15.c9_pmselr & 31);
+}
+
+static uint64_t pmxevcntr_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return pmevcntr_read(env, ri, env->cp15.c9_pmselr & 31);
+}
+
static void pmuserenr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -1279,11 +1719,16 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
- /* We only mask off bits that are RES0 both for AArch64 and AArch32.
- * For bits that vary between AArch32/64, code needs to check the
- * current execution mode before directly using the feature bit.
- */
- uint32_t valid_mask = SCR_AARCH64_MASK | SCR_AARCH32_MASK;
+ /* Begin with base v8.0 state. */
+ uint32_t valid_mask = 0x3fff;
+ ARMCPU *cpu = arm_env_get_cpu(env);
+
+ if (arm_el_is_aa64(env, 3)) {
+ value |= SCR_FW | SCR_AW; /* these two bits are RES1. */
+ valid_mask &= ~SCR_NET;
+ } else {
+ valid_mask &= ~(SCR_RW | SCR_ST);
+ }
if (!arm_feature(env, ARM_FEATURE_EL2)) {
valid_mask &= ~SCR_HCE;
@@ -1299,6 +1744,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
valid_mask &= ~SCR_SMD;
}
}
+ if (cpu_isar_feature(aa64_lor, cpu)) {
+ valid_mask |= SCR_TLOR;
+ }
/* Clear all-context RES0 bits. */
value &= valid_mask;
@@ -1327,9 +1775,10 @@ static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
CPUState *cs = ENV_GET_CPU(env);
+ uint64_t hcr_el2 = arm_hcr_el2_eff(env);
uint64_t ret = 0;
- if (arm_hcr_el2_imo(env)) {
+ if (hcr_el2 & HCR_IMO) {
if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
ret |= CPSR_I;
}
@@ -1339,7 +1788,7 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
}
- if (arm_hcr_el2_fmo(env)) {
+ if (hcr_el2 & HCR_FMO) {
if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) {
ret |= CPSR_F;
}
@@ -1359,7 +1808,7 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.access = PL1_W, .type = ARM_CP_NOP },
/* Performance monitors are implementation defined in v7,
* but with an ARM recommended set of registers, which we
- * follow (although we don't actually implement any counters)
+ * follow.
*
* Performance registers fall into three categories:
* (a) always UNDEF in PL0, RW in PL1 (PMINTENSET, PMINTENCLR)
@@ -1404,10 +1853,13 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
.writefn = pmovsr_write,
.raw_writefn = raw_write },
- /* Unimplemented so WI. */
{ .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
- .access = PL0_W, .accessfn = pmreg_access_swinc, .type = ARM_CP_NOP },
-#ifndef CONFIG_USER_ONLY
+ .access = PL0_W, .accessfn = pmreg_access_swinc, .type = ARM_CP_NO_RAW,
+ .writefn = pmswinc_write },
+ { .name = "PMSWINC_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 4,
+ .access = PL0_W, .accessfn = pmreg_access_swinc, .type = ARM_CP_NO_RAW,
+ .writefn = pmswinc_write },
{ .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
.access = PL0_RW, .type = ARM_CP_ALIAS,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmselr),
@@ -1426,26 +1878,39 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 0,
.access = PL0_RW, .accessfn = pmreg_access_ccntr,
.type = ARM_CP_IO,
- .readfn = pmccntr_read, .writefn = pmccntr_write, },
-#endif
+ .fieldoffset = offsetof(CPUARMState, cp15.c15_ccnt),
+ .readfn = pmccntr_read, .writefn = pmccntr_write,
+ .raw_readfn = raw_read, .raw_writefn = raw_write, },
+ { .name = "PMCCFILTR", .cp = 15, .opc1 = 0, .crn = 14, .crm = 15, .opc2 = 7,
+ .writefn = pmccfiltr_write_a32, .readfn = pmccfiltr_read_a32,
+ .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_ALIAS | ARM_CP_IO,
+ .resetvalue = 0, },
{ .name = "PMCCFILTR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 15, .opc2 = 7,
- .writefn = pmccfiltr_write,
+ .writefn = pmccfiltr_write, .raw_writefn = raw_write,
.access = PL0_RW, .accessfn = pmreg_access,
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.pmccfiltr_el0),
.resetvalue = 0, },
{ .name = "PMXEVTYPER", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 1,
- .access = PL0_RW, .type = ARM_CP_NO_RAW, .accessfn = pmreg_access,
+ .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO,
+ .accessfn = pmreg_access,
.writefn = pmxevtyper_write, .readfn = pmxevtyper_read },
{ .name = "PMXEVTYPER_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 1,
- .access = PL0_RW, .type = ARM_CP_NO_RAW, .accessfn = pmreg_access,
+ .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO,
+ .accessfn = pmreg_access,
.writefn = pmxevtyper_write, .readfn = pmxevtyper_read },
- /* Unimplemented, RAZ/WI. */
{ .name = "PMXEVCNTR", .cp = 15, .crn = 9, .crm = 13, .opc1 = 0, .opc2 = 2,
- .access = PL0_RW, .type = ARM_CP_CONST, .resetvalue = 0,
- .accessfn = pmreg_access_xevcntr },
+ .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO,
+ .accessfn = pmreg_access_xevcntr,
+ .writefn = pmxevcntr_write, .readfn = pmxevcntr_read },
+ { .name = "PMXEVCNTR_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 2,
+ .access = PL0_RW, .type = ARM_CP_NO_RAW | ARM_CP_IO,
+ .accessfn = pmreg_access_xevcntr,
+ .writefn = pmxevcntr_write, .readfn = pmxevcntr_read },
{ .name = "PMUSERENR", .cp = 15, .crn = 9, .crm = 14, .opc1 = 0, .opc2 = 0,
.access = PL0_R | PL1_RW, .accessfn = access_tpm,
.fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmuserenr),
@@ -1576,6 +2041,24 @@ static const ARMCPRegInfo v7mp_cp_reginfo[] = {
REGINFO_SENTINEL
};
+static const ARMCPRegInfo pmovsset_cp_reginfo[] = {
+ /* PMOVSSET is not implemented in v7 before v7ve */
+ { .name = "PMOVSSET", .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 3,
+ .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmovsr),
+ .writefn = pmovsset_write,
+ .raw_writefn = raw_write },
+ { .name = "PMOVSSET_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 14, .opc2 = 3,
+ .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_ALIAS,
+ .fieldoffset = offsetof(CPUARMState, cp15.c9_pmovsr),
+ .writefn = pmovsset_write,
+ .raw_writefn = raw_write },
+ REGINFO_SENTINEL
+};
+
static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -2724,6 +3207,7 @@ static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
+ TCR *tcr = raw_ptr(env, ri);
if (arm_feature(env, ARM_FEATURE_LPAE)) {
/* With LPAE the TTBCR could result in a change of ASID
@@ -2731,6 +3215,8 @@ static void vmsa_ttbcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
*/
tlb_flush(CPU(cpu));
}
+ /* Preserve the high half of TCR_EL1, set via TTBCR2. */
+ value = deposit64(tcr->raw_tcr, 0, 32, value);
vmsa_ttbcr_raw_write(env, ri, value);
}
@@ -2833,6 +3319,16 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
REGINFO_SENTINEL
};
+/* Note that unlike TTBCR, writing to TTBCR2 does not require flushing
+ * qemu tlbs nor adjusting cached masks.
+ */
+static const ARMCPRegInfo ttbcr2_reginfo = {
+ .name = "TTBCR2", .cp = 15, .opc1 = 0, .crn = 2, .crm = 0, .opc2 = 3,
+ .access = PL1_RW, .type = ARM_CP_ALIAS,
+ .bank_fieldoffsets = { offsetofhigh32(CPUARMState, cp15.tcr_el[3]),
+ offsetofhigh32(CPUARMState, cp15.tcr_el[1]) },
+};
+
static void omap_ticonfig_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
@@ -3945,6 +4441,9 @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
*/
valid_mask &= ~HCR_TSC;
}
+ if (cpu_isar_feature(aa64_lor, cpu)) {
+ valid_mask |= HCR_TLOR;
+ }
/* Clear RES0 bits. */
value &= valid_mask;
@@ -3991,6 +4490,51 @@ static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri,
hcr_write(env, NULL, value);
}
+/*
+ * Return the effective value of HCR_EL2.
+ * Bits that are not included here:
+ * RW (read from SCR_EL3.RW as needed)
+ */
+uint64_t arm_hcr_el2_eff(CPUARMState *env)
+{
+ uint64_t ret = env->cp15.hcr_el2;
+
+ if (arm_is_secure_below_el3(env)) {
+ /*
+ * "This register has no effect if EL2 is not enabled in the
+ * current Security state". This is ARMv8.4-SecEL2 speak for
+ * !(SCR_EL3.NS==1 || SCR_EL3.EEL2==1).
+ *
+ * Prior to that, the language was "In an implementation that
+ * includes EL3, when the value of SCR_EL3.NS is 0 the PE behaves
+ * as if this field is 0 for all purposes other than a direct
+ * read or write access of HCR_EL2". With lots of enumeration
+ * on a per-field basis. In current QEMU, this is condition
+ * is arm_is_secure_below_el3.
+ *
+ * Since the v8.4 language applies to the entire register, and
+ * appears to be backward compatible, use that.
+ */
+ ret = 0;
+ } else if (ret & HCR_TGE) {
+ /* These bits are up-to-date as of ARMv8.4. */
+ if (ret & HCR_E2H) {
+ ret &= ~(HCR_VM | HCR_FMO | HCR_IMO | HCR_AMO |
+ HCR_BSU_MASK | HCR_DC | HCR_TWI | HCR_TWE |
+ HCR_TID0 | HCR_TID2 | HCR_TPCP | HCR_TPU |
+ HCR_TDZ | HCR_CD | HCR_ID | HCR_MIOCNCE);
+ } else {
+ ret |= HCR_FMO | HCR_IMO | HCR_AMO;
+ }
+ ret &= ~(HCR_SWIO | HCR_PTW | HCR_VF | HCR_VI | HCR_VSE |
+ HCR_FB | HCR_TID1 | HCR_TID3 | HCR_TSC | HCR_TACR |
+ HCR_TSW | HCR_TTLB | HCR_TVM | HCR_HCD | HCR_TRVM |
+ HCR_TLOR);
+ }
+
+ return ret;
+}
+
static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_IO,
@@ -4214,7 +4758,7 @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
#endif
/* The only field of MDCR_EL2 that has a defined architectural reset value
* is MDCR_EL2.HPMN which should reset to the value of PMCR_EL0.N; but we
- * don't impelment any PMU event counters, so using zero as a reset
+ * don't implement any PMU event counters, so using zero as a reset
* value for MDCR_EL2 is okay
*/
{ .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH,
@@ -4503,8 +5047,7 @@ int sve_exception_el(CPUARMState *env, int el)
if (disabled) {
/* route_to_el2 */
return (arm_feature(env, ARM_FEATURE_EL2)
- && !arm_is_secure(env)
- && (env->cp15.hcr_el2 & HCR_TGE) ? 2 : 1);
+ && (arm_hcr_el2_eff(env) & HCR_TGE) ? 2 : 1);
}
/* Check CPACR.FPEN. */
@@ -4956,6 +5499,106 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
return pfr0;
}
+/* Shared logic between LORID and the rest of the LOR* registers.
+ * Secure state has already been delt with.
+ */
+static CPAccessResult access_lor_ns(CPUARMState *env)
+{
+ int el = arm_current_el(env);
+
+ if (el < 2 && (arm_hcr_el2_eff(env) & HCR_TLOR)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3 && (env->cp15.scr_el3 & SCR_TLOR)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static CPAccessResult access_lorid(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_is_secure_below_el3(env)) {
+ /* Access ok in secure mode. */
+ return CP_ACCESS_OK;
+ }
+ return access_lor_ns(env);
+}
+
+static CPAccessResult access_lor_other(CPUARMState *env,
+ const ARMCPRegInfo *ri, bool isread)
+{
+ if (arm_is_secure_below_el3(env)) {
+ /* Access denied in secure mode. */
+ return CP_ACCESS_TRAP;
+ }
+ return access_lor_ns(env);
+}
+
+#ifdef TARGET_AARCH64
+static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ int el = arm_current_el(env);
+
+ if (el < 2 &&
+ arm_feature(env, ARM_FEATURE_EL2) &&
+ !(arm_hcr_el2_eff(env) & HCR_APK)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3 &&
+ arm_feature(env, ARM_FEATURE_EL3) &&
+ !(env->cp15.scr_el3 & SCR_APK)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static const ARMCPRegInfo pauth_reginfo[] = {
+ { .name = "APDAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 0,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apda_key.lo) },
+ { .name = "APDAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 1,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apda_key.hi) },
+ { .name = "APDBKEYLO_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 2,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apdb_key.lo) },
+ { .name = "APDBKEYHI_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 2, .opc2 = 3,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apdb_key.hi) },
+ { .name = "APGAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 0,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apga_key.lo) },
+ { .name = "APGAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 3, .opc2 = 1,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apga_key.hi) },
+ { .name = "APIAKEYLO_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 0,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apia_key.lo) },
+ { .name = "APIAKEYHI_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 1,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apia_key.hi) },
+ { .name = "APIBKEYLO_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 2,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apib_key.lo) },
+ { .name = "APIBKEYHI_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 2, .crm = 1, .opc2 = 3,
+ .access = PL1_RW, .accessfn = access_pauth,
+ .fieldoffset = offsetof(CPUARMState, apib_key.hi) },
+ REGINFO_SENTINEL
+};
+#endif
+
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@@ -5058,12 +5701,15 @@ void register_cp_regs_for_features(ARMCPU *cpu)
!arm_feature(env, ARM_FEATURE_PMSA)) {
define_arm_cp_regs(cpu, v7mp_cp_reginfo);
}
+ if (arm_feature(env, ARM_FEATURE_V7VE)) {
+ define_arm_cp_regs(cpu, pmovsset_cp_reginfo);
+ }
if (arm_feature(env, ARM_FEATURE_V7)) {
/* v7 performance monitor control register: same implementor
- * field as main ID register, and we implement only the cycle
- * count register.
+ * field as main ID register, and we implement four counters in
+ * addition to the cycle count register.
*/
-#ifndef CONFIG_USER_ONLY
+ unsigned int i, pmcrn = 4;
ARMCPRegInfo pmcr = {
.name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
.access = PL0_RW,
@@ -5078,12 +5724,48 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.access = PL0_RW, .accessfn = pmreg_access,
.type = ARM_CP_IO,
.fieldoffset = offsetof(CPUARMState, cp15.c9_pmcr),
- .resetvalue = cpu->midr & 0xff000000,
+ .resetvalue = (cpu->midr & 0xff000000) | (pmcrn << PMCRN_SHIFT),
.writefn = pmcr_write, .raw_writefn = raw_write,
};
define_one_arm_cp_reg(cpu, &pmcr);
define_one_arm_cp_reg(cpu, &pmcr64);
-#endif
+ for (i = 0; i < pmcrn; i++) {
+ char *pmevcntr_name = g_strdup_printf("PMEVCNTR%d", i);
+ char *pmevcntr_el0_name = g_strdup_printf("PMEVCNTR%d_EL0", i);
+ char *pmevtyper_name = g_strdup_printf("PMEVTYPER%d", i);
+ char *pmevtyper_el0_name = g_strdup_printf("PMEVTYPER%d_EL0", i);
+ ARMCPRegInfo pmev_regs[] = {
+ { .name = pmevcntr_name, .cp = 15, .crn = 15,
+ .crm = 8 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7,
+ .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS,
+ .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn,
+ .accessfn = pmreg_access },
+ { .name = pmevcntr_el0_name, .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 15, .crm = 8 | (3 & (i >> 3)),
+ .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_IO,
+ .readfn = pmevcntr_readfn, .writefn = pmevcntr_writefn,
+ .raw_readfn = pmevcntr_rawread,
+ .raw_writefn = pmevcntr_rawwrite },
+ { .name = pmevtyper_name, .cp = 15, .crn = 15,
+ .crm = 12 | (3 & (i >> 3)), .opc1 = 0, .opc2 = i & 7,
+ .access = PL0_RW, .type = ARM_CP_IO | ARM_CP_ALIAS,
+ .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn,
+ .accessfn = pmreg_access },
+ { .name = pmevtyper_el0_name, .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 15, .crm = 12 | (3 & (i >> 3)),
+ .opc2 = i & 7, .access = PL0_RW, .accessfn = pmreg_access,
+ .type = ARM_CP_IO,
+ .readfn = pmevtyper_readfn, .writefn = pmevtyper_writefn,
+ .raw_writefn = pmevtyper_rawwrite },
+ REGINFO_SENTINEL
+ };
+ define_arm_cp_regs(cpu, pmev_regs);
+ g_free(pmevcntr_name);
+ g_free(pmevcntr_el0_name);
+ g_free(pmevtyper_name);
+ g_free(pmevtyper_el0_name);
+ }
ARMCPRegInfo clidr = {
.name = "CLIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
@@ -5095,6 +5777,21 @@ void register_cp_regs_for_features(ARMCPU *cpu)
} else {
define_arm_cp_regs(cpu, not_v7_cp_reginfo);
}
+ if (FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) >= 4 &&
+ FIELD_EX32(cpu->id_dfr0, ID_DFR0, PERFMON) != 0xf) {
+ ARMCPRegInfo v81_pmu_regs[] = {
+ { .name = "PMCEID2", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 4,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = extract64(cpu->pmceid0, 32, 32) },
+ { .name = "PMCEID3", .state = ARM_CP_STATE_AA32,
+ .cp = 15, .opc1 = 0, .crn = 9, .crm = 14, .opc2 = 5,
+ .access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
+ .resetvalue = extract64(cpu->pmceid1, 32, 32) },
+ REGINFO_SENTINEL
+ };
+ define_arm_cp_regs(cpu, v81_pmu_regs);
+ }
if (arm_feature(env, ARM_FEATURE_V8)) {
/* AArch64 ID registers, which all have impdef reset values.
* Note that within the ID register ranges the unused slots
@@ -5207,11 +5904,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
{ .name = "ID_AA64MMFR0_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 0,
.access = PL1_R, .type = ARM_CP_CONST,
- .resetvalue = cpu->id_aa64mmfr0 },
+ .resetvalue = cpu->isar.id_aa64mmfr0 },
{ .name = "ID_AA64MMFR1_EL1", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST,
- .resetvalue = cpu->id_aa64mmfr1 },
+ .resetvalue = cpu->isar.id_aa64mmfr1 },
{ .name = "ID_AA64MMFR2_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 7, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST,
@@ -5271,7 +5968,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
{ .name = "PMCEID0", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 6,
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
- .resetvalue = cpu->pmceid0 },
+ .resetvalue = extract64(cpu->pmceid0, 0, 32) },
{ .name = "PMCEID0_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 6,
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
@@ -5279,7 +5976,7 @@ void register_cp_regs_for_features(ARMCPU *cpu)
{ .name = "PMCEID1", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 9, .crm = 12, .opc2 = 7,
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
- .resetvalue = cpu->pmceid1 },
+ .resetvalue = extract64(cpu->pmceid1, 0, 32) },
{ .name = "PMCEID1_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 9, .crm = 12, .opc2 = 7,
.access = PL0_R, .accessfn = pmreg_access, .type = ARM_CP_CONST,
@@ -5433,6 +6130,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
} else {
define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo);
define_arm_cp_regs(cpu, vmsa_cp_reginfo);
+ /* TTCBR2 is introduced with ARMv8.2-A32HPD. */
+ if (FIELD_EX32(cpu->id_mmfr4, ID_MMFR4, HPDS) != 0) {
+ define_one_arm_cp_reg(cpu, &ttbcr2_reginfo);
+ }
}
if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
define_arm_cp_regs(cpu, t2ee_cp_reginfo);
@@ -5693,6 +6394,38 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_one_arm_cp_reg(cpu, &sctlr);
}
+ if (cpu_isar_feature(aa64_lor, cpu)) {
+ /*
+ * A trivial implementation of ARMv8.1-LOR leaves all of these
+ * registers fixed at 0, which indicates that there are zero
+ * supported Limited Ordering regions.
+ */
+ static const ARMCPRegInfo lor_reginfo[] = {
+ { .name = "LORSA_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 0,
+ .access = PL1_RW, .accessfn = access_lor_other,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "LOREA_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 1,
+ .access = PL1_RW, .accessfn = access_lor_other,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "LORN_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 2,
+ .access = PL1_RW, .accessfn = access_lor_other,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "LORC_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 3,
+ .access = PL1_RW, .accessfn = access_lor_other,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ { .name = "LORID_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 10, .crm = 4, .opc2 = 7,
+ .access = PL1_R, .accessfn = access_lorid,
+ .type = ARM_CP_CONST, .resetvalue = 0 },
+ REGINFO_SENTINEL
+ };
+ define_arm_cp_regs(cpu, lor_reginfo);
+ }
+
if (cpu_isar_feature(aa64_sve, cpu)) {
define_one_arm_cp_reg(cpu, &zcr_el1_reginfo);
if (arm_feature(env, ARM_FEATURE_EL2)) {
@@ -5704,6 +6437,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_one_arm_cp_reg(cpu, &zcr_el3_reginfo);
}
}
+
+#ifdef TARGET_AARCH64
+ if (cpu_isar_feature(aa64_pauth, cpu)) {
+ define_arm_cp_regs(cpu, pauth_reginfo);
+ }
+#endif
}
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
@@ -6149,15 +6888,14 @@ static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type)
* and CPS are treated as illegal mode changes.
*/
if (write_type == CPSRWriteByInstr &&
- (env->cp15.hcr_el2 & HCR_TGE) &&
(env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_MON &&
- !arm_is_secure_below_el3(env)) {
+ (arm_hcr_el2_eff(env) & HCR_TGE)) {
return 1;
}
return 0;
case ARM_CPU_MODE_HYP:
return !arm_feature(env, ARM_FEATURE_EL2)
- || arm_current_el(env) < 2 || arm_is_secure(env);
+ || arm_current_el(env) < 2 || arm_is_secure_below_el3(env);
case ARM_CPU_MODE_MON:
return arm_current_el(env) < 3;
default:
@@ -6505,12 +7243,13 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
uint32_t cur_el, bool secure)
{
CPUARMState *env = cs->env_ptr;
- int rw;
- int scr;
- int hcr;
+ bool rw;
+ bool scr;
+ bool hcr;
int target_el;
/* Is the highest EL AArch64? */
- int is64 = arm_feature(env, ARM_FEATURE_AARCH64);
+ bool is64 = arm_feature(env, ARM_FEATURE_AARCH64);
+ uint64_t hcr_el2;
if (arm_feature(env, ARM_FEATURE_EL3)) {
rw = ((env->cp15.scr_el3 & SCR_RW) == SCR_RW);
@@ -6522,24 +7261,22 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
rw = is64;
}
+ hcr_el2 = arm_hcr_el2_eff(env);
switch (excp_idx) {
case EXCP_IRQ:
scr = ((env->cp15.scr_el3 & SCR_IRQ) == SCR_IRQ);
- hcr = arm_hcr_el2_imo(env);
+ hcr = hcr_el2 & HCR_IMO;
break;
case EXCP_FIQ:
scr = ((env->cp15.scr_el3 & SCR_FIQ) == SCR_FIQ);
- hcr = arm_hcr_el2_fmo(env);
+ hcr = hcr_el2 & HCR_FMO;
break;
default:
scr = ((env->cp15.scr_el3 & SCR_EA) == SCR_EA);
- hcr = arm_hcr_el2_amo(env);
+ hcr = hcr_el2 & HCR_AMO;
break;
};
- /* If HCR.TGE is set then HCR is treated as being 1 */
- hcr |= ((env->cp15.hcr_el2 & HCR_TGE) == HCR_TGE);
-
/* Perform a table-lookup for the target EL given the current state */
target_el = target_el_table[is64][scr][rw][hcr][secure][cur_el];
@@ -6978,7 +7715,7 @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
limit = env->v7m.msplim[M_REG_S];
}
} else {
- mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
+ mmu_idx = arm_mmu_idx(env);
frame_sp_p = &env->regs[13];
limit = v7m_sp_limit(env);
}
@@ -7159,7 +7896,7 @@ static bool v7m_push_stack(ARMCPU *cpu)
CPUARMState *env = &cpu->env;
uint32_t xpsr = xpsr_read(env);
uint32_t frameptr = env->regs[13];
- ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
+ ARMMMUIdx mmu_idx = arm_mmu_idx(env);
/* Align stack pointer if the guest wants that */
if ((frameptr & 4) &&
@@ -8818,48 +9555,6 @@ static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
return mmu_idx;
}
-/* Returns TBI0 value for current regime el */
-uint32_t arm_regime_tbi0(CPUARMState *env, ARMMMUIdx mmu_idx)
-{
- TCR *tcr;
- uint32_t el;
-
- /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert
- * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
- */
- mmu_idx = stage_1_mmu_idx(mmu_idx);
-
- tcr = regime_tcr(env, mmu_idx);
- el = regime_el(env, mmu_idx);
-
- if (el > 1) {
- return extract64(tcr->raw_tcr, 20, 1);
- } else {
- return extract64(tcr->raw_tcr, 37, 1);
- }
-}
-
-/* Returns TBI1 value for current regime el */
-uint32_t arm_regime_tbi1(CPUARMState *env, ARMMMUIdx mmu_idx)
-{
- TCR *tcr;
- uint32_t el;
-
- /* For EL0 and EL1, TBI is controlled by stage 1's TCR, so convert
- * a stage 1+2 mmu index into the appropriate stage 1 mmu index.
- */
- mmu_idx = stage_1_mmu_idx(mmu_idx);
-
- tcr = regime_tcr(env, mmu_idx);
- el = regime_el(env, mmu_idx);
-
- if (el > 1) {
- return 0;
- } else {
- return extract64(tcr->raw_tcr, 38, 1);
- }
-}
-
/* Return the TTBR associated with this translation regime */
static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
int ttbrn)
@@ -9605,6 +10300,138 @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs)
return (hiattr << 6) | (hihint << 4) | (loattr << 2) | lohint;
}
+ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va,
+ ARMMMUIdx mmu_idx)
+{
+ uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
+ uint32_t el = regime_el(env, mmu_idx);
+ bool tbi, tbid, epd, hpd, using16k, using64k;
+ int select, tsz;
+
+ /*
+ * Bit 55 is always between the two regions, and is canonical for
+ * determining if address tagging is enabled.
+ */
+ select = extract64(va, 55, 1);
+
+ if (el > 1) {
+ tsz = extract32(tcr, 0, 6);
+ using64k = extract32(tcr, 14, 1);
+ using16k = extract32(tcr, 15, 1);
+ if (mmu_idx == ARMMMUIdx_S2NS) {
+ /* VTCR_EL2 */
+ tbi = tbid = hpd = false;
+ } else {
+ tbi = extract32(tcr, 20, 1);
+ hpd = extract32(tcr, 24, 1);
+ tbid = extract32(tcr, 29, 1);
+ }
+ epd = false;
+ } else if (!select) {
+ tsz = extract32(tcr, 0, 6);
+ epd = extract32(tcr, 7, 1);
+ using64k = extract32(tcr, 14, 1);
+ using16k = extract32(tcr, 15, 1);
+ tbi = extract64(tcr, 37, 1);
+ hpd = extract64(tcr, 41, 1);
+ tbid = extract64(tcr, 51, 1);
+ } else {
+ int tg = extract32(tcr, 30, 2);
+ using16k = tg == 1;
+ using64k = tg == 3;
+ tsz = extract32(tcr, 16, 6);
+ epd = extract32(tcr, 23, 1);
+ tbi = extract64(tcr, 38, 1);
+ hpd = extract64(tcr, 42, 1);
+ tbid = extract64(tcr, 52, 1);
+ }
+ tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
+ tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
+
+ return (ARMVAParameters) {
+ .tsz = tsz,
+ .select = select,
+ .tbi = tbi,
+ .tbid = tbid,
+ .epd = epd,
+ .hpd = hpd,
+ .using16k = using16k,
+ .using64k = using64k,
+ };
+}
+
+ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
+ ARMMMUIdx mmu_idx, bool data)
+{
+ ARMVAParameters ret = aa64_va_parameters_both(env, va, mmu_idx);
+
+ /* Present TBI as a composite with TBID. */
+ ret.tbi &= (data || !ret.tbid);
+ return ret;
+}
+
+static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,
+ ARMMMUIdx mmu_idx)
+{
+ uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
+ uint32_t el = regime_el(env, mmu_idx);
+ int select, tsz;
+ bool epd, hpd;
+
+ if (mmu_idx == ARMMMUIdx_S2NS) {
+ /* VTCR */
+ bool sext = extract32(tcr, 4, 1);
+ bool sign = extract32(tcr, 3, 1);
+
+ /*
+ * If the sign-extend bit is not the same as t0sz[3], the result
+ * is unpredictable. Flag this as a guest error.
+ */
+ if (sign != sext) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n");
+ }
+ tsz = sextract32(tcr, 0, 4) + 8;
+ select = 0;
+ hpd = false;
+ epd = false;
+ } else if (el == 2) {
+ /* HTCR */
+ tsz = extract32(tcr, 0, 3);
+ select = 0;
+ hpd = extract64(tcr, 24, 1);
+ epd = false;
+ } else {
+ int t0sz = extract32(tcr, 0, 3);
+ int t1sz = extract32(tcr, 16, 3);
+
+ if (t1sz == 0) {
+ select = va > (0xffffffffu >> t0sz);
+ } else {
+ /* Note that we will detect errors later. */
+ select = va >= ~(0xffffffffu >> t1sz);
+ }
+ if (!select) {
+ tsz = t0sz;
+ epd = extract32(tcr, 7, 1);
+ hpd = extract64(tcr, 41, 1);
+ } else {
+ tsz = t1sz;
+ epd = extract32(tcr, 23, 1);
+ hpd = extract64(tcr, 42, 1);
+ }
+ /* For aarch32, hpd0 is not enabled without t2e as well. */
+ hpd &= extract32(tcr, 6, 1);
+ }
+
+ return (ARMVAParameters) {
+ .tsz = tsz,
+ .select = select,
+ .epd = epd,
+ .hpd = hpd,
+ };
+}
+
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
MMUAccessType access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
@@ -9616,23 +10443,18 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
/* Read an LPAE long-descriptor translation table. */
ARMFaultType fault_type = ARMFault_Translation;
uint32_t level;
- uint32_t epd = 0;
- int32_t t0sz, t1sz;
- uint32_t tg;
+ ARMVAParameters param;
uint64_t ttbr;
- int ttbr_select;
hwaddr descaddr, indexmask, indexmask_grainsize;
uint32_t tableattrs;
- target_ulong page_size;
+ target_ulong page_size, top_bits;
uint32_t attrs;
- int32_t stride = 9;
- int32_t addrsize;
- int inputsize;
- int32_t tbi = 0;
+ int32_t stride;
+ int addrsize, inputsize;
TCR *tcr = regime_tcr(env, mmu_idx);
int ap, ns, xn, pxn;
uint32_t el = regime_el(env, mmu_idx);
- bool ttbr1_valid = true;
+ bool ttbr1_valid;
uint64_t descaddrmask;
bool aarch64 = arm_el_is_aa64(env, el);
@@ -9643,91 +10465,44 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
* support for those page table walks.
*/
if (aarch64) {
+ param = aa64_va_parameters(env, address, mmu_idx,
+ access_type != MMU_INST_FETCH);
level = 0;
- addrsize = 64;
- if (el > 1) {
- if (mmu_idx != ARMMMUIdx_S2NS) {
- tbi = extract64(tcr->raw_tcr, 20, 1);
- }
- } else {
- if (extract64(address, 55, 1)) {
- tbi = extract64(tcr->raw_tcr, 38, 1);
- } else {
- tbi = extract64(tcr->raw_tcr, 37, 1);
- }
- }
- tbi *= 8;
-
/* If we are in 64-bit EL2 or EL3 then there is no TTBR1, so mark it
* invalid.
*/
- if (el > 1) {
- ttbr1_valid = false;
- }
+ ttbr1_valid = (el < 2);
+ addrsize = 64 - 8 * param.tbi;
+ inputsize = 64 - param.tsz;
} else {
+ param = aa32_va_parameters(env, address, mmu_idx);
level = 1;
- addrsize = 32;
/* There is no TTBR1 for EL2 */
- if (el == 2) {
- ttbr1_valid = false;
- }
+ ttbr1_valid = (el != 2);
+ addrsize = (mmu_idx == ARMMMUIdx_S2NS ? 40 : 32);
+ inputsize = addrsize - param.tsz;
}
- /* Determine whether this address is in the region controlled by
- * TTBR0 or TTBR1 (or if it is in neither region and should fault).
- * This is a Non-secure PL0/1 stage 1 translation, so controlled by
- * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32:
+ /*
+ * We determined the region when collecting the parameters, but we
+ * have not yet validated that the address is valid for the region.
+ * Extract the top bits and verify that they all match select.
*/
- if (aarch64) {
- /* AArch64 translation. */
- t0sz = extract32(tcr->raw_tcr, 0, 6);
- t0sz = MIN(t0sz, 39);
- t0sz = MAX(t0sz, 16);
- } else if (mmu_idx != ARMMMUIdx_S2NS) {
- /* AArch32 stage 1 translation. */
- t0sz = extract32(tcr->raw_tcr, 0, 3);
- } else {
- /* AArch32 stage 2 translation. */
- bool sext = extract32(tcr->raw_tcr, 4, 1);
- bool sign = extract32(tcr->raw_tcr, 3, 1);
- /* Address size is 40-bit for a stage 2 translation,
- * and t0sz can be negative (from -8 to 7),
- * so we need to adjust it to use the TTBR selecting logic below.
- */
- addrsize = 40;
- t0sz = sextract32(tcr->raw_tcr, 0, 4) + 8;
-
- /* If the sign-extend bit is not the same as t0sz[3], the result
- * is unpredictable. Flag this as a guest error. */
- if (sign != sext) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "AArch32: VTCR.S / VTCR.T0SZ[3] mismatch\n");
- }
- }
- t1sz = extract32(tcr->raw_tcr, 16, 6);
- if (aarch64) {
- t1sz = MIN(t1sz, 39);
- t1sz = MAX(t1sz, 16);
- }
- if (t0sz && !extract64(address, addrsize - t0sz, t0sz - tbi)) {
- /* there is a ttbr0 region and we are in it (high bits all zero) */
- ttbr_select = 0;
- } else if (ttbr1_valid && t1sz &&
- !extract64(~address, addrsize - t1sz, t1sz - tbi)) {
- /* there is a ttbr1 region and we are in it (high bits all one) */
- ttbr_select = 1;
- } else if (!t0sz) {
- /* ttbr0 region is "everything not in the ttbr1 region" */
- ttbr_select = 0;
- } else if (!t1sz && ttbr1_valid) {
- /* ttbr1 region is "everything not in the ttbr0 region" */
- ttbr_select = 1;
- } else {
- /* in the gap between the two regions, this is a Translation fault */
+ top_bits = sextract64(address, inputsize, addrsize - inputsize);
+ if (-top_bits != param.select || (param.select && !ttbr1_valid)) {
+ /* In the gap between the two regions, this is a Translation fault */
fault_type = ARMFault_Translation;
goto do_fault;
}
+ if (param.using64k) {
+ stride = 13;
+ } else if (param.using16k) {
+ stride = 11;
+ } else {
+ stride = 9;
+ }
+
/* Note that QEMU ignores shareability and cacheability attributes,
* so we don't need to do anything with the SH, ORGN, IRGN fields
* in the TTBCR. Similarly, TTBCR:A1 selects whether we get the
@@ -9735,42 +10510,13 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
* implement any ASID-like capability so we can ignore it (instead
* we will always flush the TLB any time the ASID is changed).
*/
- if (ttbr_select == 0) {
- ttbr = regime_ttbr(env, mmu_idx, 0);
- if (el < 2) {
- epd = extract32(tcr->raw_tcr, 7, 1);
- }
- inputsize = addrsize - t0sz;
-
- tg = extract32(tcr->raw_tcr, 14, 2);
- if (tg == 1) { /* 64KB pages */
- stride = 13;
- }
- if (tg == 2) { /* 16KB pages */
- stride = 11;
- }
- } else {
- /* We should only be here if TTBR1 is valid */
- assert(ttbr1_valid);
-
- ttbr = regime_ttbr(env, mmu_idx, 1);
- epd = extract32(tcr->raw_tcr, 23, 1);
- inputsize = addrsize - t1sz;
-
- tg = extract32(tcr->raw_tcr, 30, 2);
- if (tg == 3) { /* 64KB pages */
- stride = 13;
- }
- if (tg == 1) { /* 16KB pages */
- stride = 11;
- }
- }
+ ttbr = regime_ttbr(env, mmu_idx, param.select);
/* Here we should have set up all the parameters for the translation:
* inputsize, ttbr, epd, stride, tbi
*/
- if (epd) {
+ if (param.epd) {
/* Translation table walk disabled => Translation fault on TLB miss
* Note: This is always 0 on 64-bit EL2 and EL3.
*/
@@ -9857,7 +10603,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
descaddr = descriptor & descaddrmask;
if ((descriptor & 2) && (level < 3)) {
- /* Table entry. The top five bits are attributes which may
+ /* Table entry. The top five bits are attributes which may
* propagate down through lower levels of the table (and
* which are all arranged so that 0 means "no effect", so
* we can gather them up by ORing in the bits at each level).
@@ -9882,15 +10628,17 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
break;
}
/* Merge in attributes from table descriptors */
- attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */
- attrs |= extract32(tableattrs, 3, 1) << 5; /* APTable[1] => AP[2] */
+ attrs |= nstable << 3; /* NS */
+ if (param.hpd) {
+ /* HPD disables all the table attributes except NSTable. */
+ break;
+ }
+ attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */
/* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1
* means "force PL1 access only", which means forcing AP[1] to 0.
*/
- if (extract32(tableattrs, 2, 1)) {
- attrs &= ~(1 << 4);
- }
- attrs |= nstable << 3; /* NS */
+ attrs &= ~(extract32(tableattrs, 2, 1) << 4); /* !APT[0] => AP[1] */
+ attrs |= extract32(tableattrs, 3, 1) << 5; /* APT[1] => AP[2] */
break;
}
/* Here descaddr is the final physical address, and attributes
@@ -10917,7 +11665,7 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
int prot;
bool ret;
ARMMMUFaultInfo fi = {};
- ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
+ ARMMMUIdx mmu_idx = arm_mmu_idx(env);
*attrs = (MemTxAttrs) {};
@@ -12793,22 +13541,99 @@ int fp_exception_el(CPUARMState *env, int cur_el)
return 0;
}
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env,
+ bool secstate, bool priv)
+{
+ ARMMMUIdx mmu_idx = ARM_MMU_IDX_M;
+
+ if (priv) {
+ mmu_idx |= ARM_MMU_IDX_M_PRIV;
+ }
+
+ if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) {
+ mmu_idx |= ARM_MMU_IDX_M_NEGPRI;
+ }
+
+ if (secstate) {
+ mmu_idx |= ARM_MMU_IDX_M_S;
+ }
+
+ return mmu_idx;
+}
+
+/* Return the MMU index for a v7M CPU in the specified security state */
+ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
+{
+ bool priv = arm_current_el(env) != 0;
+
+ return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv);
+}
+
+ARMMMUIdx arm_mmu_idx(CPUARMState *env)
+{
+ int el;
+
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ return arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
+ }
+
+ el = arm_current_el(env);
+ if (el < 2 && arm_is_secure_below_el3(env)) {
+ return ARMMMUIdx_S1SE0 + el;
+ } else {
+ return ARMMMUIdx_S12NSE0 + el;
+ }
+}
+
+int cpu_mmu_index(CPUARMState *env, bool ifetch)
+{
+ return arm_to_core_mmu_idx(arm_mmu_idx(env));
+}
+
+#ifndef CONFIG_USER_ONLY
+ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
+{
+ return stage_1_mmu_idx(arm_mmu_idx(env));
+}
+#endif
+
void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
- ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false));
+ ARMMMUIdx mmu_idx = arm_mmu_idx(env);
int current_el = arm_current_el(env);
int fp_el = fp_exception_el(env, current_el);
- uint32_t flags;
+ uint32_t flags = 0;
if (is_a64(env)) {
ARMCPU *cpu = arm_env_get_cpu(env);
*pc = env->pc;
- flags = ARM_TBFLAG_AARCH64_STATE_MASK;
- /* Get control bits for tagged addresses */
- flags |= (arm_regime_tbi0(env, mmu_idx) << ARM_TBFLAG_TBI0_SHIFT);
- flags |= (arm_regime_tbi1(env, mmu_idx) << ARM_TBFLAG_TBI1_SHIFT);
+ flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1);
+
+#ifndef CONFIG_USER_ONLY
+ /*
+ * Get control bits for tagged addresses. Note that the
+ * translator only uses this for instruction addresses.
+ */
+ {
+ ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx);
+ ARMVAParameters p0 = aa64_va_parameters_both(env, 0, stage1);
+ int tbii, tbid;
+
+ /* FIXME: ARMv8.1-VHE S2 translation regime. */
+ if (regime_el(env, stage1) < 2) {
+ ARMVAParameters p1 = aa64_va_parameters_both(env, -1, stage1);
+ tbid = (p1.tbi << 1) | p0.tbi;
+ tbii = tbid & ~((p1.tbid << 1) | p0.tbid);
+ } else {
+ tbid = p0.tbi;
+ tbii = tbid & !p0.tbid;
+ }
+
+ flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii);
+ }
+#endif
if (cpu_isar_feature(aa64_sve, cpu)) {
int sve_el = sve_exception_el(env, current_el);
@@ -12822,28 +13647,44 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
} else {
zcr_len = sve_zcr_len_for_el(env, current_el);
}
- flags |= sve_el << ARM_TBFLAG_SVEEXC_EL_SHIFT;
- flags |= zcr_len << ARM_TBFLAG_ZCR_LEN_SHIFT;
+ flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el);
+ flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
+ }
+
+ if (cpu_isar_feature(aa64_pauth, cpu)) {
+ /*
+ * In order to save space in flags, we record only whether
+ * pauth is "inactive", meaning all insns are implemented as
+ * a nop, or "active" when some action must be performed.
+ * The decision of which action to take is left to a helper.
+ */
+ uint64_t sctlr;
+ if (current_el == 0) {
+ /* FIXME: ARMv8.1-VHE S2 translation regime. */
+ sctlr = env->cp15.sctlr_el[1];
+ } else {
+ sctlr = env->cp15.sctlr_el[current_el];
+ }
+ if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) {
+ flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1);
+ }
}
} else {
*pc = env->regs[15];
- flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
- | (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
- | (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
- | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
- | (arm_sctlr_b(env) << ARM_TBFLAG_SCTLR_B_SHIFT);
- if (!(access_secure_reg(env))) {
- flags |= ARM_TBFLAG_NS_MASK;
- }
+ flags = FIELD_DP32(flags, TBFLAG_A32, THUMB, env->thumb);
+ flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN, env->vfp.vec_len);
+ flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE, env->vfp.vec_stride);
+ flags = FIELD_DP32(flags, TBFLAG_A32, CONDEXEC, env->condexec_bits);
+ flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, arm_sctlr_b(env));
+ flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env));
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
|| arm_el_is_aa64(env, 1)) {
- flags |= ARM_TBFLAG_VFPEN_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
- flags |= (extract32(env->cp15.c15_cpar, 0, 2)
- << ARM_TBFLAG_XSCALE_CPAR_SHIFT);
+ flags = FIELD_DP32(flags, TBFLAG_A32, XSCALE_CPAR, env->cp15.c15_cpar);
}
- flags |= (arm_to_core_mmu_idx(mmu_idx) << ARM_TBFLAG_MMUIDX_SHIFT);
+ flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, arm_to_core_mmu_idx(mmu_idx));
/* The SS_ACTIVE and PSTATE_SS bits correspond to the state machine
* states defined in the ARM ARM for software singlestep:
@@ -12853,24 +13694,24 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
* 1 1 Active-not-pending
*/
if (arm_singlestep_active(env)) {
- flags |= ARM_TBFLAG_SS_ACTIVE_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1);
if (is_a64(env)) {
if (env->pstate & PSTATE_SS) {
- flags |= ARM_TBFLAG_PSTATE_SS_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
}
} else {
if (env->uncached_cpsr & PSTATE_SS) {
- flags |= ARM_TBFLAG_PSTATE_SS_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1);
}
}
}
if (arm_cpu_data_is_big_endian(env)) {
- flags |= ARM_TBFLAG_BE_DATA_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1);
}
- flags |= fp_el << ARM_TBFLAG_FPEXC_EL_SHIFT;
+ flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el);
if (arm_v7m_is_handler_mode(env)) {
- flags |= ARM_TBFLAG_HANDLER_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_A32, HANDLER, 1);
}
/* v8M always applies stack limit checks unless CCR.STKOFHFNMIGN is
@@ -12880,7 +13721,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
arm_feature(env, ARM_FEATURE_M) &&
!((mmu_idx & ARM_MMU_IDX_M_NEGPRI) &&
(env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) {
- flags |= ARM_TBFLAG_STACKCHECK_MASK;
+ flags = FIELD_DP32(flags, TBFLAG_A32, STACKCHECK, 1);
}
*pflags = flags;
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 8c9590091b..53a38188c6 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -79,7 +79,6 @@ DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
DEF_HELPER_3(msr_i_pstate, void, env, i32, i32)
DEF_HELPER_1(clear_pstate_ss, void, env)
-DEF_HELPER_1(exception_return, void, env)
DEF_HELPER_2(get_r13_banked, i32, env, i32)
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
diff --git a/target/arm/idau.h b/target/arm/idau.h
index cac27b95fa..7c0e4e3776 100644
--- a/target/arm/idau.h
+++ b/target/arm/idau.h
@@ -38,9 +38,7 @@
#define IDAU_INTERFACE_GET_CLASS(obj) \
OBJECT_GET_CLASS(IDAUInterfaceClass, (obj), TYPE_IDAU_INTERFACE)
-typedef struct IDAUInterface {
- Object parent;
-} IDAUInterface;
+typedef struct IDAUInterface IDAUInterface;
#define IREGION_NOTVALID -1
diff --git a/target/arm/internals.h b/target/arm/internals.h
index d208b70a64..a6fd4582b2 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -104,6 +104,13 @@ void QEMU_NORETURN raise_exception(CPUARMState *env, uint32_t excp,
uint32_t syndrome, uint32_t target_el);
/*
+ * Similarly, but also use unwinding to restore cpu state.
+ */
+void QEMU_NORETURN raise_exception_ra(CPUARMState *env, uint32_t excp,
+ uint32_t syndrome, uint32_t target_el,
+ uintptr_t ra);
+
+/*
* For AArch64, map a given EL to an index in the banked_spsr array.
* Note that this mapping and the AArch32 mapping defined in bank_number()
* must agree such that the AArch64<->AArch32 SPSRs have the architecturally
@@ -229,7 +236,8 @@ static inline unsigned int arm_pamax(ARMCPU *cpu)
[4] = 44,
[5] = 48,
};
- unsigned int parange = extract32(cpu->id_aa64mmfr0, 0, 4);
+ unsigned int parange =
+ FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
/* id_aa64mmfr0 is a read-only register so values outside of the
* supported mappings can be considered an implementation error. */
@@ -258,6 +266,7 @@ enum arm_exception_class {
EC_CP14DTTRAP = 0x06,
EC_ADVSIMDFPACCESSTRAP = 0x07,
EC_FPIDTRAP = 0x08,
+ EC_PACTRAP = 0x09,
EC_CP14RRTTRAP = 0x0c,
EC_ILLEGALSTATE = 0x0e,
EC_AA32_SVC = 0x11,
@@ -425,6 +434,11 @@ static inline uint32_t syn_sve_access_trap(void)
return EC_SVEACCESSTRAP << ARM_EL_EC_SHIFT;
}
+static inline uint32_t syn_pactrap(void)
+{
+ return EC_PACTRAP << ARM_EL_EC_SHIFT;
+}
+
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
{
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)
@@ -905,4 +919,68 @@ void arm_cpu_update_virq(ARMCPU *cpu);
*/
void arm_cpu_update_vfiq(ARMCPU *cpu);
+/**
+ * arm_mmu_idx:
+ * @env: The cpu environment
+ *
+ * Return the full ARMMMUIdx for the current translation regime.
+ */
+ARMMMUIdx arm_mmu_idx(CPUARMState *env);
+
+/**
+ * arm_stage1_mmu_idx:
+ * @env: The cpu environment
+ *
+ * Return the ARMMMUIdx for the stage1 traversal for the current regime.
+ */
+#ifdef CONFIG_USER_ONLY
+static inline ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
+{
+ return ARMMMUIdx_S1NSE0;
+}
+#else
+ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env);
+#endif
+
+/*
+ * Parameters of a given virtual address, as extracted from the
+ * translation control register (TCR) for a given regime.
+ */
+typedef struct ARMVAParameters {
+ unsigned tsz : 8;
+ unsigned select : 1;
+ bool tbi : 1;
+ bool tbid : 1;
+ bool epd : 1;
+ bool hpd : 1;
+ bool using16k : 1;
+ bool using64k : 1;
+} ARMVAParameters;
+
+#ifdef CONFIG_USER_ONLY
+static inline ARMVAParameters aa64_va_parameters_both(CPUARMState *env,
+ uint64_t va,
+ ARMMMUIdx mmu_idx)
+{
+ return (ARMVAParameters) {
+ /* 48-bit address space */
+ .tsz = 16,
+ /* We can't handle tagged addresses properly in user-only mode */
+ .tbi = false,
+ };
+}
+
+static inline ARMVAParameters aa64_va_parameters(CPUARMState *env,
+ uint64_t va,
+ ARMMMUIdx mmu_idx, bool data)
+{
+ return aa64_va_parameters_both(env, va, mmu_idx);
+}
+#else
+ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va,
+ ARMMMUIdx mmu_idx);
+ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
+ ARMMMUIdx mmu_idx, bool data);
+#endif
+
#endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 44dd0ce6ce..e00ccf9c98 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -206,7 +206,7 @@ typedef struct KVMDevice {
int dev_fd;
} KVMDevice;
-static QSLIST_HEAD(kvm_devices_head, KVMDevice) kvm_devices_head;
+static QSLIST_HEAD(, KVMDevice) kvm_devices_head;
static void kvm_arm_devlistener_add(MemoryListener *listener,
MemoryRegionSection *section)
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 0a502091e7..089af9c5f0 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -538,6 +538,10 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
ARM64_SYS_REG(3, 0, 0, 6, 0));
err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64isar1,
ARM64_SYS_REG(3, 0, 0, 6, 1));
+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr0,
+ ARM64_SYS_REG(3, 0, 0, 7, 0));
+ err |= read_sys_reg64(fdarray[2], &ahcf->isar.id_aa64mmfr1,
+ ARM64_SYS_REG(3, 0, 0, 7, 1));
/*
* Note that if AArch32 support is not present in the host,
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 7a22ebc209..b292549614 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -620,6 +620,10 @@ static int cpu_pre_save(void *opaque)
{
ARMCPU *cpu = opaque;
+ if (!kvm_enabled()) {
+ pmu_op_start(&cpu->env);
+ }
+
if (kvm_enabled()) {
if (!write_kvmstate_to_list(cpu)) {
/* This should never fail */
@@ -641,6 +645,17 @@ static int cpu_pre_save(void *opaque)
return 0;
}
+static int cpu_post_save(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ if (!kvm_enabled()) {
+ pmu_op_finish(&cpu->env);
+ }
+
+ return 0;
+}
+
static int cpu_pre_load(void *opaque)
{
ARMCPU *cpu = opaque;
@@ -653,6 +668,10 @@ static int cpu_pre_load(void *opaque)
*/
env->irq_line_state = UINT32_MAX;
+ if (!kvm_enabled()) {
+ pmu_op_start(&cpu->env);
+ }
+
return 0;
}
@@ -721,6 +740,10 @@ static int cpu_post_load(void *opaque, int version_id)
hw_breakpoint_update_all(cpu);
hw_watchpoint_update_all(cpu);
+ if (!kvm_enabled()) {
+ pmu_op_finish(&cpu->env);
+ }
+
return 0;
}
@@ -729,6 +752,7 @@ const VMStateDescription vmstate_arm_cpu = {
.version_id = 22,
.minimum_version_id = 22,
.pre_save = cpu_pre_save,
+ .post_save = cpu_post_save,
.pre_load = cpu_pre_load,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 0d6e89e474..c998eadfaa 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -28,13 +28,12 @@
#define SIGNBIT (uint32_t)0x80000000
#define SIGNBIT64 ((uint64_t)1 << 63)
-void raise_exception(CPUARMState *env, uint32_t excp,
- uint32_t syndrome, uint32_t target_el)
+static CPUState *do_raise_exception(CPUARMState *env, uint32_t excp,
+ uint32_t syndrome, uint32_t target_el)
{
CPUState *cs = CPU(arm_env_get_cpu(env));
- if ((env->cp15.hcr_el2 & HCR_TGE) &&
- target_el == 1 && !arm_is_secure(env)) {
+ if (target_el == 1 && (arm_hcr_el2_eff(env) & HCR_TGE)) {
/*
* Redirect NS EL1 exceptions to NS EL2. These are reported with
* their original syndrome register value, with the exception of
@@ -51,9 +50,24 @@ void raise_exception(CPUARMState *env, uint32_t excp,
cs->exception_index = excp;
env->exception.syndrome = syndrome;
env->exception.target_el = target_el;
+
+ return cs;
+}
+
+void raise_exception(CPUARMState *env, uint32_t excp,
+ uint32_t syndrome, uint32_t target_el)
+{
+ CPUState *cs = do_raise_exception(env, excp, syndrome, target_el);
cpu_loop_exit(cs);
}
+void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
+ uint32_t target_el, uintptr_t ra)
+{
+ CPUState *cs = do_raise_exception(env, excp, syndrome, target_el);
+ cpu_loop_exit_restore(cs, ra);
+}
+
static int exception_target_el(CPUARMState *env)
{
int target_el = MAX(1, arm_current_el(env));
@@ -428,9 +442,9 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
* No need for ARM_FEATURE check as if HCR_EL2 doesn't exist the
* bits will be zero indicating no trap.
*/
- if (cur_el < 2 && !arm_is_secure(env)) {
- mask = (is_wfe) ? HCR_TWE : HCR_TWI;
- if (env->cp15.hcr_el2 & mask) {
+ if (cur_el < 2) {
+ mask = is_wfe ? HCR_TWE : HCR_TWI;
+ if (arm_hcr_el2_eff(env) & mask) {
return 2;
}
}
@@ -995,7 +1009,7 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
exception_target_el(env));
}
- if (!secure && cur_el == 1 && (env->cp15.hcr_el2 & HCR_TSC)) {
+ if (cur_el == 1 && (arm_hcr_el2_eff(env) & HCR_TSC)) {
/* In NS EL1, HCR controlled routing to EL2 has priority over SMD.
* We also want an EL2 guest to be able to forbid its EL1 from
* making PSCI calls into QEMU's "firmware" via HCR.TSC.
@@ -1015,162 +1029,6 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
}
}
-static int el_from_spsr(uint32_t spsr)
-{
- /* Return the exception level that this SPSR is requesting a return to,
- * or -1 if it is invalid (an illegal return)
- */
- if (spsr & PSTATE_nRW) {
- switch (spsr & CPSR_M) {
- case ARM_CPU_MODE_USR:
- return 0;
- case ARM_CPU_MODE_HYP:
- return 2;
- case ARM_CPU_MODE_FIQ:
- case ARM_CPU_MODE_IRQ:
- case ARM_CPU_MODE_SVC:
- case ARM_CPU_MODE_ABT:
- case ARM_CPU_MODE_UND:
- case ARM_CPU_MODE_SYS:
- return 1;
- case ARM_CPU_MODE_MON:
- /* Returning to Mon from AArch64 is never possible,
- * so this is an illegal return.
- */
- default:
- return -1;
- }
- } else {
- if (extract32(spsr, 1, 1)) {
- /* Return with reserved M[1] bit set */
- return -1;
- }
- if (extract32(spsr, 0, 4) == 1) {
- /* return to EL0 with M[0] bit set */
- return -1;
- }
- return extract32(spsr, 2, 2);
- }
-}
-
-void HELPER(exception_return)(CPUARMState *env)
-{
- int cur_el = arm_current_el(env);
- unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
- uint32_t spsr = env->banked_spsr[spsr_idx];
- int new_el;
- bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
-
- aarch64_save_sp(env, cur_el);
-
- arm_clear_exclusive(env);
-
- /* We must squash the PSTATE.SS bit to zero unless both of the
- * following hold:
- * 1. debug exceptions are currently disabled
- * 2. singlestep will be active in the EL we return to
- * We check 1 here and 2 after we've done the pstate/cpsr write() to
- * transition to the EL we're going to.
- */
- if (arm_generate_debug_exceptions(env)) {
- spsr &= ~PSTATE_SS;
- }
-
- new_el = el_from_spsr(spsr);
- if (new_el == -1) {
- goto illegal_return;
- }
- if (new_el > cur_el
- || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
- /* Disallow return to an EL which is unimplemented or higher
- * than the current one.
- */
- goto illegal_return;
- }
-
- if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) {
- /* Return to an EL which is configured for a different register width */
- goto illegal_return;
- }
-
- if (new_el == 2 && arm_is_secure_below_el3(env)) {
- /* Return to the non-existent secure-EL2 */
- goto illegal_return;
- }
-
- if (new_el == 1 && (env->cp15.hcr_el2 & HCR_TGE)
- && !arm_is_secure_below_el3(env)) {
- goto illegal_return;
- }
-
- qemu_mutex_lock_iothread();
- arm_call_pre_el_change_hook(arm_env_get_cpu(env));
- qemu_mutex_unlock_iothread();
-
- if (!return_to_aa64) {
- env->aarch64 = 0;
- /* We do a raw CPSR write because aarch64_sync_64_to_32()
- * will sort the register banks out for us, and we've already
- * caught all the bad-mode cases in el_from_spsr().
- */
- cpsr_write(env, spsr, ~0, CPSRWriteRaw);
- if (!arm_singlestep_active(env)) {
- env->uncached_cpsr &= ~PSTATE_SS;
- }
- aarch64_sync_64_to_32(env);
-
- if (spsr & CPSR_T) {
- env->regs[15] = env->elr_el[cur_el] & ~0x1;
- } else {
- env->regs[15] = env->elr_el[cur_el] & ~0x3;
- }
- qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
- "AArch32 EL%d PC 0x%" PRIx32 "\n",
- cur_el, new_el, env->regs[15]);
- } else {
- env->aarch64 = 1;
- pstate_write(env, spsr);
- if (!arm_singlestep_active(env)) {
- env->pstate &= ~PSTATE_SS;
- }
- aarch64_restore_sp(env, new_el);
- env->pc = env->elr_el[cur_el];
- qemu_log_mask(CPU_LOG_INT, "Exception return from AArch64 EL%d to "
- "AArch64 EL%d PC 0x%" PRIx64 "\n",
- cur_el, new_el, env->pc);
- }
- /*
- * Note that cur_el can never be 0. If new_el is 0, then
- * el0_a64 is return_to_aa64, else el0_a64 is ignored.
- */
- aarch64_sve_change_el(env, cur_el, new_el, return_to_aa64);
-
- qemu_mutex_lock_iothread();
- arm_call_el_change_hook(arm_env_get_cpu(env));
- qemu_mutex_unlock_iothread();
-
- return;
-
-illegal_return:
- /* Illegal return events of various kinds have architecturally
- * mandated behaviour:
- * restore NZCV and DAIF from SPSR_ELx
- * set PSTATE.IL
- * restore PC from ELR_ELx
- * no change to exception level, execution state or stack pointer
- */
- env->pstate |= PSTATE_IL;
- env->pc = env->elr_el[cur_el];
- spsr &= PSTATE_NZCV | PSTATE_DAIF;
- spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
- pstate_write(env, spsr);
- if (!arm_singlestep_active(env)) {
- env->pstate &= ~PSTATE_SS;
- }
- qemu_log_mask(LOG_GUEST_ERROR, "Illegal exception return at EL%d: "
- "resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc);
-}
-
/* Return true if the linked breakpoint entry lbn passes its checks */
static bool linked_bp_matches(ARMCPU *cpu, int lbn)
{
diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c
new file mode 100644
index 0000000000..d750f96edf
--- /dev/null
+++ b/target/arm/pauth_helper.c
@@ -0,0 +1,497 @@
+/*
+ * ARM v8.3-PAuth Operations
+ *
+ * Copyright (c) 2019 Linaro, Ltd.
+ *
+ * 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 "qemu/osdep.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/helper-proto.h"
+#include "tcg/tcg-gvec-desc.h"
+
+
+static uint64_t pac_cell_shuffle(uint64_t i)
+{
+ uint64_t o = 0;
+
+ o |= extract64(i, 52, 4);
+ o |= extract64(i, 24, 4) << 4;
+ o |= extract64(i, 44, 4) << 8;
+ o |= extract64(i, 0, 4) << 12;
+
+ o |= extract64(i, 28, 4) << 16;
+ o |= extract64(i, 48, 4) << 20;
+ o |= extract64(i, 4, 4) << 24;
+ o |= extract64(i, 40, 4) << 28;
+
+ o |= extract64(i, 32, 4) << 32;
+ o |= extract64(i, 12, 4) << 36;
+ o |= extract64(i, 56, 4) << 40;
+ o |= extract64(i, 20, 4) << 44;
+
+ o |= extract64(i, 8, 4) << 48;
+ o |= extract64(i, 36, 4) << 52;
+ o |= extract64(i, 16, 4) << 56;
+ o |= extract64(i, 60, 4) << 60;
+
+ return o;
+}
+
+static uint64_t pac_cell_inv_shuffle(uint64_t i)
+{
+ uint64_t o = 0;
+
+ o |= extract64(i, 12, 4);
+ o |= extract64(i, 24, 4) << 4;
+ o |= extract64(i, 48, 4) << 8;
+ o |= extract64(i, 36, 4) << 12;
+
+ o |= extract64(i, 56, 4) << 16;
+ o |= extract64(i, 44, 4) << 20;
+ o |= extract64(i, 4, 4) << 24;
+ o |= extract64(i, 16, 4) << 28;
+
+ o |= i & MAKE_64BIT_MASK(32, 4);
+ o |= extract64(i, 52, 4) << 36;
+ o |= extract64(i, 28, 4) << 40;
+ o |= extract64(i, 8, 4) << 44;
+
+ o |= extract64(i, 20, 4) << 48;
+ o |= extract64(i, 0, 4) << 52;
+ o |= extract64(i, 40, 4) << 56;
+ o |= i & MAKE_64BIT_MASK(60, 4);
+
+ return o;
+}
+
+static uint64_t pac_sub(uint64_t i)
+{
+ static const uint8_t sub[16] = {
+ 0xb, 0x6, 0x8, 0xf, 0xc, 0x0, 0x9, 0xe,
+ 0x3, 0x7, 0x4, 0x5, 0xd, 0x2, 0x1, 0xa,
+ };
+ uint64_t o = 0;
+ int b;
+
+ for (b = 0; b < 64; b += 16) {
+ o |= (uint64_t)sub[(i >> b) & 0xf] << b;
+ }
+ return o;
+}
+
+static uint64_t pac_inv_sub(uint64_t i)
+{
+ static const uint8_t inv_sub[16] = {
+ 0x5, 0xe, 0xd, 0x8, 0xa, 0xb, 0x1, 0x9,
+ 0x2, 0x6, 0xf, 0x0, 0x4, 0xc, 0x7, 0x3,
+ };
+ uint64_t o = 0;
+ int b;
+
+ for (b = 0; b < 64; b += 16) {
+ o |= (uint64_t)inv_sub[(i >> b) & 0xf] << b;
+ }
+ return o;
+}
+
+static int rot_cell(int cell, int n)
+{
+ /* 4-bit rotate left by n. */
+ cell |= cell << 4;
+ return extract32(cell, 4 - n, 4);
+}
+
+static uint64_t pac_mult(uint64_t i)
+{
+ uint64_t o = 0;
+ int b;
+
+ for (b = 0; b < 4 * 4; b += 4) {
+ int i0, i4, i8, ic, t0, t1, t2, t3;
+
+ i0 = extract64(i, b, 4);
+ i4 = extract64(i, b + 4 * 4, 4);
+ i8 = extract64(i, b + 8 * 4, 4);
+ ic = extract64(i, b + 12 * 4, 4);
+
+ t0 = rot_cell(i8, 1) ^ rot_cell(i4, 2) ^ rot_cell(i0, 1);
+ t1 = rot_cell(ic, 1) ^ rot_cell(i4, 1) ^ rot_cell(i0, 2);
+ t2 = rot_cell(ic, 2) ^ rot_cell(i8, 1) ^ rot_cell(i0, 1);
+ t3 = rot_cell(ic, 1) ^ rot_cell(i8, 2) ^ rot_cell(i4, 1);
+
+ o |= (uint64_t)t3 << b;
+ o |= (uint64_t)t2 << (b + 4 * 4);
+ o |= (uint64_t)t1 << (b + 8 * 4);
+ o |= (uint64_t)t0 << (b + 12 * 4);
+ }
+ return o;
+}
+
+static uint64_t tweak_cell_rot(uint64_t cell)
+{
+ return (cell >> 1) | (((cell ^ (cell >> 1)) & 1) << 3);
+}
+
+static uint64_t tweak_shuffle(uint64_t i)
+{
+ uint64_t o = 0;
+
+ o |= extract64(i, 16, 4) << 0;
+ o |= extract64(i, 20, 4) << 4;
+ o |= tweak_cell_rot(extract64(i, 24, 4)) << 8;
+ o |= extract64(i, 28, 4) << 12;
+
+ o |= tweak_cell_rot(extract64(i, 44, 4)) << 16;
+ o |= extract64(i, 8, 4) << 20;
+ o |= extract64(i, 12, 4) << 24;
+ o |= tweak_cell_rot(extract64(i, 32, 4)) << 28;
+
+ o |= extract64(i, 48, 4) << 32;
+ o |= extract64(i, 52, 4) << 36;
+ o |= extract64(i, 56, 4) << 40;
+ o |= tweak_cell_rot(extract64(i, 60, 4)) << 44;
+
+ o |= tweak_cell_rot(extract64(i, 0, 4)) << 48;
+ o |= extract64(i, 4, 4) << 52;
+ o |= tweak_cell_rot(extract64(i, 40, 4)) << 56;
+ o |= tweak_cell_rot(extract64(i, 36, 4)) << 60;
+
+ return o;
+}
+
+static uint64_t tweak_cell_inv_rot(uint64_t cell)
+{
+ return ((cell << 1) & 0xf) | ((cell & 1) ^ (cell >> 3));
+}
+
+static uint64_t tweak_inv_shuffle(uint64_t i)
+{
+ uint64_t o = 0;
+
+ o |= tweak_cell_inv_rot(extract64(i, 48, 4));
+ o |= extract64(i, 52, 4) << 4;
+ o |= extract64(i, 20, 4) << 8;
+ o |= extract64(i, 24, 4) << 12;
+
+ o |= extract64(i, 0, 4) << 16;
+ o |= extract64(i, 4, 4) << 20;
+ o |= tweak_cell_inv_rot(extract64(i, 8, 4)) << 24;
+ o |= extract64(i, 12, 4) << 28;
+
+ o |= tweak_cell_inv_rot(extract64(i, 28, 4)) << 32;
+ o |= tweak_cell_inv_rot(extract64(i, 60, 4)) << 36;
+ o |= tweak_cell_inv_rot(extract64(i, 56, 4)) << 40;
+ o |= tweak_cell_inv_rot(extract64(i, 16, 4)) << 44;
+
+ o |= extract64(i, 32, 4) << 48;
+ o |= extract64(i, 36, 4) << 52;
+ o |= extract64(i, 40, 4) << 56;
+ o |= tweak_cell_inv_rot(extract64(i, 44, 4)) << 60;
+
+ return o;
+}
+
+static uint64_t pauth_computepac(uint64_t data, uint64_t modifier,
+ ARMPACKey key)
+{
+ static const uint64_t RC[5] = {
+ 0x0000000000000000ull,
+ 0x13198A2E03707344ull,
+ 0xA4093822299F31D0ull,
+ 0x082EFA98EC4E6C89ull,
+ 0x452821E638D01377ull,
+ };
+ const uint64_t alpha = 0xC0AC29B7C97C50DDull;
+ /*
+ * Note that in the ARM pseudocode, key0 contains bits <127:64>
+ * and key1 contains bits <63:0> of the 128-bit key.
+ */
+ uint64_t key0 = key.hi, key1 = key.lo;
+ uint64_t workingval, runningmod, roundkey, modk0;
+ int i;
+
+ modk0 = (key0 << 63) | ((key0 >> 1) ^ (key0 >> 63));
+ runningmod = modifier;
+ workingval = data ^ key0;
+
+ for (i = 0; i <= 4; ++i) {
+ roundkey = key1 ^ runningmod;
+ workingval ^= roundkey;
+ workingval ^= RC[i];
+ if (i > 0) {
+ workingval = pac_cell_shuffle(workingval);
+ workingval = pac_mult(workingval);
+ }
+ workingval = pac_sub(workingval);
+ runningmod = tweak_shuffle(runningmod);
+ }
+ roundkey = modk0 ^ runningmod;
+ workingval ^= roundkey;
+ workingval = pac_cell_shuffle(workingval);
+ workingval = pac_mult(workingval);
+ workingval = pac_sub(workingval);
+ workingval = pac_cell_shuffle(workingval);
+ workingval = pac_mult(workingval);
+ workingval ^= key1;
+ workingval = pac_cell_inv_shuffle(workingval);
+ workingval = pac_inv_sub(workingval);
+ workingval = pac_mult(workingval);
+ workingval = pac_cell_inv_shuffle(workingval);
+ workingval ^= key0;
+ workingval ^= runningmod;
+ for (i = 0; i <= 4; ++i) {
+ workingval = pac_inv_sub(workingval);
+ if (i < 4) {
+ workingval = pac_mult(workingval);
+ workingval = pac_cell_inv_shuffle(workingval);
+ }
+ runningmod = tweak_inv_shuffle(runningmod);
+ roundkey = key1 ^ runningmod;
+ workingval ^= RC[4 - i];
+ workingval ^= roundkey;
+ workingval ^= alpha;
+ }
+ workingval ^= modk0;
+
+ return workingval;
+}
+
+static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier,
+ ARMPACKey *key, bool data)
+{
+ ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
+ ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
+ uint64_t pac, ext_ptr, ext, test;
+ int bot_bit, top_bit;
+
+ /* If tagged pointers are in use, use ptr<55>, otherwise ptr<63>. */
+ if (param.tbi) {
+ ext = sextract64(ptr, 55, 1);
+ } else {
+ ext = sextract64(ptr, 63, 1);
+ }
+
+ /* Build a pointer with known good extension bits. */
+ top_bit = 64 - 8 * param.tbi;
+ bot_bit = 64 - param.tsz;
+ ext_ptr = deposit64(ptr, bot_bit, top_bit - bot_bit, ext);
+
+ pac = pauth_computepac(ext_ptr, modifier, *key);
+
+ /*
+ * Check if the ptr has good extension bits and corrupt the
+ * pointer authentication code if not.
+ */
+ test = sextract64(ptr, bot_bit, top_bit - bot_bit);
+ if (test != 0 && test != -1) {
+ pac ^= MAKE_64BIT_MASK(top_bit - 1, 1);
+ }
+
+ /*
+ * Preserve the determination between upper and lower at bit 55,
+ * and insert pointer authentication code.
+ */
+ if (param.tbi) {
+ ptr &= ~MAKE_64BIT_MASK(bot_bit, 55 - bot_bit + 1);
+ pac &= MAKE_64BIT_MASK(bot_bit, 54 - bot_bit + 1);
+ } else {
+ ptr &= MAKE_64BIT_MASK(0, bot_bit);
+ pac &= ~(MAKE_64BIT_MASK(55, 1) | MAKE_64BIT_MASK(0, bot_bit));
+ }
+ ext &= MAKE_64BIT_MASK(55, 1);
+ return pac | ext | ptr;
+}
+
+static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param)
+{
+ uint64_t extfield = -param.select;
+ int bot_pac_bit = 64 - param.tsz;
+ int top_pac_bit = 64 - 8 * param.tbi;
+
+ return deposit64(ptr, bot_pac_bit, top_pac_bit - bot_pac_bit, extfield);
+}
+
+static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
+ ARMPACKey *key, bool data, int keynumber)
+{
+ ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
+ ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
+ int bot_bit, top_bit;
+ uint64_t pac, orig_ptr, test;
+
+ orig_ptr = pauth_original_ptr(ptr, param);
+ pac = pauth_computepac(orig_ptr, modifier, *key);
+ bot_bit = 64 - param.tsz;
+ top_bit = 64 - 8 * param.tbi;
+
+ test = (pac ^ ptr) & ~MAKE_64BIT_MASK(55, 1);
+ if (unlikely(extract64(test, bot_bit, top_bit - bot_bit))) {
+ int error_code = (keynumber << 1) | (keynumber ^ 1);
+ if (param.tbi) {
+ return deposit64(ptr, 53, 2, error_code);
+ } else {
+ return deposit64(ptr, 61, 2, error_code);
+ }
+ }
+ return orig_ptr;
+}
+
+static uint64_t pauth_strip(CPUARMState *env, uint64_t ptr, bool data)
+{
+ ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
+ ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
+
+ return pauth_original_ptr(ptr, param);
+}
+
+static void QEMU_NORETURN pauth_trap(CPUARMState *env, int target_el,
+ uintptr_t ra)
+{
+ raise_exception_ra(env, EXCP_UDEF, syn_pactrap(), target_el, ra);
+}
+
+static void pauth_check_trap(CPUARMState *env, int el, uintptr_t ra)
+{
+ if (el < 2 && arm_feature(env, ARM_FEATURE_EL2)) {
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ bool trap = !(hcr & HCR_API);
+ /* FIXME: ARMv8.1-VHE: trap only applies to EL1&0 regime. */
+ /* FIXME: ARMv8.3-NV: HCR_NV trap takes precedence for ERETA[AB]. */
+ if (trap) {
+ pauth_trap(env, 2, ra);
+ }
+ }
+ if (el < 3 && arm_feature(env, ARM_FEATURE_EL3)) {
+ if (!(env->cp15.scr_el3 & SCR_API)) {
+ pauth_trap(env, 3, ra);
+ }
+ }
+}
+
+static bool pauth_key_enabled(CPUARMState *env, int el, uint32_t bit)
+{
+ uint32_t sctlr;
+ if (el == 0) {
+ /* FIXME: ARMv8.1-VHE S2 translation regime. */
+ sctlr = env->cp15.sctlr_el[1];
+ } else {
+ sctlr = env->cp15.sctlr_el[el];
+ }
+ return (sctlr & bit) != 0;
+}
+
+uint64_t HELPER(pacia)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnIA)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_addpac(env, x, y, &env->apia_key, false);
+}
+
+uint64_t HELPER(pacib)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnIB)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_addpac(env, x, y, &env->apib_key, false);
+}
+
+uint64_t HELPER(pacda)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnDA)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_addpac(env, x, y, &env->apda_key, true);
+}
+
+uint64_t HELPER(pacdb)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnDB)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_addpac(env, x, y, &env->apdb_key, true);
+}
+
+uint64_t HELPER(pacga)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ uint64_t pac;
+
+ pauth_check_trap(env, arm_current_el(env), GETPC());
+ pac = pauth_computepac(x, y, env->apga_key);
+
+ return pac & 0xffffffff00000000ull;
+}
+
+uint64_t HELPER(autia)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnIA)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_auth(env, x, y, &env->apia_key, false, 0);
+}
+
+uint64_t HELPER(autib)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnIB)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_auth(env, x, y, &env->apib_key, false, 1);
+}
+
+uint64_t HELPER(autda)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnDA)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_auth(env, x, y, &env->apda_key, true, 0);
+}
+
+uint64_t HELPER(autdb)(CPUARMState *env, uint64_t x, uint64_t y)
+{
+ int el = arm_current_el(env);
+ if (!pauth_key_enabled(env, el, SCTLR_EnDB)) {
+ return x;
+ }
+ pauth_check_trap(env, el, GETPC());
+ return pauth_auth(env, x, y, &env->apdb_key, true, 1);
+}
+
+uint64_t HELPER(xpaci)(CPUARMState *env, uint64_t a)
+{
+ return pauth_strip(env, a, false);
+}
+
+uint64_t HELPER(xpacd)(CPUARMState *env, uint64_t a)
+{
+ return pauth_strip(env, a, true);
+}
diff --git a/target/arm/sve.decode b/target/arm/sve.decode
index e10b689454..4f580a25e7 100644
--- a/target/arm/sve.decode
+++ b/target/arm/sve.decode
@@ -99,6 +99,7 @@
# Two operand with governing predicate, flags setting
@pd_pg_pn_s ........ . s:1 ...... .. pg:4 . rn:4 . rd:4 &rpr_s
+@pd_pg_pn_s0 ........ . . ...... .. pg:4 . rn:4 . rd:4 &rpr_s s=0
# Three operand with unused vector element size
@rd_rn_rm_e0 ........ ... rm:5 ... ... rn:5 rd:5 &rrr_esz esz=0
@@ -667,8 +668,8 @@ BRKPB 00100101 0. 00 .... 11 .... 0 .... 1 .... @pd_pg_pn_pm_s
# SVE partition break condition
BRKA_z 00100101 0. 01000001 .... 0 .... 0 .... @pd_pg_pn_s
BRKB_z 00100101 1. 01000001 .... 0 .... 0 .... @pd_pg_pn_s
-BRKA_m 00100101 0. 01000001 .... 0 .... 1 .... @pd_pg_pn_s
-BRKB_m 00100101 1. 01000001 .... 0 .... 1 .... @pd_pg_pn_s
+BRKA_m 00100101 00 01000001 .... 0 .... 1 .... @pd_pg_pn_s0
+BRKB_m 00100101 10 01000001 .... 0 .... 1 .... @pd_pg_pn_s0
# SVE propagate break to next partition
BRKN 00100101 0. 01100001 .... 0 .... 0 .... @pd_pg_pn_s
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index fd36425f1a..4d28a27c3b 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -261,7 +261,7 @@ void gen_a64_set_pc_im(uint64_t val)
/* Load the PC from a generic TCG variable.
*
* If address tagging is enabled via the TCR TBI bits, then loading
- * an address into the PC will clear out any tag in the it:
+ * an address into the PC will clear out any tag in it:
* + for EL2 and EL3 there is only one TBI bit, and if it is set
* then the address is zero-extended, clearing bits [63:56]
* + for EL0 and EL1, TBI0 controls addresses with bit 55 == 0
@@ -276,56 +276,38 @@ void gen_a64_set_pc_im(uint64_t val)
*/
static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
{
+ /* Note that TBII is TBI1:TBI0. */
+ int tbi = s->tbii;
if (s->current_el <= 1) {
- /* Test if NEITHER or BOTH TBI values are set. If so, no need to
- * examine bit 55 of address, can just generate code.
- * If mixed, then test via generated code
- */
- if (s->tbi0 && s->tbi1) {
- TCGv_i64 tmp_reg = tcg_temp_new_i64();
- /* Both bits set, sign extension from bit 55 into [63:56] will
- * cover both cases
- */
- tcg_gen_shli_i64(tmp_reg, src, 8);
- tcg_gen_sari_i64(cpu_pc, tmp_reg, 8);
- tcg_temp_free_i64(tmp_reg);
- } else if (!s->tbi0 && !s->tbi1) {
- /* Neither bit set, just load it as-is */
- tcg_gen_mov_i64(cpu_pc, src);
- } else {
- TCGv_i64 tcg_tmpval = tcg_temp_new_i64();
- TCGv_i64 tcg_bit55 = tcg_temp_new_i64();
- TCGv_i64 tcg_zero = tcg_const_i64(0);
-
- tcg_gen_andi_i64(tcg_bit55, src, (1ull << 55));
-
- if (s->tbi0) {
- /* tbi0==1, tbi1==0, so 0-fill upper byte if bit 55 = 0 */
- tcg_gen_andi_i64(tcg_tmpval, src,
- 0x00FFFFFFFFFFFFFFull);
- tcg_gen_movcond_i64(TCG_COND_EQ, cpu_pc, tcg_bit55, tcg_zero,
- tcg_tmpval, src);
- } else {
- /* tbi0==0, tbi1==1, so 1-fill upper byte if bit 55 = 1 */
- tcg_gen_ori_i64(tcg_tmpval, src,
- 0xFF00000000000000ull);
- tcg_gen_movcond_i64(TCG_COND_NE, cpu_pc, tcg_bit55, tcg_zero,
- tcg_tmpval, src);
+ if (tbi != 0) {
+ /* Sign-extend from bit 55. */
+ tcg_gen_sextract_i64(cpu_pc, src, 0, 56);
+
+ if (tbi != 3) {
+ TCGv_i64 tcg_zero = tcg_const_i64(0);
+
+ /*
+ * The two TBI bits differ.
+ * If tbi0, then !tbi1: only use the extension if positive.
+ * if !tbi0, then tbi1: only use the extension if negative.
+ */
+ tcg_gen_movcond_i64(tbi == 1 ? TCG_COND_GE : TCG_COND_LT,
+ cpu_pc, cpu_pc, tcg_zero, cpu_pc, src);
+ tcg_temp_free_i64(tcg_zero);
}
- tcg_temp_free_i64(tcg_zero);
- tcg_temp_free_i64(tcg_bit55);
- tcg_temp_free_i64(tcg_tmpval);
+ return;
}
- } else { /* EL > 1 */
- if (s->tbi0) {
+ } else {
+ if (tbi != 0) {
/* Force tag byte to all zero */
- tcg_gen_andi_i64(cpu_pc, src, 0x00FFFFFFFFFFFFFFull);
- } else {
- /* Load unmodified address */
- tcg_gen_mov_i64(cpu_pc, src);
+ tcg_gen_extract_i64(cpu_pc, src, 0, 56);
+ return;
}
}
+
+ /* Load unmodified address */
+ tcg_gen_mov_i64(cpu_pc, src);
}
typedef struct DisasCompare64 {
@@ -1471,33 +1453,102 @@ static void handle_hint(DisasContext *s, uint32_t insn,
}
switch (selector) {
- case 0: /* NOP */
- return;
- case 3: /* WFI */
+ case 0b00000: /* NOP */
+ break;
+ case 0b00011: /* WFI */
s->base.is_jmp = DISAS_WFI;
- return;
+ break;
+ case 0b00001: /* YIELD */
/* When running in MTTCG we don't generate jumps to the yield and
* WFE helpers as it won't affect the scheduling of other vCPUs.
* If we wanted to more completely model WFE/SEV so we don't busy
* spin unnecessarily we would need to do something more involved.
*/
- case 1: /* YIELD */
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
s->base.is_jmp = DISAS_YIELD;
}
- return;
- case 2: /* WFE */
+ break;
+ case 0b00010: /* WFE */
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
s->base.is_jmp = DISAS_WFE;
}
- return;
- case 4: /* SEV */
- case 5: /* SEVL */
+ break;
+ case 0b00100: /* SEV */
+ case 0b00101: /* SEVL */
/* we treat all as NOP at least for now */
- return;
+ break;
+ case 0b00111: /* XPACLRI */
+ if (s->pauth_active) {
+ gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]);
+ }
+ break;
+ case 0b01000: /* PACIA1716 */
+ if (s->pauth_active) {
+ gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
+ }
+ break;
+ case 0b01010: /* PACIB1716 */
+ if (s->pauth_active) {
+ gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
+ }
+ break;
+ case 0b01100: /* AUTIA1716 */
+ if (s->pauth_active) {
+ gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
+ }
+ break;
+ case 0b01110: /* AUTIB1716 */
+ if (s->pauth_active) {
+ gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
+ }
+ break;
+ case 0b11000: /* PACIAZ */
+ if (s->pauth_active) {
+ gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30],
+ new_tmp_a64_zero(s));
+ }
+ break;
+ case 0b11001: /* PACIASP */
+ if (s->pauth_active) {
+ gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
+ }
+ break;
+ case 0b11010: /* PACIBZ */
+ if (s->pauth_active) {
+ gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30],
+ new_tmp_a64_zero(s));
+ }
+ break;
+ case 0b11011: /* PACIBSP */
+ if (s->pauth_active) {
+ gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
+ }
+ break;
+ case 0b11100: /* AUTIAZ */
+ if (s->pauth_active) {
+ gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30],
+ new_tmp_a64_zero(s));
+ }
+ break;
+ case 0b11101: /* AUTIASP */
+ if (s->pauth_active) {
+ gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
+ }
+ break;
+ case 0b11110: /* AUTIBZ */
+ if (s->pauth_active) {
+ gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30],
+ new_tmp_a64_zero(s));
+ }
+ break;
+ case 0b11111: /* AUTIBSP */
+ if (s->pauth_active) {
+ gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
+ }
+ break;
default:
/* default specified as NOP equivalent */
- return;
+ break;
}
}
@@ -1912,6 +1963,8 @@ static void disas_exc(DisasContext *s, uint32_t insn)
static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
{
unsigned int opc, op2, op3, rn, op4;
+ TCGv_i64 dst;
+ TCGv_i64 modifier;
opc = extract32(insn, 21, 4);
op2 = extract32(insn, 16, 5);
@@ -1919,44 +1972,152 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
rn = extract32(insn, 5, 5);
op4 = extract32(insn, 0, 5);
- if (op4 != 0x0 || op3 != 0x0 || op2 != 0x1f) {
- unallocated_encoding(s);
- return;
+ if (op2 != 0x1f) {
+ goto do_unallocated;
}
switch (opc) {
case 0: /* BR */
case 1: /* BLR */
case 2: /* RET */
- gen_a64_set_pc(s, cpu_reg(s, rn));
+ switch (op3) {
+ case 0:
+ /* BR, BLR, RET */
+ if (op4 != 0) {
+ goto do_unallocated;
+ }
+ dst = cpu_reg(s, rn);
+ break;
+
+ case 2:
+ case 3:
+ if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ if (opc == 2) {
+ /* RETAA, RETAB */
+ if (rn != 0x1f || op4 != 0x1f) {
+ goto do_unallocated;
+ }
+ rn = 30;
+ modifier = cpu_X[31];
+ } else {
+ /* BRAAZ, BRABZ, BLRAAZ, BLRABZ */
+ if (op4 != 0x1f) {
+ goto do_unallocated;
+ }
+ modifier = new_tmp_a64_zero(s);
+ }
+ if (s->pauth_active) {
+ dst = new_tmp_a64(s);
+ if (op3 == 2) {
+ gen_helper_autia(dst, cpu_env, cpu_reg(s, rn), modifier);
+ } else {
+ gen_helper_autib(dst, cpu_env, cpu_reg(s, rn), modifier);
+ }
+ } else {
+ dst = cpu_reg(s, rn);
+ }
+ break;
+
+ default:
+ goto do_unallocated;
+ }
+
+ gen_a64_set_pc(s, dst);
/* BLR also needs to load return address */
if (opc == 1) {
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
}
break;
+
+ case 8: /* BRAA */
+ case 9: /* BLRAA */
+ if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ if (op3 != 2 || op3 != 3) {
+ goto do_unallocated;
+ }
+ if (s->pauth_active) {
+ dst = new_tmp_a64(s);
+ modifier = cpu_reg_sp(s, op4);
+ if (op3 == 2) {
+ gen_helper_autia(dst, cpu_env, cpu_reg(s, rn), modifier);
+ } else {
+ gen_helper_autib(dst, cpu_env, cpu_reg(s, rn), modifier);
+ }
+ } else {
+ dst = cpu_reg(s, rn);
+ }
+ gen_a64_set_pc(s, dst);
+ /* BLRAA also needs to load return address */
+ if (opc == 9) {
+ tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
+ }
+ break;
+
case 4: /* ERET */
if (s->current_el == 0) {
- unallocated_encoding(s);
- return;
+ goto do_unallocated;
+ }
+ switch (op3) {
+ case 0: /* ERET */
+ if (op4 != 0) {
+ goto do_unallocated;
+ }
+ dst = tcg_temp_new_i64();
+ tcg_gen_ld_i64(dst, cpu_env,
+ offsetof(CPUARMState, elr_el[s->current_el]));
+ break;
+
+ case 2: /* ERETAA */
+ case 3: /* ERETAB */
+ if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ if (rn != 0x1f || op4 != 0x1f) {
+ goto do_unallocated;
+ }
+ dst = tcg_temp_new_i64();
+ tcg_gen_ld_i64(dst, cpu_env,
+ offsetof(CPUARMState, elr_el[s->current_el]));
+ if (s->pauth_active) {
+ modifier = cpu_X[31];
+ if (op3 == 2) {
+ gen_helper_autia(dst, cpu_env, dst, modifier);
+ } else {
+ gen_helper_autib(dst, cpu_env, dst, modifier);
+ }
+ }
+ break;
+
+ default:
+ goto do_unallocated;
}
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
- gen_helper_exception_return(cpu_env);
+
+ gen_helper_exception_return(cpu_env, dst);
+ tcg_temp_free_i64(dst);
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
}
/* Must exit loop to check un-masked IRQs */
s->base.is_jmp = DISAS_EXIT;
return;
+
case 5: /* DRPS */
- if (rn != 0x1f) {
- unallocated_encoding(s);
+ if (op3 != 0 || op4 != 0 || rn != 0x1f) {
+ goto do_unallocated;
} else {
unsupported_encoding(s, insn);
}
return;
+
default:
+ do_unallocated:
unallocated_encoding(s);
return;
}
@@ -2290,6 +2451,12 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
}
return;
+ case 0x8: /* STLLR */
+ if (!dc_isar_feature(aa64_lor, s)) {
+ break;
+ }
+ /* StoreLORelease is the same as Store-Release for QEMU. */
+ /* fall through */
case 0x9: /* STLR */
/* Generate ISS for non-exclusive accesses including LASR. */
if (rn == 31) {
@@ -2301,6 +2468,12 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
return;
+ case 0xc: /* LDLAR */
+ if (!dc_isar_feature(aa64_lor, s)) {
+ break;
+ }
+ /* LoadLOAcquire is the same as Load-Acquire for QEMU. */
+ /* fall through */
case 0xd: /* LDAR */
/* Generate ISS for non-exclusive accesses including LASR. */
if (rn == 31) {
@@ -2955,6 +3128,64 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
s->be_data | size | MO_ALIGN);
}
+/*
+ * PAC memory operations
+ *
+ * 31 30 27 26 24 22 21 12 11 10 5 0
+ * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
+ * | size | 1 1 1 | V | 0 0 | M S | 1 | imm9 | W | 1 | Rn | Rt |
+ * +------+-------+---+-----+-----+---+--------+---+---+----+-----+
+ *
+ * Rt: the result register
+ * Rn: base address or SP
+ * V: vector flag (always 0 as of v8.3)
+ * M: clear for key DA, set for key DB
+ * W: pre-indexing flag
+ * S: sign for imm9.
+ */
+static void disas_ldst_pac(DisasContext *s, uint32_t insn,
+ int size, int rt, bool is_vector)
+{
+ int rn = extract32(insn, 5, 5);
+ bool is_wback = extract32(insn, 11, 1);
+ bool use_key_a = !extract32(insn, 23, 1);
+ int offset;
+ TCGv_i64 tcg_addr, tcg_rt;
+
+ if (size != 3 || is_vector || !dc_isar_feature(aa64_pauth, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+ tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+ if (s->pauth_active) {
+ if (use_key_a) {
+ gen_helper_autda(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
+ } else {
+ gen_helper_autdb(tcg_addr, cpu_env, tcg_addr, cpu_X[31]);
+ }
+ }
+
+ /* Form the 10-bit signed, scaled offset. */
+ offset = (extract32(insn, 22, 1) << 9) | extract32(insn, 12, 9);
+ offset = sextract32(offset << size, 0, 10 + size);
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+
+ tcg_rt = cpu_reg(s, rt);
+
+ do_gpr_ld(s, tcg_rt, tcg_addr, size, /* is_signed */ false,
+ /* extend */ false, /* iss_valid */ !is_wback,
+ /* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false);
+
+ if (is_wback) {
+ tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
+ }
+}
+
/* Load/store register (all forms) */
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
{
@@ -2980,6 +3211,9 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
case 2:
disas_ldst_reg_roffset(s, insn, opc, size, rt, is_vector);
return;
+ default:
+ disas_ldst_pac(s, insn, size, rt, is_vector);
+ return;
}
break;
case 1:
@@ -4482,38 +4716,197 @@ static void handle_rev16(DisasContext *s, unsigned int sf,
*/
static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
{
- unsigned int sf, opcode, rn, rd;
+ unsigned int sf, opcode, opcode2, rn, rd;
+ TCGv_i64 tcg_rd;
- if (extract32(insn, 29, 1) || extract32(insn, 16, 5)) {
+ if (extract32(insn, 29, 1)) {
unallocated_encoding(s);
return;
}
sf = extract32(insn, 31, 1);
opcode = extract32(insn, 10, 6);
+ opcode2 = extract32(insn, 16, 5);
rn = extract32(insn, 5, 5);
rd = extract32(insn, 0, 5);
- switch (opcode) {
- case 0: /* RBIT */
+#define MAP(SF, O2, O1) ((SF) | (O1 << 1) | (O2 << 7))
+
+ switch (MAP(sf, opcode2, opcode)) {
+ case MAP(0, 0x00, 0x00): /* RBIT */
+ case MAP(1, 0x00, 0x00):
handle_rbit(s, sf, rn, rd);
break;
- case 1: /* REV16 */
+ case MAP(0, 0x00, 0x01): /* REV16 */
+ case MAP(1, 0x00, 0x01):
handle_rev16(s, sf, rn, rd);
break;
- case 2: /* REV32 */
+ case MAP(0, 0x00, 0x02): /* REV/REV32 */
+ case MAP(1, 0x00, 0x02):
handle_rev32(s, sf, rn, rd);
break;
- case 3: /* REV64 */
+ case MAP(1, 0x00, 0x03): /* REV64 */
handle_rev64(s, sf, rn, rd);
break;
- case 4: /* CLZ */
+ case MAP(0, 0x00, 0x04): /* CLZ */
+ case MAP(1, 0x00, 0x04):
handle_clz(s, sf, rn, rd);
break;
- case 5: /* CLS */
+ case MAP(0, 0x00, 0x05): /* CLS */
+ case MAP(1, 0x00, 0x05):
handle_cls(s, sf, rn, rd);
break;
+ case MAP(1, 0x01, 0x00): /* PACIA */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x01): /* PACIB */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x02): /* PACDA */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x03): /* PACDB */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x04): /* AUTIA */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x05): /* AUTIB */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x06): /* AUTDA */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x07): /* AUTDB */
+ if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
+ } else if (!dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ break;
+ case MAP(1, 0x01, 0x08): /* PACIZA */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x09): /* PACIZB */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0a): /* PACDZA */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0b): /* PACDZB */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0c): /* AUTIZA */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autia(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0d): /* AUTIZB */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autib(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0e): /* AUTDZA */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autda(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x0f): /* AUTDZB */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, new_tmp_a64_zero(s));
+ }
+ break;
+ case MAP(1, 0x01, 0x10): /* XPACI */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_xpaci(tcg_rd, cpu_env, tcg_rd);
+ }
+ break;
+ case MAP(1, 0x01, 0x11): /* XPACD */
+ if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
+ goto do_unallocated;
+ } else if (s->pauth_active) {
+ tcg_rd = cpu_reg(s, rd);
+ gen_helper_xpacd(tcg_rd, cpu_env, tcg_rd);
+ }
+ break;
+ default:
+ do_unallocated:
+ unallocated_encoding(s);
+ break;
}
+
+#undef MAP
}
static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
@@ -4644,6 +5037,13 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
case 11: /* RORV */
handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
break;
+ case 12: /* PACGA */
+ if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) {
+ goto do_unallocated;
+ }
+ gen_helper_pacga(cpu_reg(s, rd), cpu_env,
+ cpu_reg(s, rn), cpu_reg_sp(s, rm));
+ break;
case 16:
case 17:
case 18:
@@ -4659,6 +5059,7 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
break;
}
default:
+ do_unallocated:
unallocated_encoding(s);
break;
}
@@ -13368,7 +13769,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cpu->env_ptr;
ARMCPU *arm_cpu = arm_env_get_cpu(env);
- int bound;
+ uint32_t tb_flags = dc->base.tb->flags;
+ int bound, core_mmu_idx;
dc->isar = &arm_cpu->isar;
dc->pc = dc->base.pc_first;
@@ -13382,19 +13784,20 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
!arm_el_is_aa64(env, 3);
dc->thumb = 0;
dc->sctlr_b = 0;
- dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
+ dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
dc->condexec_mask = 0;
dc->condexec_cond = 0;
- dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
- dc->tbi0 = ARM_TBFLAG_TBI0(dc->base.tb->flags);
- dc->tbi1 = ARM_TBFLAG_TBI1(dc->base.tb->flags);
+ core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
+ dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
+ dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII);
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
- dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
- dc->sve_excp_el = ARM_TBFLAG_SVEEXC_EL(dc->base.tb->flags);
- dc->sve_len = (ARM_TBFLAG_ZCR_LEN(dc->base.tb->flags) + 1) * 16;
+ dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
+ dc->sve_excp_el = FIELD_EX32(tb_flags, TBFLAG_A64, SVEEXC_EL);
+ dc->sve_len = (FIELD_EX32(tb_flags, TBFLAG_A64, ZCR_LEN) + 1) * 16;
+ dc->pauth_active = FIELD_EX32(tb_flags, TBFLAG_A64, PAUTH_ACTIVE);
dc->vec_len = 0;
dc->vec_stride = 0;
dc->cp_regs = arm_cpu->cp_regs;
@@ -13415,8 +13818,8 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
* emit code to generate a software step exception
* end the TB
*/
- dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
- dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
+ dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE);
+ dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS);
dc->is_ldex = false;
dc->ss_same_el = (arm_debug_target_el(env) == dc->current_el);
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 7c4675ffd8..66cf28c8cb 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -9733,6 +9733,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
rd = (insn >> 12) & 0xf;
if (insn & (1 << 23)) {
/* load/store exclusive */
+ bool is_ld = extract32(insn, 20, 1);
+ bool is_lasr = !extract32(insn, 8, 1);
int op2 = (insn >> 8) & 3;
op1 = (insn >> 21) & 0x3;
@@ -9760,11 +9762,12 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
addr = tcg_temp_local_new_i32();
load_reg_var(s, addr, rn);
- /* Since the emulation does not have barriers,
- the acquire/release semantics need no special
- handling */
+ if (is_lasr && !is_ld) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+
if (op2 == 0) {
- if (insn & (1 << 20)) {
+ if (is_ld) {
tmp = tcg_temp_new_i32();
switch (op1) {
case 0: /* lda */
@@ -9810,7 +9813,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
tcg_temp_free_i32(tmp);
}
- } else if (insn & (1 << 20)) {
+ } else if (is_ld) {
switch (op1) {
case 0: /* ldrex */
gen_load_exclusive(s, rd, 15, addr, 2);
@@ -9847,6 +9850,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
}
tcg_temp_free_i32(addr);
+
+ if (is_lasr && is_ld) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
} else if ((insn & 0x00300f00) == 0) {
/* 0bcccc_0001_0x00_xxxx_xxxx_0000_1001_xxxx
* - SWP, SWPB
@@ -10862,6 +10869,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
tcg_gen_addi_i32(tmp, tmp, s->pc);
store_reg(s, 15, tmp);
} else {
+ bool is_lasr = false;
+ bool is_ld = extract32(insn, 20, 1);
int op2 = (insn >> 6) & 0x3;
op = (insn >> 4) & 0x3;
switch (op2) {
@@ -10883,12 +10892,18 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
case 3:
/* Load-acquire/store-release exclusive */
ARCH(8);
+ is_lasr = true;
break;
}
+
+ if (is_lasr && !is_ld) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ }
+
addr = tcg_temp_local_new_i32();
load_reg_var(s, addr, rn);
if (!(op2 & 1)) {
- if (insn & (1 << 20)) {
+ if (is_ld) {
tmp = tcg_temp_new_i32();
switch (op) {
case 0: /* ldab */
@@ -10927,12 +10942,16 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
tcg_temp_free_i32(tmp);
}
- } else if (insn & (1 << 20)) {
+ } else if (is_ld) {
gen_load_exclusive(s, rs, rd, addr, op);
} else {
gen_store_exclusive(s, rm, rs, rd, addr, op);
}
tcg_temp_free_i32(addr);
+
+ if (is_lasr && is_ld) {
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
}
} else {
/* Load/store multiple, RFE, SRS. */
@@ -13021,6 +13040,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUARMState *env = cs->env_ptr;
ARMCPU *cpu = arm_env_get_cpu(env);
+ uint32_t tb_flags = dc->base.tb->flags;
+ uint32_t condexec, core_mmu_idx;
dc->isar = &cpu->isar;
dc->pc = dc->base.pc_first;
@@ -13032,26 +13053,28 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
*/
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
!arm_el_is_aa64(env, 3);
- dc->thumb = ARM_TBFLAG_THUMB(dc->base.tb->flags);
- dc->sctlr_b = ARM_TBFLAG_SCTLR_B(dc->base.tb->flags);
- dc->be_data = ARM_TBFLAG_BE_DATA(dc->base.tb->flags) ? MO_BE : MO_LE;
- dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) & 0xf) << 1;
- dc->condexec_cond = ARM_TBFLAG_CONDEXEC(dc->base.tb->flags) >> 4;
- dc->mmu_idx = core_to_arm_mmu_idx(env, ARM_TBFLAG_MMUIDX(dc->base.tb->flags));
+ dc->thumb = FIELD_EX32(tb_flags, TBFLAG_A32, THUMB);
+ dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR_B);
+ dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
+ condexec = FIELD_EX32(tb_flags, TBFLAG_A32, CONDEXEC);
+ dc->condexec_mask = (condexec & 0xf) << 1;
+ dc->condexec_cond = condexec >> 4;
+ core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX);
+ dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
- dc->ns = ARM_TBFLAG_NS(dc->base.tb->flags);
- dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(dc->base.tb->flags);
- dc->vfp_enabled = ARM_TBFLAG_VFPEN(dc->base.tb->flags);
- dc->vec_len = ARM_TBFLAG_VECLEN(dc->base.tb->flags);
- dc->vec_stride = ARM_TBFLAG_VECSTRIDE(dc->base.tb->flags);
- dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(dc->base.tb->flags);
- dc->v7m_handler_mode = ARM_TBFLAG_HANDLER(dc->base.tb->flags);
+ dc->ns = FIELD_EX32(tb_flags, TBFLAG_A32, NS);
+ dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL);
+ dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN);
+ dc->vec_len = FIELD_EX32(tb_flags, TBFLAG_A32, VECLEN);
+ dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE);
+ dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR);
+ dc->v7m_handler_mode = FIELD_EX32(tb_flags, TBFLAG_A32, HANDLER);
dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) &&
regime_is_secure(env, dc->mmu_idx);
- dc->v8m_stackcheck = ARM_TBFLAG_STACKCHECK(dc->base.tb->flags);
+ dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;
@@ -13070,8 +13093,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
* emit code to generate a software step exception
* end the TB
*/
- dc->ss_active = ARM_TBFLAG_SS_ACTIVE(dc->base.tb->flags);
- dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(dc->base.tb->flags);
+ dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE);
+ dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS);
dc->is_ldex = false;
dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */
@@ -13516,11 +13539,11 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
DisasContext dc;
const TranslatorOps *ops = &arm_translator_ops;
- if (ARM_TBFLAG_THUMB(tb->flags)) {
+ if (FIELD_EX32(tb->flags, TBFLAG_A32, THUMB)) {
ops = &thumb_translator_ops;
}
#ifdef TARGET_AARCH64
- if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
+ if (FIELD_EX32(tb->flags, TBFLAG_ANY, AARCH64_STATE)) {
ops = &aarch64_translator_ops;
}
#endif
diff --git a/target/arm/translate.h b/target/arm/translate.h
index 1550aa8bc7..bb37d35741 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -26,8 +26,7 @@ typedef struct DisasContext {
int user;
#endif
ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */
- bool tbi0; /* TBI0 for EL0/1 or TBI for EL2/3 */
- bool tbi1; /* TBI1 for EL0/1, not used for EL2/3 */
+ uint8_t tbii; /* TBI1|TBI0 for EL0/1 or TBI for EL2/3 */
bool ns; /* Use non-secure CPREG bank on access */
int fp_excp_el; /* FP exception EL or 0 if enabled */
int sve_excp_el; /* SVE exception EL or 0 if enabled */
@@ -68,6 +67,8 @@ typedef struct DisasContext {
bool is_ldex;
/* True if a single-step exception will be taken to the current EL */
bool ss_same_el;
+ /* True if v8.3-PAuth is active. */
+ bool pauth_active;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar;
/* TCG op of the current insn_start. */
diff --git a/target/cris/helper.c b/target/cris/helper.c
index d2ec349191..b2dbb2075c 100644
--- a/target/cris/helper.c
+++ b/target/cris/helper.c
@@ -240,7 +240,7 @@ void cris_cpu_do_interrupt(CPUState *cs)
/* Exception starts with dslot cleared. */
env->dslot = 0;
}
-
+
if (env->pregs[PR_CCS] & U_FLAG) {
/* Swap stack pointers. */
env->pregs[PR_USP] = env->regs[R_SP];
diff --git a/target/cris/mmu.h b/target/cris/mmu.h
index 8e249e812b..0217f476de 100644
--- a/target/cris/mmu.h
+++ b/target/cris/mmu.h
@@ -5,13 +5,13 @@
struct cris_mmu_result
{
- uint32_t phy;
- int prot;
- int bf_vec;
+ uint32_t phy;
+ int prot;
+ int bf_vec;
};
void cris_mmu_init(CPUCRISState *env);
void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid);
int cris_mmu_translate(struct cris_mmu_result *res,
- CPUCRISState *env, uint32_t vaddr,
- int rw, int mmu_idx, int debug);
+ CPUCRISState *env, uint32_t vaddr,
+ int rw, int mmu_idx, int debug);
diff --git a/target/cris/translate_v10.inc.c b/target/cris/translate_v10.inc.c
index fce78825cc..a87b8bb281 100644
--- a/target/cris/translate_v10.inc.c
+++ b/target/cris/translate_v10.inc.c
@@ -384,7 +384,7 @@ static unsigned int dec10_setclrf(DisasContext *dc)
}
static inline void dec10_reg_prep_sext(DisasContext *dc, int size, int sext,
- TCGv dd, TCGv ds, TCGv sd, TCGv ss)
+ TCGv dd, TCGv ds, TCGv sd, TCGv ss)
{
if (sext) {
t_gen_sext(dd, sd, size);
diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs
index 32bf966300..cb9c265525 100644
--- a/target/i386/Makefile.objs
+++ b/target/i386/Makefile.objs
@@ -12,10 +12,10 @@ obj-$(call lnot,$(CONFIG_HYPERV)) += hyperv-stub.o
ifeq ($(CONFIG_WIN32),y)
obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o
endif
-ifeq ($(CONFIG_DARWIN),y)
-obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-darwin.o
-obj-$(CONFIG_HVF) += hvf/
+ifeq ($(CONFIG_POSIX),y)
+obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-posix.o
endif
+obj-$(CONFIG_HVF) += hvf/
obj-$(CONFIG_WHPX) += whpx-all.o
endif
obj-$(CONFIG_SEV) += sev.o
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index f81d35e1f9..2f5412592d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -929,6 +929,13 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
*/
.no_autoenable_flags = ~0U,
},
+ /*
+ * .feat_names are commented out for Hyper-V enlightenments because we
+ * don't want to have two different ways for enabling them on QEMU command
+ * line. Some features (e.g. "hyperv_time", "hyperv_vapic", ...) require
+ * enabling several feature bits simultaneously, exposing these bits
+ * individually may just confuse guests.
+ */
[FEAT_HYPERV_EAX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
@@ -980,6 +987,36 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
.cpuid = { .eax = 0x40000003, .reg = R_EDX, },
},
+ [FEAT_HV_RECOMM_EAX] = {
+ .type = CPUID_FEATURE_WORD,
+ .feat_names = {
+ NULL /* hv_recommend_pv_as_switch */,
+ NULL /* hv_recommend_pv_tlbflush_local */,
+ NULL /* hv_recommend_pv_tlbflush_remote */,
+ NULL /* hv_recommend_msr_apic_access */,
+ NULL /* hv_recommend_msr_reset */,
+ NULL /* hv_recommend_relaxed_timing */,
+ NULL /* hv_recommend_dma_remapping */,
+ NULL /* hv_recommend_int_remapping */,
+ NULL /* hv_recommend_x2apic_msrs */,
+ NULL /* hv_recommend_autoeoi_deprecation */,
+ NULL /* hv_recommend_pv_ipi */,
+ NULL /* hv_recommend_ex_hypercalls */,
+ NULL /* hv_hypervisor_is_nested */,
+ NULL /* hv_recommend_int_mbec */,
+ NULL /* hv_recommend_evmcs */,
+ NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .cpuid = { .eax = 0x40000004, .reg = R_EAX, },
+ },
+ [FEAT_HV_NESTED_EAX] = {
+ .type = CPUID_FEATURE_WORD,
+ .cpuid = { .eax = 0x4000000A, .reg = R_EAX, },
+ },
[FEAT_SVM] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
@@ -1023,8 +1060,8 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
"avx512bitalg", NULL, "avx512-vpopcntdq", NULL,
"la57", NULL, NULL, NULL,
NULL, NULL, "rdpid", NULL,
- NULL, "cldemote", NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, "cldemote", NULL, "movdiri",
+ "movdir64b", NULL, NULL, NULL,
},
.cpuid = {
.eax = 7,
@@ -1042,7 +1079,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
NULL, NULL, NULL, NULL,
NULL, NULL, "pconfig", NULL,
NULL, NULL, NULL, NULL,
- NULL, NULL, "spec-ctrl", NULL,
+ NULL, NULL, "spec-ctrl", "stibp",
NULL, "arch-capabilities", NULL, "ssbd",
},
.cpuid = {
@@ -2296,7 +2333,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
+ CPUID_7_0_EBX_SMAP,
/* Missing: XSAVES (not supported by some Linux versions,
* including v4.1 to v4.12).
* KVM doesn't yet expose any XSAVES state save component,
@@ -2343,7 +2380,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
+ CPUID_7_0_EBX_SMAP,
/* Missing: XSAVES (not supported by some Linux versions,
* including v4.1 to v4.12).
* KVM doesn't yet expose any XSAVES state save component,
@@ -2388,7 +2425,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLWB |
CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT,
@@ -2440,7 +2477,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLWB |
CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL,
@@ -2490,7 +2527,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLWB |
CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT |
@@ -2546,7 +2583,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_INTEL_PT,
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_INTEL_PT,
.features[FEAT_7_0_ECX] =
CPUID_7_0_ECX_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
CPUID_7_0_ECX_OSPKE | CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI |
@@ -2601,7 +2638,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
- CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLWB |
CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT |
@@ -2706,7 +2743,6 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_DE | CPUID_FP87,
.features[FEAT_1_ECX] =
CPUID_EXT_CX16 | CPUID_EXT_SSE3,
- /* Missing: CPUID_EXT2_RDTSCP */
.features[FEAT_8000_0001_EDX] =
CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
@@ -2730,9 +2766,9 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_1_ECX] =
CPUID_EXT_POPCNT | CPUID_EXT_CX16 | CPUID_EXT_MONITOR |
CPUID_EXT_SSE3,
- /* Missing: CPUID_EXT2_RDTSCP */
.features[FEAT_8000_0001_EDX] =
- CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
+ CPUID_EXT2_LM | CPUID_EXT2_NX | CPUID_EXT2_SYSCALL |
+ CPUID_EXT2_RDTSCP,
.features[FEAT_8000_0001_ECX] =
CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A |
CPUID_EXT3_ABM | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
@@ -2757,10 +2793,9 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
CPUID_EXT_SSE3,
- /* Missing: CPUID_EXT2_RDTSCP */
.features[FEAT_8000_0001_EDX] =
CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_NX |
- CPUID_EXT2_SYSCALL,
+ CPUID_EXT2_SYSCALL | CPUID_EXT2_RDTSCP,
.features[FEAT_8000_0001_ECX] =
CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
@@ -2788,10 +2823,9 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_FMA |
CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
- /* Missing: CPUID_EXT2_RDTSCP */
.features[FEAT_8000_0001_EDX] =
CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_NX |
- CPUID_EXT2_SYSCALL,
+ CPUID_EXT2_SYSCALL | CPUID_EXT2_RDTSCP,
.features[FEAT_8000_0001_ECX] =
CPUID_EXT3_TBM | CPUID_EXT3_FMA4 | CPUID_EXT3_XOP |
CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE |
@@ -3568,7 +3602,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
prop->driver = typename;
prop->property = g_strdup(name);
prop->value = g_strdup(val);
- prop->errp = &error_fatal;
qdev_prop_register_global(prop);
}
@@ -4065,7 +4098,7 @@ arch_query_cpu_model_expansion(CpuModelExpansionType type,
x86_cpu_to_dict_full(xc, props);
break;
default:
- error_setg(&err, "Unsupportted expansion type");
+ error_setg(&err, "Unsupported expansion type");
goto out;
}
@@ -5152,6 +5185,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
if (cpu->host_phys_bits) {
/* The user asked for us to use the host physical bits */
cpu->phys_bits = host_phys_bits;
+ if (cpu->host_phys_bits_limit &&
+ cpu->phys_bits > cpu->host_phys_bits_limit) {
+ cpu->phys_bits = cpu->host_phys_bits_limit;
+ }
}
/* Print a warning if the user set it to a value that's not the
@@ -5739,6 +5776,7 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("kvm", X86CPU, expose_kvm, true),
DEFINE_PROP_UINT32("phys-bits", X86CPU, phys_bits, 0),
DEFINE_PROP_BOOL("host-phys-bits", X86CPU, host_phys_bits, false),
+ DEFINE_PROP_UINT8("host-phys-bits-limit", X86CPU, host_phys_bits_limit, 0),
DEFINE_PROP_BOOL("fill-mtrr-mask", X86CPU, fill_mtrr_mask, true),
DEFINE_PROP_UINT32("level", X86CPU, env.cpuid_level, UINT32_MAX),
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, UINT32_MAX),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 9c52d0cbeb..59656a70e6 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -497,6 +497,8 @@ typedef enum FeatureWord {
FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
FEAT_HYPERV_EBX, /* CPUID[4000_0003].EBX */
FEAT_HYPERV_EDX, /* CPUID[4000_0003].EDX */
+ FEAT_HV_RECOMM_EAX, /* CPUID[4000_0004].EAX */
+ FEAT_HV_NESTED_EAX, /* CPUID[4000_000A].EAX */
FEAT_SVM, /* CPUID[8000_000A].EDX */
FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */
FEAT_6_EAX, /* CPUID[6].EAX */
@@ -687,6 +689,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_ECX_LA57 (1U << 16)
#define CPUID_7_0_ECX_RDPID (1U << 22)
#define CPUID_7_0_ECX_CLDEMOTE (1U << 25) /* CLDEMOTE Instruction */
+#define CPUID_7_0_ECX_MOVDIRI (1U << 27) /* MOVDIRI Instruction */
+#define CPUID_7_0_ECX_MOVDIR64B (1U << 28) /* MOVDIR64B Instruction */
#define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
@@ -1457,6 +1461,9 @@ struct X86CPU {
/* if true override the phys_bits value with a value read from the host */
bool host_phys_bits;
+ /* if set, limit maximum value for phys_bits when host_phys_bits is true */
+ uint8_t host_phys_bits_limit;
+
/* Stop SMI delivery for migration compatibility with old machines */
bool kvm_no_smi_migration;
diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c
index d2e512856b..b978a9b821 100644
--- a/target/i386/hax-all.c
+++ b/target/i386/hax-all.c
@@ -154,13 +154,7 @@ int hax_vcpu_create(int id)
return 0;
}
- vcpu = g_malloc(sizeof(struct hax_vcpu_state));
- if (!vcpu) {
- fprintf(stderr, "Failed to alloc vcpu state\n");
- return -ENOMEM;
- }
-
- memset(vcpu, 0, sizeof(struct hax_vcpu_state));
+ vcpu = g_new0(struct hax_vcpu_state, 1);
ret = hax_host_create_vcpu(hax_global.vm->fd, id);
if (ret) {
@@ -211,7 +205,7 @@ int hax_vcpu_destroy(CPUState *cpu)
}
/*
- * 1. The hax_tunnel is also destroied when vcpu destroy
+ * 1. The hax_tunnel is also destroyed when vcpu is destroyed
* 2. close fd will cause hax module vcpu be cleaned
*/
hax_close_fd(vcpu->fd);
@@ -250,11 +244,8 @@ struct hax_vm *hax_vm_create(struct hax_state *hax)
return hax->vm;
}
- vm = g_malloc(sizeof(struct hax_vm));
- if (!vm) {
- return NULL;
- }
- memset(vm, 0, sizeof(struct hax_vm));
+ vm = g_new0(struct hax_vm, 1);
+
ret = hax_host_create_vm(hax, &vm_id);
if (ret) {
fprintf(stderr, "Failed to create vm %x\n", ret);
diff --git a/target/i386/hax-i386.h b/target/i386/hax-i386.h
index 6abc156f88..f13fa4638f 100644
--- a/target/i386/hax-i386.h
+++ b/target/i386/hax-i386.h
@@ -16,7 +16,7 @@
#include "cpu.h"
#include "sysemu/hax.h"
-#ifdef CONFIG_DARWIN
+#ifdef CONFIG_POSIX
typedef int hax_fd;
#endif
@@ -82,8 +82,8 @@ hax_fd hax_mod_open(void);
void hax_memory_init(void);
-#ifdef CONFIG_DARWIN
-#include "target/i386/hax-darwin.h"
+#ifdef CONFIG_POSIX
+#include "target/i386/hax-posix.h"
#endif
#ifdef CONFIG_WIN32
diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c
index 5c37e94caa..6bb5a24917 100644
--- a/target/i386/hax-mem.c
+++ b/target/i386/hax-mem.c
@@ -56,7 +56,7 @@ typedef struct HAXMapping {
* send to the kernel only the removal of the pages from the MMIO hole after
* having computed locally the result of the deletion and additions.
*/
-static QTAILQ_HEAD(HAXMappingListHead, HAXMapping) mappings =
+static QTAILQ_HEAD(, HAXMapping) mappings =
QTAILQ_HEAD_INITIALIZER(mappings);
/**
diff --git a/target/i386/hax-darwin.c b/target/i386/hax-posix.c
index a5426a6dac..a5426a6dac 100644
--- a/target/i386/hax-darwin.c
+++ b/target/i386/hax-posix.c
diff --git a/target/i386/hax-darwin.h b/target/i386/hax-posix.h
index 51af0e8c88..51af0e8c88 100644
--- a/target/i386/hax-darwin.h
+++ b/target/i386/hax-posix.h
diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c
index d125a6ef83..5f513c5563 100644
--- a/target/i386/hvf/x86_decode.c
+++ b/target/i386/hvf/x86_decode.c
@@ -525,8 +525,6 @@ static void decode_sldtgroup(CPUX86State *env, struct x86_decode *decode)
X86_DECODE_CMD_INVL
};
decode->cmd = group[decode->modrm.reg];
- printf("%llx: decode_sldtgroup: %d\n", env->hvf_emul->fetch_rip,
- decode->modrm.reg);
}
static void decode_lidtgroup(CPUX86State *env, struct x86_decode *decode)
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index b2401d13ea..9af4542fb8 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -798,6 +798,48 @@ static int hyperv_handle_properties(CPUState *cs)
}
env->features[FEAT_HYPERV_EAX] |= HV_SYNTIMERS_AVAILABLE;
}
+ if (cpu->hyperv_relaxed_timing) {
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_RELAXED_TIMING_RECOMMENDED;
+ }
+ if (cpu->hyperv_vapic) {
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_APIC_ACCESS_RECOMMENDED;
+ }
+ if (cpu->hyperv_tlbflush) {
+ if (kvm_check_extension(cs->kvm_state,
+ KVM_CAP_HYPERV_TLBFLUSH) <= 0) {
+ fprintf(stderr, "Hyper-V TLB flush support "
+ "(requested by 'hv-tlbflush' cpu flag) "
+ " is not supported by kernel\n");
+ return -ENOSYS;
+ }
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_REMOTE_TLB_FLUSH_RECOMMENDED;
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_EX_PROCESSOR_MASKS_RECOMMENDED;
+ }
+ if (cpu->hyperv_ipi) {
+ if (kvm_check_extension(cs->kvm_state,
+ KVM_CAP_HYPERV_SEND_IPI) <= 0) {
+ fprintf(stderr, "Hyper-V IPI send support "
+ "(requested by 'hv-ipi' cpu flag) "
+ " is not supported by kernel\n");
+ return -ENOSYS;
+ }
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_CLUSTER_IPI_RECOMMENDED;
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_EX_PROCESSOR_MASKS_RECOMMENDED;
+ }
+ if (cpu->hyperv_evmcs) {
+ uint16_t evmcs_version;
+
+ if (kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
+ (uintptr_t)&evmcs_version)) {
+ fprintf(stderr, "Hyper-V Enlightened VMCS "
+ "(requested by 'hv-evmcs' cpu flag) "
+ "is not supported by kernel\n");
+ return -ENOSYS;
+ }
+ env->features[FEAT_HV_RECOMM_EAX] |= HV_ENLIGHTENED_VMCS_RECOMMENDED;
+ env->features[FEAT_HV_NESTED_EAX] = evmcs_version;
+ }
+
return 0;
}
@@ -864,14 +906,21 @@ int kvm_arch_init_vcpu(CPUState *cs)
struct {
struct kvm_cpuid2 cpuid;
struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES];
- } QEMU_PACKED cpuid_data;
+ } cpuid_data;
+ /*
+ * The kernel defines these structs with padding fields so there
+ * should be no extra padding in our cpuid_data struct.
+ */
+ QEMU_BUILD_BUG_ON(sizeof(cpuid_data) !=
+ sizeof(struct kvm_cpuid2) +
+ sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES);
+
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
uint32_t limit, i, j, cpuid_i;
uint32_t unused;
struct kvm_cpuid_entry2 *c;
uint32_t signature[3];
- uint16_t evmcs_version;
int kvm_base = KVM_CPUID_SIGNATURE;
int r;
Error *local_err = NULL;
@@ -946,44 +995,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
c = &cpuid_data.entries[cpuid_i++];
c->function = HV_CPUID_ENLIGHTMENT_INFO;
- if (cpu->hyperv_relaxed_timing) {
- c->eax |= HV_RELAXED_TIMING_RECOMMENDED;
- }
- if (cpu->hyperv_vapic) {
- c->eax |= HV_APIC_ACCESS_RECOMMENDED;
- }
- if (cpu->hyperv_tlbflush) {
- if (kvm_check_extension(cs->kvm_state,
- KVM_CAP_HYPERV_TLBFLUSH) <= 0) {
- fprintf(stderr, "Hyper-V TLB flush support "
- "(requested by 'hv-tlbflush' cpu flag) "
- " is not supported by kernel\n");
- return -ENOSYS;
- }
- c->eax |= HV_REMOTE_TLB_FLUSH_RECOMMENDED;
- c->eax |= HV_EX_PROCESSOR_MASKS_RECOMMENDED;
- }
- if (cpu->hyperv_ipi) {
- if (kvm_check_extension(cs->kvm_state,
- KVM_CAP_HYPERV_SEND_IPI) <= 0) {
- fprintf(stderr, "Hyper-V IPI send support "
- "(requested by 'hv-ipi' cpu flag) "
- " is not supported by kernel\n");
- return -ENOSYS;
- }
- c->eax |= HV_CLUSTER_IPI_RECOMMENDED;
- c->eax |= HV_EX_PROCESSOR_MASKS_RECOMMENDED;
- }
- if (cpu->hyperv_evmcs) {
- if (kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, 0,
- (uintptr_t)&evmcs_version)) {
- fprintf(stderr, "Hyper-V Enlightened VMCS "
- "(requested by 'hv-evmcs' cpu flag) "
- "is not supported by kernel\n");
- return -ENOSYS;
- }
- c->eax |= HV_ENLIGHTENED_VMCS_RECOMMENDED;
- }
+
+ c->eax = env->features[FEAT_HV_RECOMM_EAX];
c->ebx = cpu->hyperv_spinlock_attempts;
c = &cpuid_data.entries[cpuid_i++];
@@ -1007,7 +1020,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
c = &cpuid_data.entries[cpuid_i++];
c->function = HV_CPUID_NESTED_FEATURES;
- c->eax = evmcs_version;
+ c->eax = env->features[FEAT_HV_NESTED_EAX];
}
}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 2395171acf..20b2d325d8 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -11,12 +11,13 @@
*
*/
+#include "qemu/osdep.h"
+
#include <linux/kvm.h>
#include <linux/psp-sev.h>
#include <sys/ioctl.h>
-#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qom/object_interfaces.h"
#include "qemu/base64.h"
diff --git a/target/i386/translate.c b/target/i386/translate.c
index 0dd5fbe45c..49cd298374 100644
--- a/target/i386/translate.c
+++ b/target/i386/translate.c
@@ -3445,7 +3445,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
case 0x172:
case 0x173:
if (b1 >= 2) {
- goto unknown_op;
+ goto unknown_op;
}
val = x86_ldub_code(env, s);
if (is_xmm) {
@@ -6400,7 +6400,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
tcg_gen_movi_i32(s->tmp2_i32, val);
gen_helper_in_func(ot, s->T1, s->tmp2_i32);
gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
@@ -6421,7 +6421,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
tcg_gen_movi_i32(s->tmp2_i32, val);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
@@ -6439,7 +6439,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_in_func(ot, s->T1, s->tmp2_i32);
gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
@@ -6459,7 +6459,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
@@ -7166,7 +7166,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_jmp_im(s, pc_start - s->cs_base);
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
gen_helper_rdtsc(cpu_env);
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
diff --git a/target/i386/whp-dispatch.h b/target/i386/whp-dispatch.h
index d8d3485976..4ae3cc8fa5 100644
--- a/target/i386/whp-dispatch.h
+++ b/target/i386/whp-dispatch.h
@@ -1,5 +1,4 @@
#include "windows.h"
-#include <stdbool.h>
#include <WinHvPlatform.h>
#include <WinHvEmulation.h>
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 9b546a2c18..5596cd5485 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -202,7 +202,11 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
(cpu->cfg.use_barrel ? PVR2_USE_BARREL_MASK : 0) |
(cpu->cfg.use_div ? PVR2_USE_DIV_MASK : 0) |
(cpu->cfg.use_msr_instr ? PVR2_USE_MSR_INSTR : 0) |
- (cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0);
+ (cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0) |
+ (cpu->cfg.dopb_bus_exception ?
+ PVR2_DOPB_BUS_EXC_MASK : 0) |
+ (cpu->cfg.iopb_bus_exception ?
+ PVR2_IOPB_BUS_EXC_MASK : 0);
env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
PVR5_DCACHE_WRITEBACK_MASK : 0;
@@ -265,6 +269,12 @@ static Property mb_properties[] = {
DEFINE_PROP_BOOL("dcache-writeback", MicroBlazeCPU, cfg.dcache_writeback,
false),
DEFINE_PROP_BOOL("endianness", MicroBlazeCPU, cfg.endi, false),
+ /* Enables bus exceptions on failed data accesses (load/stores). */
+ DEFINE_PROP_BOOL("dopb-bus-exception", MicroBlazeCPU,
+ cfg.dopb_bus_exception, false),
+ /* Enables bus exceptions on failed instruction fetches. */
+ DEFINE_PROP_BOOL("iopb-bus-exception", MicroBlazeCPU,
+ cfg.iopb_bus_exception, false),
DEFINE_PROP_STRING("version", MicroBlazeCPU, cfg.version),
DEFINE_PROP_UINT8("pvr", MicroBlazeCPU, cfg.pvr, C_PVR_FULL),
DEFINE_PROP_END_OF_LIST(),
@@ -297,7 +307,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
#ifdef CONFIG_USER_ONLY
cc->handle_mmu_fault = mb_cpu_handle_mmu_fault;
#else
- cc->do_unassigned_access = mb_cpu_unassigned_access;
+ cc->do_transaction_failed = mb_cpu_transaction_failed;
cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
#endif
dc->vmsd = &vmstate_mb_cpu;
diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h
index 3c4e0ba80a..792bbc97c7 100644
--- a/target/microblaze/cpu.h
+++ b/target/microblaze/cpu.h
@@ -308,6 +308,8 @@ struct MicroBlazeCPU {
bool use_mmu;
bool dcache_writeback;
bool endi;
+ bool dopb_bus_exception;
+ bool iopb_bus_exception;
char *version;
uint8_t pvr;
} cfg;
@@ -388,9 +390,10 @@ static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
}
#if !defined(CONFIG_USER_ONLY)
-void mb_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
- bool is_write, bool is_exec, int is_asi,
- unsigned size);
+void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
+ unsigned size, MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
#endif
#endif
diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c
index 7cdbbcccae..e23dcfdc20 100644
--- a/target/microblaze/op_helper.c
+++ b/target/microblaze/op_helper.c
@@ -486,26 +486,28 @@ void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
mmu_write(env, ext, rn, v);
}
-void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
- bool is_write, bool is_exec, int is_asi,
- unsigned size)
+void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
+ unsigned size, MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
{
MicroBlazeCPU *cpu;
CPUMBState *env;
-
- qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
- addr, is_write ? 1 : 0, is_exec ? 1 : 0);
- if (cs == NULL) {
- return;
- }
+ qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
+ " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n",
+ addr, physaddr, size,
+ access_type == MMU_INST_FETCH ? "INST_FETCH" :
+ (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
cpu = MICROBLAZE_CPU(cs);
env = &cpu->env;
+
+ cpu_restore_state(cs, retaddr, true);
if (!(env->sregs[SR_MSR] & MSR_EE)) {
return;
}
env->sregs[SR_EAR] = addr;
- if (is_exec) {
+ if (access_type == MMU_INST_FETCH) {
if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
helper_raise_exception(env, EXCP_HW_EXCP);
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 03c03fd8c6..c4da7dfbfd 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -123,87 +123,6 @@ typedef struct mips_def_t mips_def_t;
#define MIPS_KSCRATCH_NUM 6
#define MIPS_MAAR_MAX 16 /* Must be an even number. */
-typedef struct TCState TCState;
-struct TCState {
- target_ulong gpr[32];
- target_ulong PC;
- target_ulong HI[MIPS_DSP_ACC];
- target_ulong LO[MIPS_DSP_ACC];
- target_ulong ACX[MIPS_DSP_ACC];
- target_ulong DSPControl;
- int32_t CP0_TCStatus;
-#define CP0TCSt_TCU3 31
-#define CP0TCSt_TCU2 30
-#define CP0TCSt_TCU1 29
-#define CP0TCSt_TCU0 28
-#define CP0TCSt_TMX 27
-#define CP0TCSt_RNST 23
-#define CP0TCSt_TDS 21
-#define CP0TCSt_DT 20
-#define CP0TCSt_DA 15
-#define CP0TCSt_A 13
-#define CP0TCSt_TKSU 11
-#define CP0TCSt_IXMT 10
-#define CP0TCSt_TASID 0
- int32_t CP0_TCBind;
-#define CP0TCBd_CurTC 21
-#define CP0TCBd_TBE 17
-#define CP0TCBd_CurVPE 0
- target_ulong CP0_TCHalt;
- target_ulong CP0_TCContext;
- target_ulong CP0_TCSchedule;
- target_ulong CP0_TCScheFBack;
- int32_t CP0_Debug_tcstatus;
- target_ulong CP0_UserLocal;
-
- int32_t msacsr;
-
-#define MSACSR_FS 24
-#define MSACSR_FS_MASK (1 << MSACSR_FS)
-#define MSACSR_NX 18
-#define MSACSR_NX_MASK (1 << MSACSR_NX)
-#define MSACSR_CEF 2
-#define MSACSR_CEF_MASK (0xffff << MSACSR_CEF)
-#define MSACSR_RM 0
-#define MSACSR_RM_MASK (0x3 << MSACSR_RM)
-#define MSACSR_MASK (MSACSR_RM_MASK | MSACSR_CEF_MASK | MSACSR_NX_MASK | \
- MSACSR_FS_MASK)
-
- float_status msa_fp_status;
-
-#define NUMBER_OF_MXU_REGISTERS 16
- target_ulong mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
- target_ulong mxu_cr;
-#define MXU_CR_LC 31
-#define MXU_CR_RC 30
-#define MXU_CR_BIAS 2
-#define MXU_CR_RD_EN 1
-#define MXU_CR_MXU_EN 0
-
-};
-
-typedef struct CPUMIPSState CPUMIPSState;
-struct CPUMIPSState {
- TCState active_tc;
- CPUMIPSFPUContext active_fpu;
-
- uint32_t current_tc;
- uint32_t current_fpu;
-
- uint32_t SEGBITS;
- uint32_t PABITS;
-#if defined(TARGET_MIPS64)
-# define PABITS_BASE 36
-#else
-# define PABITS_BASE 32
-#endif
- target_ulong SEGMask;
- uint64_t PAMask;
-#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
-
- int32_t msair;
-#define MSAIR_ProcID 8
-#define MSAIR_Rev 0
/*
* Summary of CP0 registers
@@ -245,8 +164,8 @@ struct CPUMIPSState {
* 3 BadInstrX
* 4 GuestCtl1 GuestCtl0Ext
* 5 GuestCtl2
- * 6 GuestCtl3
- * 7
+ * 6 SAARI GuestCtl3
+ * 7 SAAR
*
*
* Register 12 Register 13 Register 14 Register 15
@@ -314,6 +233,240 @@ struct CPUMIPSState {
* 7 TagLo TagHi KScratch<n>
*
*/
+#define CP0_REGISTER_00 0
+#define CP0_REGISTER_01 1
+#define CP0_REGISTER_02 2
+#define CP0_REGISTER_03 3
+#define CP0_REGISTER_04 4
+#define CP0_REGISTER_05 5
+#define CP0_REGISTER_06 6
+#define CP0_REGISTER_07 7
+#define CP0_REGISTER_08 8
+#define CP0_REGISTER_09 9
+#define CP0_REGISTER_10 10
+#define CP0_REGISTER_11 11
+#define CP0_REGISTER_12 12
+#define CP0_REGISTER_13 13
+#define CP0_REGISTER_14 14
+#define CP0_REGISTER_15 15
+#define CP0_REGISTER_16 16
+#define CP0_REGISTER_17 17
+#define CP0_REGISTER_18 18
+#define CP0_REGISTER_19 19
+#define CP0_REGISTER_20 20
+#define CP0_REGISTER_21 21
+#define CP0_REGISTER_22 22
+#define CP0_REGISTER_23 23
+#define CP0_REGISTER_24 24
+#define CP0_REGISTER_25 25
+#define CP0_REGISTER_26 26
+#define CP0_REGISTER_27 27
+#define CP0_REGISTER_28 28
+#define CP0_REGISTER_29 29
+#define CP0_REGISTER_30 30
+#define CP0_REGISTER_31 31
+
+
+/* CP0 Register 00 */
+#define CP0_REG00__INDEX 0
+#define CP0_REG00__VPCONTROL 4
+/* CP0 Register 01 */
+/* CP0 Register 02 */
+#define CP0_REG02__ENTRYLO0 0
+/* CP0 Register 03 */
+#define CP0_REG03__ENTRYLO1 0
+#define CP0_REG03__GLOBALNUM 1
+/* CP0 Register 04 */
+#define CP0_REG04__CONTEXT 0
+#define CP0_REG04__USERLOCAL 2
+#define CP0_REG04__DBGCONTEXTID 4
+#define CP0_REG00__MMID 5
+/* CP0 Register 05 */
+#define CP0_REG05__PAGEMASK 0
+#define CP0_REG05__PAGEGRAIN 1
+/* CP0 Register 06 */
+#define CP0_REG06__WIRED 0
+/* CP0 Register 07 */
+#define CP0_REG07__HWRENA 0
+/* CP0 Register 08 */
+#define CP0_REG08__BADVADDR 0
+#define CP0_REG08__BADINSTR 1
+#define CP0_REG08__BADINSTRP 2
+/* CP0 Register 09 */
+#define CP0_REG09__COUNT 0
+#define CP0_REG09__SAARI 6
+#define CP0_REG09__SAAR 7
+/* CP0 Register 10 */
+#define CP0_REG10__ENTRYHI 0
+#define CP0_REG10__GUESTCTL1 4
+#define CP0_REG10__GUESTCTL2 5
+/* CP0 Register 11 */
+#define CP0_REG11__COMPARE 0
+#define CP0_REG11__GUESTCTL0EXT 4
+/* CP0 Register 12 */
+#define CP0_REG12__STATUS 0
+#define CP0_REG12__INTCTL 1
+#define CP0_REG12__SRSCTL 2
+#define CP0_REG12__GUESTCTL0 6
+#define CP0_REG12__GTOFFSET 7
+/* CP0 Register 13 */
+#define CP0_REG13__CAUSE 0
+/* CP0 Register 14 */
+#define CP0_REG14__EPC 0
+/* CP0 Register 15 */
+#define CP0_REG15__PRID 0
+#define CP0_REG15__EBASE 1
+#define CP0_REG15__CDMMBASE 2
+#define CP0_REG15__CMGCRBASE 3
+/* CP0 Register 16 */
+#define CP0_REG16__CONFIG 0
+#define CP0_REG16__CONFIG1 1
+#define CP0_REG16__CONFIG2 2
+#define CP0_REG16__CONFIG3 3
+#define CP0_REG16__CONFIG4 4
+#define CP0_REG16__CONFIG5 5
+#define CP0_REG00__CONFIG7 7
+/* CP0 Register 17 */
+#define CP0_REG17__LLADDR 0
+#define CP0_REG17__MAAR 1
+#define CP0_REG17__MAARI 2
+/* CP0 Register 18 */
+#define CP0_REG18__WATCHLO0 0
+#define CP0_REG18__WATCHLO1 1
+#define CP0_REG18__WATCHLO2 2
+#define CP0_REG18__WATCHLO3 3
+/* CP0 Register 19 */
+#define CP0_REG19__WATCHHI0 0
+#define CP0_REG19__WATCHHI1 1
+#define CP0_REG19__WATCHHI2 2
+#define CP0_REG19__WATCHHI3 3
+/* CP0 Register 20 */
+#define CP0_REG20__XCONTEXT 0
+/* CP0 Register 21 */
+/* CP0 Register 22 */
+/* CP0 Register 23 */
+#define CP0_REG23__DEBUG 0
+/* CP0 Register 24 */
+#define CP0_REG24__DEPC 0
+/* CP0 Register 25 */
+#define CP0_REG25__PERFCTL0 0
+#define CP0_REG25__PERFCNT0 1
+#define CP0_REG25__PERFCTL1 2
+#define CP0_REG25__PERFCNT1 3
+#define CP0_REG25__PERFCTL2 4
+#define CP0_REG25__PERFCNT2 5
+#define CP0_REG25__PERFCTL3 6
+#define CP0_REG25__PERFCNT3 7
+/* CP0 Register 26 */
+#define CP0_REG00__ERRCTL 0
+/* CP0 Register 27 */
+#define CP0_REG27__CACHERR 0
+/* CP0 Register 28 */
+#define CP0_REG28__ITAGLO 0
+#define CP0_REG28__IDATALO 1
+#define CP0_REG28__DTAGLO 2
+#define CP0_REG28__DDATALO 3
+/* CP0 Register 29 */
+#define CP0_REG29__IDATAHI 1
+#define CP0_REG29__DDATAHI 3
+/* CP0 Register 30 */
+#define CP0_REG30__ERROREPC 0
+/* CP0 Register 31 */
+#define CP0_REG31__DESAVE 0
+#define CP0_REG31__KSCRATCH1 2
+#define CP0_REG31__KSCRATCH2 3
+#define CP0_REG31__KSCRATCH3 4
+#define CP0_REG31__KSCRATCH4 5
+#define CP0_REG31__KSCRATCH5 6
+#define CP0_REG31__KSCRATCH6 7
+
+
+typedef struct TCState TCState;
+struct TCState {
+ target_ulong gpr[32];
+ target_ulong PC;
+ target_ulong HI[MIPS_DSP_ACC];
+ target_ulong LO[MIPS_DSP_ACC];
+ target_ulong ACX[MIPS_DSP_ACC];
+ target_ulong DSPControl;
+ int32_t CP0_TCStatus;
+#define CP0TCSt_TCU3 31
+#define CP0TCSt_TCU2 30
+#define CP0TCSt_TCU1 29
+#define CP0TCSt_TCU0 28
+#define CP0TCSt_TMX 27
+#define CP0TCSt_RNST 23
+#define CP0TCSt_TDS 21
+#define CP0TCSt_DT 20
+#define CP0TCSt_DA 15
+#define CP0TCSt_A 13
+#define CP0TCSt_TKSU 11
+#define CP0TCSt_IXMT 10
+#define CP0TCSt_TASID 0
+ int32_t CP0_TCBind;
+#define CP0TCBd_CurTC 21
+#define CP0TCBd_TBE 17
+#define CP0TCBd_CurVPE 0
+ target_ulong CP0_TCHalt;
+ target_ulong CP0_TCContext;
+ target_ulong CP0_TCSchedule;
+ target_ulong CP0_TCScheFBack;
+ int32_t CP0_Debug_tcstatus;
+ target_ulong CP0_UserLocal;
+
+ int32_t msacsr;
+
+#define MSACSR_FS 24
+#define MSACSR_FS_MASK (1 << MSACSR_FS)
+#define MSACSR_NX 18
+#define MSACSR_NX_MASK (1 << MSACSR_NX)
+#define MSACSR_CEF 2
+#define MSACSR_CEF_MASK (0xffff << MSACSR_CEF)
+#define MSACSR_RM 0
+#define MSACSR_RM_MASK (0x3 << MSACSR_RM)
+#define MSACSR_MASK (MSACSR_RM_MASK | MSACSR_CEF_MASK | MSACSR_NX_MASK | \
+ MSACSR_FS_MASK)
+
+ float_status msa_fp_status;
+
+ /* Upper 64-bit MMRs (multimedia registers); the lower 64-bit are GPRs */
+ uint64_t mmr[32];
+
+#define NUMBER_OF_MXU_REGISTERS 16
+ target_ulong mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
+ target_ulong mxu_cr;
+#define MXU_CR_LC 31
+#define MXU_CR_RC 30
+#define MXU_CR_BIAS 2
+#define MXU_CR_RD_EN 1
+#define MXU_CR_MXU_EN 0
+
+};
+
+struct MIPSITUState;
+typedef struct CPUMIPSState CPUMIPSState;
+struct CPUMIPSState {
+ TCState active_tc;
+ CPUMIPSFPUContext active_fpu;
+
+ uint32_t current_tc;
+ uint32_t current_fpu;
+
+ uint32_t SEGBITS;
+ uint32_t PABITS;
+#if defined(TARGET_MIPS64)
+# define PABITS_BASE 36
+#else
+# define PABITS_BASE 32
+#endif
+ target_ulong SEGMask;
+ uint64_t PAMask;
+#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1)
+
+ int32_t msair;
+#define MSAIR_ProcID 8
+#define MSAIR_Rev 0
+
/*
* CP0 Register 0
*/
@@ -386,6 +539,7 @@ struct CPUMIPSState {
*/
target_ulong CP0_Context;
target_ulong CP0_KScratch[MIPS_KSCRATCH_NUM];
+ int32_t CP0_MemoryMapID;
/*
* CP0 Register 5
*/
@@ -511,6 +665,12 @@ struct CPUMIPSState {
* CP0 Register 9
*/
int32_t CP0_Count;
+ uint32_t CP0_SAARI;
+#define CP0SAARI_TARGET 0 /* 5..0 */
+ uint64_t CP0_SAAR[2];
+#define CP0SAAR_BASE 12 /* 43..12 */
+#define CP0SAAR_SIZE 1 /* 5..1 */
+#define CP0SAAR_EN 0
/*
* CP0 Register 10
*/
@@ -860,6 +1020,7 @@ struct CPUMIPSState {
uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
uint64_t insn_flags; /* Supported instruction set */
+ int saarp;
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@@ -875,6 +1036,7 @@ struct CPUMIPSState {
const mips_def_t *cpu_model;
void *irq[8];
QEMUTimer *timer; /* Internal timer */
+ struct MIPSITUState *itu;
MemoryRegion *itc_tag; /* ITC Configuration Tags */
target_ulong exception_base; /* ExceptionBase input to the core */
};
@@ -1017,6 +1179,9 @@ void cpu_set_exception_base(int vp_index, target_ulong address);
/* mips_int.c */
void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level);
+/* mips_itu.c */
+void itc_reconfigure(struct MIPSITUState *tag);
+
/* helper.c */
target_ulong exception_resume_pc (CPUMIPSState *env);
diff --git a/target/mips/helper.h b/target/mips/helper.h
index c23e4e5d97..8872c4647b 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -65,6 +65,8 @@ DEF_HELPER_1(mftc0_tcschedule, tl, env)
DEF_HELPER_1(mfc0_tcschefback, tl, env)
DEF_HELPER_1(mftc0_tcschefback, tl, env)
DEF_HELPER_1(mfc0_count, tl, env)
+DEF_HELPER_1(mfc0_saar, tl, env)
+DEF_HELPER_1(mfhc0_saar, tl, env)
DEF_HELPER_1(mftc0_entryhi, tl, env)
DEF_HELPER_1(mftc0_status, tl, env)
DEF_HELPER_1(mftc0_cause, tl, env)
@@ -87,6 +89,7 @@ DEF_HELPER_1(dmfc0_tcschefback, tl, env)
DEF_HELPER_1(dmfc0_lladdr, tl, env)
DEF_HELPER_1(dmfc0_maar, tl, env)
DEF_HELPER_2(dmfc0_watchlo, tl, env, i32)
+DEF_HELPER_1(dmfc0_saar, tl, env)
#endif /* TARGET_MIPS64 */
DEF_HELPER_2(mtc0_index, void, env, tl)
@@ -131,6 +134,9 @@ DEF_HELPER_2(mtc0_srsconf4, void, env, tl)
DEF_HELPER_2(mtc0_hwrena, void, env, tl)
DEF_HELPER_2(mtc0_pwctl, void, env, tl)
DEF_HELPER_2(mtc0_count, void, env, tl)
+DEF_HELPER_2(mtc0_saari, void, env, tl)
+DEF_HELPER_2(mtc0_saar, void, env, tl)
+DEF_HELPER_2(mthc0_saar, void, env, tl)
DEF_HELPER_2(mtc0_entryhi, void, env, tl)
DEF_HELPER_2(mttc0_entryhi, void, env, tl)
DEF_HELPER_2(mtc0_compare, void, env, tl)
diff --git a/target/mips/internal.h b/target/mips/internal.h
index 8b1b2456af..8f6fc919d5 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -61,6 +61,7 @@ struct mips_def_t {
target_ulong CP0_EBaseWG_rw_bitmask;
uint64_t insn_flags;
enum mips_mmu_types mmu_type;
+ int32_t SAARP;
};
extern const struct mips_def_t mips_defs[];
diff --git a/target/mips/machine.c b/target/mips/machine.c
index 704e9c01bf..1341ab1df9 100644
--- a/target/mips/machine.c
+++ b/target/mips/machine.c
@@ -214,8 +214,8 @@ const VMStateDescription vmstate_tlb = {
const VMStateDescription vmstate_mips_cpu = {
.name = "cpu",
- .version_id = 15,
- .minimum_version_id = 15,
+ .version_id = 17,
+ .minimum_version_id = 17,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
/* Active TC */
@@ -253,6 +253,7 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU),
VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU),
VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
+ VMSTATE_INT32(env.CP0_MemoryMapID, MIPSCPU),
VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU),
VMSTATE_UINTTL(env.CP0_SegCtl0, MIPSCPU),
@@ -274,6 +275,8 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_UINT32(env.CP0_BadInstrP, MIPSCPU),
VMSTATE_UINT32(env.CP0_BadInstrX, MIPSCPU),
VMSTATE_INT32(env.CP0_Count, MIPSCPU),
+ VMSTATE_UINT32(env.CP0_SAARI, MIPSCPU),
+ VMSTATE_UINT64_ARRAY(env.CP0_SAAR, MIPSCPU, 2),
VMSTATE_UINTTL(env.CP0_EntryHi, MIPSCPU),
VMSTATE_INT32(env.CP0_Compare, MIPSCPU),
VMSTATE_INT32(env.CP0_Status, MIPSCPU),
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index d1f1d1aa35..aebad24ed6 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -938,6 +938,22 @@ target_ulong helper_mfc0_count(CPUMIPSState *env)
return count;
}
+target_ulong helper_mfc0_saar(CPUMIPSState *env)
+{
+ if ((env->CP0_SAARI & 0x3f) < 2) {
+ return (int32_t) env->CP0_SAAR[env->CP0_SAARI & 0x3f];
+ }
+ return 0;
+}
+
+target_ulong helper_mfhc0_saar(CPUMIPSState *env)
+{
+ if ((env->CP0_SAARI & 0x3f) < 2) {
+ return env->CP0_SAAR[env->CP0_SAARI & 0x3f] >> 32;
+ }
+ return 0;
+}
+
target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
@@ -1059,6 +1075,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
{
return env->CP0_WatchLo[sel];
}
+
+target_ulong helper_dmfc0_saar(CPUMIPSState *env)
+{
+ if ((env->CP0_SAARI & 0x3f) < 2) {
+ return env->CP0_SAAR[env->CP0_SAARI & 0x3f];
+ }
+ return 0;
+}
#endif /* TARGET_MIPS64 */
void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
@@ -1598,6 +1622,46 @@ void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
qemu_mutex_unlock_iothread();
}
+void helper_mtc0_saari(CPUMIPSState *env, target_ulong arg1)
+{
+ uint32_t target = arg1 & 0x3f;
+ if (target <= 1) {
+ env->CP0_SAARI = target;
+ }
+}
+
+void helper_mtc0_saar(CPUMIPSState *env, target_ulong arg1)
+{
+ uint32_t target = env->CP0_SAARI & 0x3f;
+ if (target < 2) {
+ env->CP0_SAAR[target] = arg1 & 0x00000ffffffff03fULL;
+ switch (target) {
+ case 0:
+ if (env->itu) {
+ itc_reconfigure(env->itu);
+ }
+ break;
+ }
+ }
+}
+
+void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1)
+{
+ uint32_t target = env->CP0_SAARI & 0x3f;
+ if (target < 2) {
+ env->CP0_SAAR[target] =
+ (((uint64_t) arg1 << 32) & 0x00000fff00000000ULL) |
+ (env->CP0_SAAR[target] & 0x00000000ffffffffULL);
+ switch (target) {
+ case 0:
+ if (env->itu) {
+ itc_reconfigure(env->itu);
+ }
+ break;
+ }
+ }
+}
+
void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
{
target_ulong old, val, mask;
diff --git a/target/mips/translate.c b/target/mips/translate.c
index e9c23a594b..ab307c410c 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -1399,10 +1399,12 @@ enum {
/*
- * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET
- * ============================================
*
- * MXU (full name: MIPS eXtension/enhanced Unit) is an SIMD extension of MIPS32
+ * AN OVERVIEW OF MXU EXTENSION INSTRUCTION SET
+ * ============================================
+ *
+ *
+ * MXU (full name: MIPS eXtension/enhanced Unit) is a SIMD extension of MIPS32
* instructions set. It is designed to fit the needs of signal, graphical and
* video processing applications. MXU instruction set is used in Xburst family
* of microprocessors by Ingenic.
@@ -1410,39 +1412,31 @@ enum {
* MXU unit contains 17 registers called X0-X16. X0 is always zero, and X16 is
* the control register.
*
- * The notation used in MXU assembler mnemonics
- * --------------------------------------------
*
- * Registers:
+ * The notation used in MXU assembler mnemonics
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Register operands:
*
* XRa, XRb, XRc, XRd - MXU registers
* Rb, Rc, Rd, Rs, Rt - general purpose MIPS registers
*
- * Subfields:
+ * Non-register operands:
*
- * aptn1 - 1-bit accumulate add/subtract pattern
- * aptn2 - 2-bit accumulate add/subtract pattern
- * eptn2 - 2-bit execute add/subtract pattern
- * optn2 - 2-bit operand pattern
- * optn3 - 3-bit operand pattern
- * sft4 - 4-bit shift amount
- * strd2 - 2-bit stride amount
+ * aptn1 - 1-bit accumulate add/subtract pattern
+ * aptn2 - 2-bit accumulate add/subtract pattern
+ * eptn2 - 2-bit execute add/subtract pattern
+ * optn2 - 2-bit operand pattern
+ * optn3 - 3-bit operand pattern
+ * sft4 - 4-bit shift amount
+ * strd2 - 2-bit stride amount
*
* Prefixes:
*
- * <Operation parallel level><Operand size>
- * S 32
- * D 16
- * Q 8
- *
- * Suffixes:
- *
- * E - Expand results
- * F - Fixed point multiplication
- * L - Low part result
- * R - Doing rounding
- * V - Variable instead of immediate
- * W - Combine above L and V
+ * Level of parallelism: Operand size:
+ * S - single operation at a time 32 - word
+ * D - two operations in parallel 16 - half word
+ * Q - four operations in parallel 8 - byte
*
* Operations:
*
@@ -1486,6 +1480,19 @@ enum {
* SCOP - Calculate x’s scope (-1, means x<0; 0, means x==0; 1, means x>0)
* XOR - Logical bitwise 'exclusive or' operation
*
+ * Suffixes:
+ *
+ * E - Expand results
+ * F - Fixed point multiplication
+ * L - Low part result
+ * R - Doing rounding
+ * V - Variable instead of immediate
+ * W - Combine above L and V
+ *
+ *
+ * The list of MXU instructions grouped by functionality
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
* Load/Store instructions Multiplication instructions
* ----------------------- ---------------------------
*
@@ -1563,6 +1570,13 @@ enum {
* Q16SAT XRa, XRb, XRc S32I2M XRa, Rb
*
*
+ * The opcode organization of MXU instructions
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The bits 31..26 of all MXU instructions are equal to 0x1C (also referred
+ * as opcode SPECIAL2 in the base MIPS ISA). The organization and meaning of
+ * other bits up to the instruction level is as follows:
+ *
* bits
* 05..00
*
@@ -1663,12 +1677,21 @@ enum {
* │ 20..18
* ├─ 100111 ─ OPC_MXU__POOL16 ─┬─ 000 ─ OPC_MXU_D32SARW
* │ ├─ 001 ─ OPC_MXU_S32ALN
- * ├─ 101000 ─ OPC_MXU_LXB ├─ 010 ─ OPC_MXU_S32ALNI
- * ├─ 101001 ─ <not assigned> ├─ 011 ─ OPC_MXU_S32NOR
- * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_S32AND
- * ├─ 101011 ─ OPC_MXU_S16STD ├─ 101 ─ OPC_MXU_S32OR
- * ├─ 101100 ─ OPC_MXU_S16LDI ├─ 110 ─ OPC_MXU_S32XOR
- * ├─ 101101 ─ OPC_MXU_S16SDI └─ 111 ─ OPC_MXU_S32LUI
+ * │ ├─ 010 ─ OPC_MXU_S32ALNI
+ * │ ├─ 011 ─ OPC_MXU_S32LUI
+ * │ ├─ 100 ─ OPC_MXU_S32NOR
+ * │ ├─ 101 ─ OPC_MXU_S32AND
+ * │ ├─ 110 ─ OPC_MXU_S32OR
+ * │ └─ 111 ─ OPC_MXU_S32XOR
+ * │
+ * │ 7..5
+ * ├─ 101000 ─ OPC_MXU__POOL17 ─┬─ 000 ─ OPC_MXU_LXB
+ * │ ├─ 001 ─ OPC_MXU_LXH
+ * ├─ 101001 ─ <not assigned> ├─ 011 ─ OPC_MXU_LXW
+ * ├─ 101010 ─ OPC_MXU_S16LDD ├─ 100 ─ OPC_MXU_LXBU
+ * ├─ 101011 ─ OPC_MXU_S16STD └─ 101 ─ OPC_MXU_LXHU
+ * ├─ 101100 ─ OPC_MXU_S16LDI
+ * ├─ 101101 ─ OPC_MXU_S16SDI
* ├─ 101110 ─ OPC_MXU_S32M2I
* ├─ 101111 ─ OPC_MXU_S32I2M
* ├─ 110000 ─ OPC_MXU_D32SLL
@@ -1678,23 +1701,23 @@ enum {
* ├─ 110100 ─ OPC_MXU_Q16SLL ├─ 010 ─ OPC_MXU_D32SARV
* ├─ 110101 ─ OPC_MXU_Q16SLR ├─ 011 ─ OPC_MXU_Q16SLLV
* │ ├─ 100 ─ OPC_MXU_Q16SLRV
- * ├─ 110110 ─ OPC_MXU__POOL17 ─┴─ 101 ─ OPC_MXU_Q16SARV
+ * ├─ 110110 ─ OPC_MXU__POOL18 ─┴─ 101 ─ OPC_MXU_Q16SARV
* │
* ├─ 110111 ─ OPC_MXU_Q16SAR
* │ 23..22
- * ├─ 111000 ─ OPC_MXU__POOL18 ─┬─ 00 ─ OPC_MXU_Q8MUL
+ * ├─ 111000 ─ OPC_MXU__POOL19 ─┬─ 00 ─ OPC_MXU_Q8MUL
* │ └─ 01 ─ OPC_MXU_Q8MULSU
* │
* │ 20..18
- * ├─ 111001 ─ OPC_MXU__POOL19 ─┬─ 000 ─ OPC_MXU_Q8MOVZ
+ * ├─ 111001 ─ OPC_MXU__POOL20 ─┬─ 000 ─ OPC_MXU_Q8MOVZ
* │ ├─ 001 ─ OPC_MXU_Q8MOVN
* │ ├─ 010 ─ OPC_MXU_D16MOVZ
* │ ├─ 011 ─ OPC_MXU_D16MOVN
* │ ├─ 100 ─ OPC_MXU_S32MOVZ
- * │ └─ 101 ─ OPC_MXU_S32MOV
+ * │ └─ 101 ─ OPC_MXU_S32MOVN
* │
* │ 23..22
- * ├─ 111010 ─ OPC_MXU__POOL20 ─┬─ 00 ─ OPC_MXU_Q8MAC
+ * ├─ 111010 ─ OPC_MXU__POOL21 ─┬─ 00 ─ OPC_MXU_Q8MAC
* │ └─ 10 ─ OPC_MXU_Q8MACSU
* ├─ 111011 ─ OPC_MXU_Q16SCOP
* ├─ 111100 ─ OPC_MXU_Q8MADL
@@ -1703,10 +1726,10 @@ enum {
* └─ 111111 ─ <not assigned> (overlaps with SDBBP)
*
*
- * Compiled after:
+ * Compiled after:
*
* "XBurst® Instruction Set Architecture MIPS eXtension/enhanced Unit
- * Programming Manual", Ingenic Semiconductor Co, Ltd., 2017
+ * Programming Manual", Ingenic Semiconductor Co, Ltd., revision June 2, 2017
*/
enum {
@@ -1750,7 +1773,7 @@ enum {
OPC_MXU_S8SDI = 0x25,
OPC_MXU__POOL15 = 0x26,
OPC_MXU__POOL16 = 0x27,
- OPC_MXU_LXB = 0x28,
+ OPC_MXU__POOL17 = 0x28,
/* not assigned 0x29 */
OPC_MXU_S16LDD = 0x2A,
OPC_MXU_S16STD = 0x2B,
@@ -1764,11 +1787,11 @@ enum {
OPC_MXU_D32SAR = 0x33,
OPC_MXU_Q16SLL = 0x34,
OPC_MXU_Q16SLR = 0x35,
- OPC_MXU__POOL17 = 0x36,
+ OPC_MXU__POOL18 = 0x36,
OPC_MXU_Q16SAR = 0x37,
- OPC_MXU__POOL18 = 0x38,
- OPC_MXU__POOL19 = 0x39,
- OPC_MXU__POOL20 = 0x3A,
+ OPC_MXU__POOL19 = 0x38,
+ OPC_MXU__POOL20 = 0x39,
+ OPC_MXU__POOL21 = 0x3A,
OPC_MXU_Q16SCOP = 0x3B,
OPC_MXU_Q8MADL = 0x3C,
OPC_MXU_S32SFL = 0x3D,
@@ -1930,17 +1953,28 @@ enum {
OPC_MXU_D32SARW = 0x00,
OPC_MXU_S32ALN = 0x01,
OPC_MXU_S32ALNI = 0x02,
- OPC_MXU_S32NOR = 0x03,
- OPC_MXU_S32AND = 0x04,
- OPC_MXU_S32OR = 0x05,
- OPC_MXU_S32XOR = 0x06,
- OPC_MXU_S32LUI = 0x07,
+ OPC_MXU_S32LUI = 0x03,
+ OPC_MXU_S32NOR = 0x04,
+ OPC_MXU_S32AND = 0x05,
+ OPC_MXU_S32OR = 0x06,
+ OPC_MXU_S32XOR = 0x07,
};
/*
* MXU pool 17
*/
enum {
+ OPC_MXU_LXB = 0x00,
+ OPC_MXU_LXH = 0x01,
+ OPC_MXU_LXW = 0x03,
+ OPC_MXU_LXBU = 0x04,
+ OPC_MXU_LXHU = 0x05,
+};
+
+/*
+ * MXU pool 18
+ */
+enum {
OPC_MXU_D32SLLV = 0x00,
OPC_MXU_D32SLRV = 0x01,
OPC_MXU_D32SARV = 0x03,
@@ -1950,7 +1984,7 @@ enum {
};
/*
- * MXU pool 18
+ * MXU pool 19
*/
enum {
OPC_MXU_Q8MUL = 0x00,
@@ -1958,7 +1992,7 @@ enum {
};
/*
- * MXU pool 19
+ * MXU pool 20
*/
enum {
OPC_MXU_Q8MOVZ = 0x00,
@@ -1970,7 +2004,7 @@ enum {
};
/*
- * MXU pool 20
+ * MXU pool 21
*/
enum {
OPC_MXU_Q8MAC = 0x00,
@@ -2421,9 +2455,16 @@ static TCGv_i32 fpu_fcr0, fpu_fcr31;
static TCGv_i64 fpu_f64[32];
static TCGv_i64 msa_wr_d[64];
+#if defined(TARGET_MIPS64)
+/* Upper halves of R5900's 128-bit registers: MMRs (multimedia registers) */
+static TCGv_i64 cpu_mmr[32];
+#endif
+
+#if !defined(TARGET_MIPS64)
/* MXU registers */
static TCGv mxu_gpr[NUMBER_OF_MXU_REGISTERS - 1];
static TCGv mxu_CR;
+#endif
#include "exec/gen-icount.h"
@@ -2501,6 +2542,7 @@ typedef struct DisasContext {
bool mrp;
bool nan2008;
bool abs2008;
+ bool saar;
} DisasContext;
#define DISAS_STOP DISAS_TARGET_0
@@ -2547,10 +2589,12 @@ static const char * const msaregnames[] = {
"w30.d0", "w30.d1", "w31.d0", "w31.d1",
};
+#if !defined(TARGET_MIPS64)
static const char * const mxuregnames[] = {
"XR1", "XR2", "XR3", "XR4", "XR5", "XR6", "XR7", "XR8",
"XR9", "XR10", "XR11", "XR12", "XR13", "XR14", "XR15", "MXU_CR",
};
+#endif
#define LOG_DISAS(...) \
do { \
@@ -2633,6 +2677,7 @@ static inline void gen_store_srsgpr (int from, int to)
}
}
+#if !defined(TARGET_MIPS64)
/* MXU General purpose registers moves. */
static inline void gen_load_mxu_gpr(TCGv t, unsigned int reg)
{
@@ -2661,6 +2706,7 @@ static inline void gen_store_mxu_cr(TCGv t)
/* TODO: Add handling of RW rules for MXU_CR. */
tcg_gen_mov_tl(mxu_CR, t);
}
+#endif
/* Tests */
@@ -4993,8 +5039,8 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
}
/*
- * These MULT and MULTU instructions implemented in for example the
- * Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
+ * These MULT[U] and MADD[U] instructions implemented in for example
+ * the Toshiba/Sony R5900 and the Toshiba TX19, TX39 and TX79 core
* architectures are special three-operand variants with the syntax
*
* MULT[U][1] rd, rs, rt
@@ -5003,6 +5049,14 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
*
* (rd, LO, HI) <- rs * rt
*
+ * and
+ *
+ * MADD[U][1] rd, rs, rt
+ *
+ * such that
+ *
+ * (rd, LO, HI) <- (LO, HI) + rs * rt
+ *
* where the low-order 32-bits of the result is placed into both the
* GPR rd and the special register LO. The high-order 32-bits of the
* result is placed into the special register HI.
@@ -5059,8 +5113,54 @@ static void gen_mul_txx9(DisasContext *ctx, uint32_t opc,
tcg_temp_free_i32(t3);
}
break;
+ case MMI_OPC_MADD1:
+ acc = 1;
+ /* Fall through */
+ case MMI_OPC_MADD:
+ {
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ tcg_gen_ext_tl_i64(t2, t0);
+ tcg_gen_ext_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_add_i64(t2, t2, t3);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ if (rd) {
+ gen_move_low32(cpu_gpr[rd], t2);
+ }
+ tcg_temp_free_i64(t2);
+ }
+ break;
+ case MMI_OPC_MADDU1:
+ acc = 1;
+ /* Fall through */
+ case MMI_OPC_MADDU:
+ {
+ TCGv_i64 t2 = tcg_temp_new_i64();
+ TCGv_i64 t3 = tcg_temp_new_i64();
+
+ tcg_gen_ext32u_tl(t0, t0);
+ tcg_gen_ext32u_tl(t1, t1);
+ tcg_gen_extu_tl_i64(t2, t0);
+ tcg_gen_extu_tl_i64(t3, t1);
+ tcg_gen_mul_i64(t2, t2, t3);
+ tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]);
+ tcg_gen_add_i64(t2, t2, t3);
+ tcg_temp_free_i64(t3);
+ gen_move_low32(cpu_LO[acc], t2);
+ gen_move_high32(cpu_HI[acc], t2);
+ if (rd) {
+ gen_move_low32(cpu_gpr[rd], t2);
+ }
+ tcg_temp_free_i64(t2);
+ }
+ break;
default:
- MIPS_INVAL("mul TXx9");
+ MIPS_INVAL("mul/madd TXx9");
generate_exception_end(ctx, EXCP_RI);
goto out;
}
@@ -6473,55 +6573,66 @@ static inline void gen_mtc0_store32 (TCGv arg, target_ulong off)
static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
switch (reg) {
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0));
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
gen_mfhc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1));
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
default:
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_09:
+ switch (sel) {
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mfhc0_saar(arg, cpu_env);
+ register_name = "SAAR";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
+ break;
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
gen_mfhc0_load64(arg, offsetof(CPUMIPSState, lladdr),
ctx->CP0_LLAddr_shift);
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_mfhc0_maar(arg, cpu_env);
- rn = "MAAR";
+ register_name = "MAAR";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_mfhc0_load64(arg, offsetof(CPUMIPSState, CP0_TagLo), 0);
- rn = "TagLo";
+ register_name = "TagLo";
break;
default:
goto cp0_unimplemented;
@@ -6530,63 +6641,74 @@ static void gen_mfhc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("mfhc0", rn, reg, sel);
+ trace_mips_translate_c0("mfhc0", register_name, reg, sel);
return;
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "mfhc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "mfhc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
tcg_gen_movi_tl(arg, 0);
}
static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
uint64_t mask = ctx->PAMask >> 36;
switch (reg) {
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
tcg_gen_andi_tl(arg, arg, mask);
gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo0));
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
CP0_CHECK(ctx->hflags & MIPS_HFLAG_ELPA);
tcg_gen_andi_tl(arg, arg, mask);
gen_mthc0_entrylo(arg, offsetof(CPUMIPSState, CP0_EntryLo1));
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
default:
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_09:
+ switch (sel) {
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mthc0_saar(cpu_env, arg);
+ register_name = "SAAR";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
/* LLAddr is read-only (the only exception is bit 0 if LLB is
supported); the CP0_LLAddr_rw_bitmask does not seem to be
relevant for modern MIPS cores supporting MTHC0, therefore
treating MTHC0 to LLAddr as NOP. */
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_mthc0_maar(cpu_env, arg);
- rn = "MAAR";
+ register_name = "MAAR";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
@@ -6594,7 +6716,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 6:
tcg_gen_andi_tl(arg, arg, mask);
gen_mthc0_store64(arg, offsetof(CPUMIPSState, CP0_TagLo));
- rn = "TagLo";
+ register_name = "TagLo";
break;
default:
goto cp0_unimplemented;
@@ -6603,10 +6725,11 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("mthc0", rn, reg, sel);
+ trace_mips_translate_c0("mthc0", register_name, reg, sel);
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "mthc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "mthc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
}
static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg)
@@ -6620,89 +6743,89 @@ static inline void gen_mfc0_unimplemented(DisasContext *ctx, TCGv arg)
static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
if (sel != 0)
check_insn(ctx, ISA_MIPS32);
switch (reg) {
- case 0:
+ case CP0_REGISTER_00:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
- rn = "Index";
+ register_name = "Index";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpcontrol(arg, cpu_env);
- rn = "MVPControl";
+ register_name = "MVPControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf0(arg, cpu_env);
- rn = "MVPConf0";
+ register_name = "MVPConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf1(arg, cpu_env);
- rn = "MVPConf1";
+ register_name = "MVPConf1";
break;
case 4:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl));
- rn = "VPControl";
+ register_name = "VPControl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 1:
+ case CP0_REGISTER_01:
switch (sel) {
case 0:
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
gen_helper_mfc0_random(arg, cpu_env);
- rn = "Random";
+ register_name = "Random";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
- rn = "VPEControl";
+ register_name = "VPEControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
- rn = "VPEConf0";
+ register_name = "VPEConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
- rn = "VPEConf1";
+ register_name = "VPEConf1";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_YQMask));
- rn = "YQMask";
+ register_name = "YQMask";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPESchedule));
- rn = "VPESchedule";
+ register_name = "VPESchedule";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load64(arg, offsetof(CPUMIPSState, CP0_VPEScheFBack));
- rn = "VPEScheFBack";
+ register_name = "VPEScheFBack";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
- rn = "VPEOpt";
+ register_name = "VPEOpt";
break;
default:
goto cp0_unimplemented;
}
break;
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
{
@@ -6719,48 +6842,48 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_move_low32(arg, tmp);
tcg_temp_free_i64(tmp);
}
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcstatus(arg, cpu_env);
- rn = "TCStatus";
+ register_name = "TCStatus";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcbind(arg, cpu_env);
- rn = "TCBind";
+ register_name = "TCBind";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcrestart(arg, cpu_env);
- rn = "TCRestart";
+ register_name = "TCRestart";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tchalt(arg, cpu_env);
- rn = "TCHalt";
+ register_name = "TCHalt";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tccontext(arg, cpu_env);
- rn = "TCContext";
+ register_name = "TCContext";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcschedule(arg, cpu_env);
- rn = "TCSchedule";
+ register_name = "TCSchedule";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcschefback(arg, cpu_env);
- rn = "TCScheFBack";
+ register_name = "TCScheFBack";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
{
@@ -6777,172 +6900,172 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_move_low32(arg, tmp);
tcg_temp_free_i64(tmp);
}
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
case 1:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber));
- rn = "GlobalNumber";
+ register_name = "GlobalNumber";
break;
default:
goto cp0_unimplemented;
}
break;
- case 4:
+ case CP0_REGISTER_04:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
tcg_gen_ext32s_tl(arg, arg);
- rn = "Context";
+ register_name = "Context";
break;
case 1:
// gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
- rn = "ContextConfig";
+ register_name = "ContextConfig";
goto cp0_unimplemented;
case 2:
CP0_CHECK(ctx->ulri);
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
tcg_gen_ext32s_tl(arg, arg);
- rn = "UserLocal";
+ register_name = "UserLocal";
break;
default:
goto cp0_unimplemented;
}
break;
- case 5:
+ case CP0_REGISTER_05:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
- rn = "PageMask";
+ register_name = "PageMask";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
- rn = "PageGrain";
+ register_name = "PageGrain";
break;
case 2:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0));
tcg_gen_ext32s_tl(arg, arg);
- rn = "SegCtl0";
+ register_name = "SegCtl0";
break;
case 3:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1));
tcg_gen_ext32s_tl(arg, arg);
- rn = "SegCtl1";
+ register_name = "SegCtl1";
break;
case 4:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2));
tcg_gen_ext32s_tl(arg, arg);
- rn = "SegCtl2";
+ register_name = "SegCtl2";
break;
case 5:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWBase));
- rn = "PWBase";
+ register_name = "PWBase";
break;
case 6:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWField));
- rn = "PWField";
+ register_name = "PWField";
break;
case 7:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWSize));
- rn = "PWSize";
+ register_name = "PWSize";
break;
default:
goto cp0_unimplemented;
}
break;
- case 6:
+ case CP0_REGISTER_06:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
- rn = "Wired";
+ register_name = "Wired";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
- rn = "SRSConf0";
+ register_name = "SRSConf0";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
- rn = "SRSConf1";
+ register_name = "SRSConf1";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
- rn = "SRSConf2";
+ register_name = "SRSConf2";
break;
case 4:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
- rn = "SRSConf3";
+ register_name = "SRSConf3";
break;
case 5:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
- rn = "SRSConf4";
+ register_name = "SRSConf4";
break;
case 6:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl));
- rn = "PWCtl";
+ register_name = "PWCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 7:
+ case CP0_REGISTER_07:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
- rn = "HWREna";
+ register_name = "HWREna";
break;
default:
goto cp0_unimplemented;
}
break;
- case 8:
+ case CP0_REGISTER_08:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
tcg_gen_ext32s_tl(arg, arg);
- rn = "BadVAddr";
+ register_name = "BadVAddr";
break;
case 1:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr));
- rn = "BadInstr";
+ register_name = "BadInstr";
break;
case 2:
CP0_CHECK(ctx->bp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP));
- rn = "BadInstrP";
+ register_name = "BadInstrP";
break;
case 3:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX));
tcg_gen_andi_tl(arg, arg, ~0xffff);
- rn = "BadInstrX";
+ register_name = "BadInstrX";
break;
default:
goto cp0_unimplemented;
}
break;
- case 9:
+ case CP0_REGISTER_09:
switch (sel) {
case 0:
/* Mark as an IO operation because we read the time. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
- }
+ }
gen_helper_mfc0_count(arg, cpu_env);
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
gen_io_end();
@@ -6952,164 +7075,173 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ensure we break completely out of translated code. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Count";
+ register_name = "Count";
+ break;
+ case 6:
+ CP0_CHECK(ctx->saar);
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI));
+ register_name = "SAARI";
+ break;
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mfc0_saar(arg, cpu_env);
+ register_name = "SAAR";
break;
- /* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 10:
+ case CP0_REGISTER_10:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
tcg_gen_ext32s_tl(arg, arg);
- rn = "EntryHi";
+ register_name = "EntryHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 11:
+ case CP0_REGISTER_11:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
- rn = "Compare";
+ register_name = "Compare";
break;
/* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 12:
+ case CP0_REGISTER_12:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
- rn = "Status";
+ register_name = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
- rn = "IntCtl";
+ register_name = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
- rn = "SRSCtl";
+ register_name = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
- rn = "SRSMap";
+ register_name = "SRSMap";
break;
default:
goto cp0_unimplemented;
}
break;
- case 13:
+ case CP0_REGISTER_13:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
- rn = "Cause";
+ register_name = "Cause";
break;
default:
goto cp0_unimplemented;
}
break;
- case 14:
+ case CP0_REGISTER_14:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
tcg_gen_ext32s_tl(arg, arg);
- rn = "EPC";
+ register_name = "EPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 15:
+ case CP0_REGISTER_15:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
- rn = "PRid";
+ register_name = "PRid";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
tcg_gen_ext32s_tl(arg, arg);
- rn = "EBase";
+ register_name = "EBase";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
CP0_CHECK(ctx->cmgcr);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase));
tcg_gen_ext32s_tl(arg, arg);
- rn = "CMGCRBase";
+ register_name = "CMGCRBase";
break;
default:
goto cp0_unimplemented;
}
break;
- case 16:
+ case CP0_REGISTER_16:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
- rn = "Config";
+ register_name = "Config";
break;
case 1:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
- rn = "Config1";
+ register_name = "Config1";
break;
case 2:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
- rn = "Config2";
+ register_name = "Config2";
break;
case 3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
- rn = "Config3";
+ register_name = "Config3";
break;
case 4:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4));
- rn = "Config4";
+ register_name = "Config4";
break;
case 5:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
- rn = "Config5";
+ register_name = "Config5";
break;
/* 6,7 are implementation dependent */
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
- rn = "Config6";
+ register_name = "Config6";
break;
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
- rn = "Config7";
+ register_name = "Config7";
break;
default:
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
gen_helper_mfc0_lladdr(arg, cpu_env);
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_mfc0_maar(arg, cpu_env);
- rn = "MAAR";
+ register_name = "MAAR";
break;
case 2:
CP0_CHECK(ctx->mrp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI));
- rn = "MAARI";
+ register_name = "MAARI";
break;
default:
goto cp0_unimplemented;
}
break;
- case 18:
+ case CP0_REGISTER_18:
switch (sel) {
case 0:
case 1:
@@ -7121,13 +7253,13 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchlo, arg, sel);
- rn = "WatchLo";
+ register_name = "WatchLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 19:
+ case CP0_REGISTER_19:
switch (sel) {
case 0:
case 1:
@@ -7139,142 +7271,142 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchhi, arg, sel);
- rn = "WatchHi";
+ register_name = "WatchHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 20:
+ case CP0_REGISTER_20:
switch (sel) {
case 0:
#if defined(TARGET_MIPS64)
check_insn(ctx, ISA_MIPS3);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
tcg_gen_ext32s_tl(arg, arg);
- rn = "XContext";
+ register_name = "XContext";
break;
#endif
default:
goto cp0_unimplemented;
}
break;
- case 21:
+ case CP0_REGISTER_21:
/* Officially reserved, but sel 0 is used for R1x000 framemask */
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask));
- rn = "Framemask";
+ register_name = "Framemask";
break;
default:
goto cp0_unimplemented;
}
break;
- case 22:
+ case CP0_REGISTER_22:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "'Diagnostic"; /* implementation dependent */
+ register_name = "'Diagnostic"; /* implementation dependent */
break;
- case 23:
+ case CP0_REGISTER_23:
switch (sel) {
case 0:
gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */
- rn = "Debug";
+ register_name = "Debug";
break;
case 1:
// gen_helper_mfc0_tracecontrol(arg); /* PDtrace support */
- rn = "TraceControl";
+ register_name = "TraceControl";
goto cp0_unimplemented;
case 2:
// gen_helper_mfc0_tracecontrol2(arg); /* PDtrace support */
- rn = "TraceControl2";
+ register_name = "TraceControl2";
goto cp0_unimplemented;
case 3:
// gen_helper_mfc0_usertracedata(arg); /* PDtrace support */
- rn = "UserTraceData";
+ register_name = "UserTraceData";
goto cp0_unimplemented;
case 4:
// gen_helper_mfc0_tracebpc(arg); /* PDtrace support */
- rn = "TraceBPC";
+ register_name = "TraceBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 24:
+ case CP0_REGISTER_24:
switch (sel) {
case 0:
/* EJTAG support */
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
tcg_gen_ext32s_tl(arg, arg);
- rn = "DEPC";
+ register_name = "DEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 25:
+ case CP0_REGISTER_25:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
- rn = "Performance0";
+ register_name = "Performance0";
break;
case 1:
// gen_helper_mfc0_performance1(arg);
- rn = "Performance1";
+ register_name = "Performance1";
goto cp0_unimplemented;
case 2:
// gen_helper_mfc0_performance2(arg);
- rn = "Performance2";
+ register_name = "Performance2";
goto cp0_unimplemented;
case 3:
// gen_helper_mfc0_performance3(arg);
- rn = "Performance3";
+ register_name = "Performance3";
goto cp0_unimplemented;
case 4:
// gen_helper_mfc0_performance4(arg);
- rn = "Performance4";
+ register_name = "Performance4";
goto cp0_unimplemented;
case 5:
// gen_helper_mfc0_performance5(arg);
- rn = "Performance5";
+ register_name = "Performance5";
goto cp0_unimplemented;
case 6:
// gen_helper_mfc0_performance6(arg);
- rn = "Performance6";
+ register_name = "Performance6";
goto cp0_unimplemented;
case 7:
// gen_helper_mfc0_performance7(arg);
- rn = "Performance7";
+ register_name = "Performance7";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 26:
+ case CP0_REGISTER_26:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
- rn = "ErrCtl";
+ register_name = "ErrCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 27:
+ case CP0_REGISTER_27:
switch (sel) {
case 0:
case 1:
case 2:
case 3:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "CacheErr";
+ register_name = "CacheErr";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
@@ -7286,56 +7418,56 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_move_low32(arg, tmp);
tcg_temp_free_i64(tmp);
}
- rn = "TagLo";
+ register_name = "TagLo";
break;
case 1:
case 3:
case 5:
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
- rn = "DataLo";
+ register_name = "DataLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 29:
+ case CP0_REGISTER_29:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
- rn = "TagHi";
+ register_name = "TagHi";
break;
case 1:
case 3:
case 5:
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
- rn = "DataHi";
+ register_name = "DataHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 30:
+ case CP0_REGISTER_30:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
tcg_gen_ext32s_tl(arg, arg);
- rn = "ErrorEPC";
+ register_name = "ErrorEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 31:
+ case CP0_REGISTER_31:
switch (sel) {
case 0:
/* EJTAG support */
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
- rn = "DESAVE";
+ register_name = "DESAVE";
break;
case 2:
case 3:
@@ -7347,7 +7479,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
tcg_gen_ext32s_tl(arg, arg);
- rn = "KScratch";
+ register_name = "KScratch";
break;
default:
goto cp0_unimplemented;
@@ -7356,17 +7488,18 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("mfc0", rn, reg, sel);
+ trace_mips_translate_c0("mfc0", register_name, reg, sel);
return;
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "mfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "mfc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
gen_mfc0_unimplemented(ctx, arg);
}
static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
if (sel != 0)
check_insn(ctx, ISA_MIPS32);
@@ -7376,316 +7509,325 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
switch (reg) {
- case 0:
+ case CP0_REGISTER_00:
switch (sel) {
case 0:
gen_helper_mtc0_index(cpu_env, arg);
- rn = "Index";
+ register_name = "Index";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_mvpcontrol(cpu_env, arg);
- rn = "MVPControl";
+ register_name = "MVPControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
- rn = "MVPConf0";
+ register_name = "MVPConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
- rn = "MVPConf1";
+ register_name = "MVPConf1";
break;
case 4:
CP0_CHECK(ctx->vp);
/* ignored */
- rn = "VPControl";
+ register_name = "VPControl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 1:
+ case CP0_REGISTER_01:
switch (sel) {
case 0:
/* ignored */
- rn = "Random";
+ register_name = "Random";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpecontrol(cpu_env, arg);
- rn = "VPEControl";
+ register_name = "VPEControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf0(cpu_env, arg);
- rn = "VPEConf0";
+ register_name = "VPEConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf1(cpu_env, arg);
- rn = "VPEConf1";
+ register_name = "VPEConf1";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_yqmask(cpu_env, arg);
- rn = "YQMask";
+ register_name = "YQMask";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_VPESchedule));
- rn = "VPESchedule";
+ register_name = "VPESchedule";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_VPEScheFBack));
- rn = "VPEScheFBack";
+ register_name = "VPEScheFBack";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeopt(cpu_env, arg);
- rn = "VPEOpt";
+ register_name = "VPEOpt";
break;
default:
goto cp0_unimplemented;
}
break;
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
gen_helper_mtc0_entrylo0(cpu_env, arg);
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcstatus(cpu_env, arg);
- rn = "TCStatus";
+ register_name = "TCStatus";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcbind(cpu_env, arg);
- rn = "TCBind";
+ register_name = "TCBind";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcrestart(cpu_env, arg);
- rn = "TCRestart";
+ register_name = "TCRestart";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tchalt(cpu_env, arg);
- rn = "TCHalt";
+ register_name = "TCHalt";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tccontext(cpu_env, arg);
- rn = "TCContext";
+ register_name = "TCContext";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschedule(cpu_env, arg);
- rn = "TCSchedule";
+ register_name = "TCSchedule";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschefback(cpu_env, arg);
- rn = "TCScheFBack";
+ register_name = "TCScheFBack";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
gen_helper_mtc0_entrylo1(cpu_env, arg);
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
case 1:
CP0_CHECK(ctx->vp);
/* ignored */
- rn = "GlobalNumber";
+ register_name = "GlobalNumber";
break;
default:
goto cp0_unimplemented;
}
break;
- case 4:
+ case CP0_REGISTER_04:
switch (sel) {
case 0:
gen_helper_mtc0_context(cpu_env, arg);
- rn = "Context";
+ register_name = "Context";
break;
case 1:
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
- rn = "ContextConfig";
+ register_name = "ContextConfig";
goto cp0_unimplemented;
case 2:
CP0_CHECK(ctx->ulri);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
- rn = "UserLocal";
+ register_name = "UserLocal";
break;
default:
goto cp0_unimplemented;
}
break;
- case 5:
+ case CP0_REGISTER_05:
switch (sel) {
case 0:
gen_helper_mtc0_pagemask(cpu_env, arg);
- rn = "PageMask";
+ register_name = "PageMask";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg);
- rn = "PageGrain";
+ register_name = "PageGrain";
ctx->base.is_jmp = DISAS_STOP;
break;
case 2:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl0(cpu_env, arg);
- rn = "SegCtl0";
+ register_name = "SegCtl0";
break;
case 3:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl1(cpu_env, arg);
- rn = "SegCtl1";
+ register_name = "SegCtl1";
break;
case 4:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl2(cpu_env, arg);
- rn = "SegCtl2";
+ register_name = "SegCtl2";
break;
case 5:
check_pw(ctx);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_PWBase));
- rn = "PWBase";
+ register_name = "PWBase";
break;
case 6:
check_pw(ctx);
gen_helper_mtc0_pwfield(cpu_env, arg);
- rn = "PWField";
+ register_name = "PWField";
break;
case 7:
check_pw(ctx);
gen_helper_mtc0_pwsize(cpu_env, arg);
- rn = "PWSize";
+ register_name = "PWSize";
break;
default:
goto cp0_unimplemented;
}
break;
- case 6:
+ case CP0_REGISTER_06:
switch (sel) {
case 0:
gen_helper_mtc0_wired(cpu_env, arg);
- rn = "Wired";
+ register_name = "Wired";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf0(cpu_env, arg);
- rn = "SRSConf0";
+ register_name = "SRSConf0";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf1(cpu_env, arg);
- rn = "SRSConf1";
+ register_name = "SRSConf1";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf2(cpu_env, arg);
- rn = "SRSConf2";
+ register_name = "SRSConf2";
break;
case 4:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf3(cpu_env, arg);
- rn = "SRSConf3";
+ register_name = "SRSConf3";
break;
case 5:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf4(cpu_env, arg);
- rn = "SRSConf4";
+ register_name = "SRSConf4";
break;
case 6:
check_pw(ctx);
gen_helper_mtc0_pwctl(cpu_env, arg);
- rn = "PWCtl";
+ register_name = "PWCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 7:
+ case CP0_REGISTER_07:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
- rn = "HWREna";
+ register_name = "HWREna";
break;
default:
goto cp0_unimplemented;
}
break;
- case 8:
+ case CP0_REGISTER_08:
switch (sel) {
case 0:
/* ignored */
- rn = "BadVAddr";
+ register_name = "BadVAddr";
break;
case 1:
/* ignored */
- rn = "BadInstr";
+ register_name = "BadInstr";
break;
case 2:
/* ignored */
- rn = "BadInstrP";
+ register_name = "BadInstrP";
break;
case 3:
/* ignored */
- rn = "BadInstrX";
+ register_name = "BadInstrX";
break;
default:
goto cp0_unimplemented;
}
break;
- case 9:
+ case CP0_REGISTER_09:
switch (sel) {
case 0:
gen_helper_mtc0_count(cpu_env, arg);
- rn = "Count";
+ register_name = "Count";
+ break;
+ case 6:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mtc0_saari(cpu_env, arg);
+ register_name = "SAARI";
+ break;
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mtc0_saar(cpu_env, arg);
+ register_name = "SAAR";
break;
- /* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 10:
+ case CP0_REGISTER_10:
switch (sel) {
case 0:
gen_helper_mtc0_entryhi(cpu_env, arg);
- rn = "EntryHi";
+ register_name = "EntryHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 11:
+ case CP0_REGISTER_11:
switch (sel) {
case 0:
gen_helper_mtc0_compare(cpu_env, arg);
- rn = "Compare";
+ register_name = "Compare";
break;
/* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 12:
+ case CP0_REGISTER_12:
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
@@ -7693,34 +7835,34 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Status";
+ register_name = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "IntCtl";
+ register_name = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "SRSCtl";
+ register_name = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "SRSMap";
+ register_name = "SRSMap";
break;
default:
goto cp0_unimplemented;
}
break;
- case 13:
+ case CP0_REGISTER_13:
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
@@ -7730,107 +7872,107 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
* translated code to check for pending interrupts. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Cause";
+ register_name = "Cause";
break;
default:
goto cp0_unimplemented;
}
break;
- case 14:
+ case CP0_REGISTER_14:
switch (sel) {
case 0:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
- rn = "EPC";
+ register_name = "EPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 15:
+ case CP0_REGISTER_15:
switch (sel) {
case 0:
/* ignored */
- rn = "PRid";
+ register_name = "PRid";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_ebase(cpu_env, arg);
- rn = "EBase";
+ register_name = "EBase";
break;
default:
goto cp0_unimplemented;
}
break;
- case 16:
+ case CP0_REGISTER_16:
switch (sel) {
case 0:
gen_helper_mtc0_config0(cpu_env, arg);
- rn = "Config";
+ register_name = "Config";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 1:
/* ignored, read only */
- rn = "Config1";
+ register_name = "Config1";
break;
case 2:
gen_helper_mtc0_config2(cpu_env, arg);
- rn = "Config2";
+ register_name = "Config2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 3:
gen_helper_mtc0_config3(cpu_env, arg);
- rn = "Config3";
+ register_name = "Config3";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 4:
gen_helper_mtc0_config4(cpu_env, arg);
- rn = "Config4";
+ register_name = "Config4";
ctx->base.is_jmp = DISAS_STOP;
break;
case 5:
gen_helper_mtc0_config5(cpu_env, arg);
- rn = "Config5";
+ register_name = "Config5";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
/* 6,7 are implementation dependent */
case 6:
/* ignored */
- rn = "Config6";
+ register_name = "Config6";
break;
case 7:
/* ignored */
- rn = "Config7";
+ register_name = "Config7";
break;
default:
- rn = "Invalid config selector";
+ register_name = "Invalid config selector";
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
gen_helper_mtc0_lladdr(cpu_env, arg);
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maar(cpu_env, arg);
- rn = "MAAR";
+ register_name = "MAAR";
break;
case 2:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maari(cpu_env, arg);
- rn = "MAARI";
+ register_name = "MAARI";
break;
default:
goto cp0_unimplemented;
}
break;
- case 18:
+ case CP0_REGISTER_18:
switch (sel) {
case 0:
case 1:
@@ -7842,13 +7984,13 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchlo, arg, sel);
- rn = "WatchLo";
+ register_name = "WatchLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 19:
+ case CP0_REGISTER_19:
switch (sel) {
case 0:
case 1:
@@ -7860,59 +8002,59 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchhi, arg, sel);
- rn = "WatchHi";
+ register_name = "WatchHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 20:
+ case CP0_REGISTER_20:
switch (sel) {
case 0:
#if defined(TARGET_MIPS64)
check_insn(ctx, ISA_MIPS3);
gen_helper_mtc0_xcontext(cpu_env, arg);
- rn = "XContext";
+ register_name = "XContext";
break;
#endif
default:
goto cp0_unimplemented;
}
break;
- case 21:
+ case CP0_REGISTER_21:
/* Officially reserved, but sel 0 is used for R1x000 framemask */
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
switch (sel) {
case 0:
gen_helper_mtc0_framemask(cpu_env, arg);
- rn = "Framemask";
+ register_name = "Framemask";
break;
default:
goto cp0_unimplemented;
}
break;
- case 22:
+ case CP0_REGISTER_22:
/* ignored */
- rn = "Diagnostic"; /* implementation dependent */
+ register_name = "Diagnostic"; /* implementation dependent */
break;
- case 23:
+ case CP0_REGISTER_23:
switch (sel) {
case 0:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Debug";
+ register_name = "Debug";
break;
case 1:
// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
- rn = "TraceControl";
+ register_name = "TraceControl";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
- rn = "TraceControl2";
+ register_name = "TraceControl2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
@@ -7920,7 +8062,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
- rn = "UserTraceData";
+ register_name = "UserTraceData";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
goto cp0_unimplemented;
@@ -7928,142 +8070,142 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "TraceBPC";
+ register_name = "TraceBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 24:
+ case CP0_REGISTER_24:
switch (sel) {
case 0:
/* EJTAG support */
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
- rn = "DEPC";
+ register_name = "DEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 25:
+ case CP0_REGISTER_25:
switch (sel) {
case 0:
gen_helper_mtc0_performance0(cpu_env, arg);
- rn = "Performance0";
+ register_name = "Performance0";
break;
case 1:
// gen_helper_mtc0_performance1(arg);
- rn = "Performance1";
+ register_name = "Performance1";
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_performance2(arg);
- rn = "Performance2";
+ register_name = "Performance2";
goto cp0_unimplemented;
case 3:
// gen_helper_mtc0_performance3(arg);
- rn = "Performance3";
+ register_name = "Performance3";
goto cp0_unimplemented;
case 4:
// gen_helper_mtc0_performance4(arg);
- rn = "Performance4";
+ register_name = "Performance4";
goto cp0_unimplemented;
case 5:
// gen_helper_mtc0_performance5(arg);
- rn = "Performance5";
+ register_name = "Performance5";
goto cp0_unimplemented;
case 6:
// gen_helper_mtc0_performance6(arg);
- rn = "Performance6";
+ register_name = "Performance6";
goto cp0_unimplemented;
case 7:
// gen_helper_mtc0_performance7(arg);
- rn = "Performance7";
+ register_name = "Performance7";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 26:
+ case CP0_REGISTER_26:
switch (sel) {
case 0:
gen_helper_mtc0_errctl(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
- rn = "ErrCtl";
+ register_name = "ErrCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 27:
+ case CP0_REGISTER_27:
switch (sel) {
case 0:
case 1:
case 2:
case 3:
/* ignored */
- rn = "CacheErr";
+ register_name = "CacheErr";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_helper_mtc0_taglo(cpu_env, arg);
- rn = "TagLo";
+ register_name = "TagLo";
break;
case 1:
case 3:
case 5:
case 7:
gen_helper_mtc0_datalo(cpu_env, arg);
- rn = "DataLo";
+ register_name = "DataLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 29:
+ case CP0_REGISTER_29:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_helper_mtc0_taghi(cpu_env, arg);
- rn = "TagHi";
+ register_name = "TagHi";
break;
case 1:
case 3:
case 5:
case 7:
gen_helper_mtc0_datahi(cpu_env, arg);
- rn = "DataHi";
+ register_name = "DataHi";
break;
default:
- rn = "invalid sel";
+ register_name = "invalid sel";
goto cp0_unimplemented;
}
break;
- case 30:
+ case CP0_REGISTER_30:
switch (sel) {
case 0:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
- rn = "ErrorEPC";
+ register_name = "ErrorEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 31:
+ case CP0_REGISTER_31:
switch (sel) {
case 0:
/* EJTAG support */
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
- rn = "DESAVE";
+ register_name = "DESAVE";
break;
case 2:
case 3:
@@ -8074,7 +8216,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
- rn = "KScratch";
+ register_name = "KScratch";
break;
default:
goto cp0_unimplemented;
@@ -8083,7 +8225,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("mtc0", rn, reg, sel);
+ trace_mips_translate_c0("mtc0", register_name, reg, sel);
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
@@ -8096,297 +8238,298 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
return;
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "mtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "mtc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
}
#if defined(TARGET_MIPS64)
static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
if (sel != 0)
check_insn(ctx, ISA_MIPS64);
switch (reg) {
- case 0:
+ case CP0_REGISTER_00:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Index));
- rn = "Index";
+ register_name = "Index";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpcontrol(arg, cpu_env);
- rn = "MVPControl";
+ register_name = "MVPControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf0(arg, cpu_env);
- rn = "MVPConf0";
+ register_name = "MVPConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_mvpconf1(arg, cpu_env);
- rn = "MVPConf1";
+ register_name = "MVPConf1";
break;
case 4:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPControl));
- rn = "VPControl";
+ register_name = "VPControl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 1:
+ case CP0_REGISTER_01:
switch (sel) {
case 0:
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
gen_helper_mfc0_random(arg, cpu_env);
- rn = "Random";
+ register_name = "Random";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEControl));
- rn = "VPEControl";
+ register_name = "VPEControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf0));
- rn = "VPEConf0";
+ register_name = "VPEConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEConf1));
- rn = "VPEConf1";
+ register_name = "VPEConf1";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask));
- rn = "YQMask";
+ register_name = "YQMask";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
- rn = "VPESchedule";
+ register_name = "VPESchedule";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
- rn = "VPEScheFBack";
+ register_name = "VPEScheFBack";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_VPEOpt));
- rn = "VPEOpt";
+ register_name = "VPEOpt";
break;
default:
goto cp0_unimplemented;
}
break;
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0));
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcstatus(arg, cpu_env);
- rn = "TCStatus";
+ register_name = "TCStatus";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mfc0_tcbind(arg, cpu_env);
- rn = "TCBind";
+ register_name = "TCBind";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcrestart(arg, cpu_env);
- rn = "TCRestart";
+ register_name = "TCRestart";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tchalt(arg, cpu_env);
- rn = "TCHalt";
+ register_name = "TCHalt";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tccontext(arg, cpu_env);
- rn = "TCContext";
+ register_name = "TCContext";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcschedule(arg, cpu_env);
- rn = "TCSchedule";
+ register_name = "TCSchedule";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_dmfc0_tcschefback(arg, cpu_env);
- rn = "TCScheFBack";
+ register_name = "TCScheFBack";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo1));
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
case 1:
CP0_CHECK(ctx->vp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_GlobalNumber));
- rn = "GlobalNumber";
+ register_name = "GlobalNumber";
break;
default:
goto cp0_unimplemented;
}
break;
- case 4:
+ case CP0_REGISTER_04:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_Context));
- rn = "Context";
+ register_name = "Context";
break;
case 1:
// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
- rn = "ContextConfig";
+ register_name = "ContextConfig";
goto cp0_unimplemented;
case 2:
CP0_CHECK(ctx->ulri);
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
- rn = "UserLocal";
+ register_name = "UserLocal";
break;
default:
goto cp0_unimplemented;
}
break;
- case 5:
+ case CP0_REGISTER_05:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageMask));
- rn = "PageMask";
+ register_name = "PageMask";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PageGrain));
- rn = "PageGrain";
+ register_name = "PageGrain";
break;
case 2:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl0));
- rn = "SegCtl0";
+ register_name = "SegCtl0";
break;
case 3:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl1));
- rn = "SegCtl1";
+ register_name = "SegCtl1";
break;
case 4:
CP0_CHECK(ctx->sc);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_SegCtl2));
- rn = "SegCtl2";
+ register_name = "SegCtl2";
break;
case 5:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase));
- rn = "PWBase";
+ register_name = "PWBase";
break;
case 6:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWField));
- rn = "PWField";
+ register_name = "PWField";
break;
case 7:
check_pw(ctx);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWSize));
- rn = "PWSize";
+ register_name = "PWSize";
break;
default:
goto cp0_unimplemented;
}
break;
- case 6:
+ case CP0_REGISTER_06:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Wired));
- rn = "Wired";
+ register_name = "Wired";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf0));
- rn = "SRSConf0";
+ register_name = "SRSConf0";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf1));
- rn = "SRSConf1";
+ register_name = "SRSConf1";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf2));
- rn = "SRSConf2";
+ register_name = "SRSConf2";
break;
case 4:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf3));
- rn = "SRSConf3";
+ register_name = "SRSConf3";
break;
case 5:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSConf4));
- rn = "SRSConf4";
+ register_name = "SRSConf4";
break;
case 6:
check_pw(ctx);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PWCtl));
- rn = "PWCtl";
+ register_name = "PWCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 7:
+ case CP0_REGISTER_07:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_HWREna));
- rn = "HWREna";
+ register_name = "HWREna";
break;
default:
goto cp0_unimplemented;
}
break;
- case 8:
+ case CP0_REGISTER_08:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
- rn = "BadVAddr";
+ register_name = "BadVAddr";
break;
case 1:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstr));
- rn = "BadInstr";
+ register_name = "BadInstr";
break;
case 2:
CP0_CHECK(ctx->bp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrP));
- rn = "BadInstrP";
+ register_name = "BadInstrP";
break;
case 3:
CP0_CHECK(ctx->bi);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_BadInstrX));
tcg_gen_andi_tl(arg, arg, ~0xffff);
- rn = "BadInstrX";
+ register_name = "BadInstrX";
break;
default:
goto cp0_unimplemented;
}
break;
- case 9:
+ case CP0_REGISTER_09:
switch (sel) {
case 0:
/* Mark as an IO operation because we read the time. */
@@ -8402,160 +8545,169 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
ensure we break completely out of translated code. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Count";
+ register_name = "Count";
+ break;
+ case 6:
+ CP0_CHECK(ctx->saar);
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SAARI));
+ register_name = "SAARI";
+ break;
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_dmfc0_saar(arg, cpu_env);
+ register_name = "SAAR";
break;
- /* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 10:
+ case CP0_REGISTER_10:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryHi));
- rn = "EntryHi";
+ register_name = "EntryHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 11:
+ case CP0_REGISTER_11:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Compare));
- rn = "Compare";
+ register_name = "Compare";
break;
/* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
break;
- case 12:
+ case CP0_REGISTER_12:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Status));
- rn = "Status";
+ register_name = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_IntCtl));
- rn = "IntCtl";
+ register_name = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSCtl));
- rn = "SRSCtl";
+ register_name = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
- rn = "SRSMap";
+ register_name = "SRSMap";
break;
default:
goto cp0_unimplemented;
}
break;
- case 13:
+ case CP0_REGISTER_13:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Cause));
- rn = "Cause";
+ register_name = "Cause";
break;
default:
goto cp0_unimplemented;
}
break;
- case 14:
+ case CP0_REGISTER_14:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
- rn = "EPC";
+ register_name = "EPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 15:
+ case CP0_REGISTER_15:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_PRid));
- rn = "PRid";
+ register_name = "PRid";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
- rn = "EBase";
+ register_name = "EBase";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
CP0_CHECK(ctx->cmgcr);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_CMGCRBase));
- rn = "CMGCRBase";
+ register_name = "CMGCRBase";
break;
default:
goto cp0_unimplemented;
}
break;
- case 16:
+ case CP0_REGISTER_16:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config0));
- rn = "Config";
+ register_name = "Config";
break;
case 1:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config1));
- rn = "Config1";
+ register_name = "Config1";
break;
case 2:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config2));
- rn = "Config2";
+ register_name = "Config2";
break;
case 3:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
- rn = "Config3";
+ register_name = "Config3";
break;
case 4:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4));
- rn = "Config4";
+ register_name = "Config4";
break;
case 5:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
- rn = "Config5";
+ register_name = "Config5";
break;
/* 6,7 are implementation dependent */
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
- rn = "Config6";
+ register_name = "Config6";
break;
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config7));
- rn = "Config7";
+ register_name = "Config7";
break;
default:
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
gen_helper_dmfc0_lladdr(arg, cpu_env);
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_dmfc0_maar(arg, cpu_env);
- rn = "MAAR";
+ register_name = "MAAR";
break;
case 2:
CP0_CHECK(ctx->mrp);
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_MAARI));
- rn = "MAARI";
+ register_name = "MAARI";
break;
default:
goto cp0_unimplemented;
}
break;
- case 18:
+ case CP0_REGISTER_18:
switch (sel) {
case 0:
case 1:
@@ -8567,13 +8719,13 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(dmfc0_watchlo, arg, sel);
- rn = "WatchLo";
+ register_name = "WatchLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 19:
+ case CP0_REGISTER_19:
switch (sel) {
case 0:
case 1:
@@ -8585,125 +8737,125 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_1e0i(mfc0_watchhi, arg, sel);
- rn = "WatchHi";
+ register_name = "WatchHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 20:
+ case CP0_REGISTER_20:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS3);
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_XContext));
- rn = "XContext";
+ register_name = "XContext";
break;
default:
goto cp0_unimplemented;
}
break;
- case 21:
+ case CP0_REGISTER_21:
/* Officially reserved, but sel 0 is used for R1x000 framemask */
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Framemask));
- rn = "Framemask";
+ register_name = "Framemask";
break;
default:
goto cp0_unimplemented;
}
break;
- case 22:
+ case CP0_REGISTER_22:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "'Diagnostic"; /* implementation dependent */
+ register_name = "'Diagnostic"; /* implementation dependent */
break;
- case 23:
+ case CP0_REGISTER_23:
switch (sel) {
case 0:
gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */
- rn = "Debug";
+ register_name = "Debug";
break;
case 1:
// gen_helper_dmfc0_tracecontrol(arg, cpu_env); /* PDtrace support */
- rn = "TraceControl";
+ register_name = "TraceControl";
goto cp0_unimplemented;
case 2:
// gen_helper_dmfc0_tracecontrol2(arg, cpu_env); /* PDtrace support */
- rn = "TraceControl2";
+ register_name = "TraceControl2";
goto cp0_unimplemented;
case 3:
// gen_helper_dmfc0_usertracedata(arg, cpu_env); /* PDtrace support */
- rn = "UserTraceData";
+ register_name = "UserTraceData";
goto cp0_unimplemented;
case 4:
// gen_helper_dmfc0_tracebpc(arg, cpu_env); /* PDtrace support */
- rn = "TraceBPC";
+ register_name = "TraceBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 24:
+ case CP0_REGISTER_24:
switch (sel) {
case 0:
/* EJTAG support */
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
- rn = "DEPC";
+ register_name = "DEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 25:
+ case CP0_REGISTER_25:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Performance0));
- rn = "Performance0";
+ register_name = "Performance0";
break;
case 1:
// gen_helper_dmfc0_performance1(arg);
- rn = "Performance1";
+ register_name = "Performance1";
goto cp0_unimplemented;
case 2:
// gen_helper_dmfc0_performance2(arg);
- rn = "Performance2";
+ register_name = "Performance2";
goto cp0_unimplemented;
case 3:
// gen_helper_dmfc0_performance3(arg);
- rn = "Performance3";
+ register_name = "Performance3";
goto cp0_unimplemented;
case 4:
// gen_helper_dmfc0_performance4(arg);
- rn = "Performance4";
+ register_name = "Performance4";
goto cp0_unimplemented;
case 5:
// gen_helper_dmfc0_performance5(arg);
- rn = "Performance5";
+ register_name = "Performance5";
goto cp0_unimplemented;
case 6:
// gen_helper_dmfc0_performance6(arg);
- rn = "Performance6";
+ register_name = "Performance6";
goto cp0_unimplemented;
case 7:
// gen_helper_dmfc0_performance7(arg);
- rn = "Performance7";
+ register_name = "Performance7";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 26:
+ case CP0_REGISTER_26:
switch (sel) {
case 0:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
- rn = "ErrCtl";
+ register_name = "ErrCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 27:
+ case CP0_REGISTER_27:
switch (sel) {
/* ignored */
case 0:
@@ -8711,68 +8863,68 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 2:
case 3:
tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "CacheErr";
+ register_name = "CacheErr";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagLo));
- rn = "TagLo";
+ register_name = "TagLo";
break;
case 1:
case 3:
case 5:
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataLo));
- rn = "DataLo";
+ register_name = "DataLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 29:
+ case CP0_REGISTER_29:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_TagHi));
- rn = "TagHi";
+ register_name = "TagHi";
break;
case 1:
case 3:
case 5:
case 7:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DataHi));
- rn = "DataHi";
+ register_name = "DataHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 30:
+ case CP0_REGISTER_30:
switch (sel) {
case 0:
tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
- rn = "ErrorEPC";
+ register_name = "ErrorEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 31:
+ case CP0_REGISTER_31:
switch (sel) {
case 0:
/* EJTAG support */
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
- rn = "DESAVE";
+ register_name = "DESAVE";
break;
case 2:
case 3:
@@ -8783,7 +8935,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_ld_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
- rn = "KScratch";
+ register_name = "KScratch";
break;
default:
goto cp0_unimplemented;
@@ -8792,17 +8944,18 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("dmfc0", rn, reg, sel);
+ trace_mips_translate_c0("dmfc0", register_name, reg, sel);
return;
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "dmfc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "dmfc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
gen_mfc0_unimplemented(ctx, arg);
}
static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
{
- const char *rn = "invalid";
+ const char *register_name = "invalid";
if (sel != 0)
check_insn(ctx, ISA_MIPS64);
@@ -8812,308 +8965,317 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
switch (reg) {
- case 0:
+ case CP0_REGISTER_00:
switch (sel) {
case 0:
gen_helper_mtc0_index(cpu_env, arg);
- rn = "Index";
+ register_name = "Index";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_mvpcontrol(cpu_env, arg);
- rn = "MVPControl";
+ register_name = "MVPControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
- rn = "MVPConf0";
+ register_name = "MVPConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
/* ignored */
- rn = "MVPConf1";
+ register_name = "MVPConf1";
break;
case 4:
CP0_CHECK(ctx->vp);
/* ignored */
- rn = "VPControl";
+ register_name = "VPControl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 1:
+ case CP0_REGISTER_01:
switch (sel) {
case 0:
/* ignored */
- rn = "Random";
+ register_name = "Random";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpecontrol(cpu_env, arg);
- rn = "VPEControl";
+ register_name = "VPEControl";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf0(cpu_env, arg);
- rn = "VPEConf0";
+ register_name = "VPEConf0";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeconf1(cpu_env, arg);
- rn = "VPEConf1";
+ register_name = "VPEConf1";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_yqmask(cpu_env, arg);
- rn = "YQMask";
+ register_name = "YQMask";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
- rn = "VPESchedule";
+ register_name = "VPESchedule";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
- rn = "VPEScheFBack";
+ register_name = "VPEScheFBack";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_vpeopt(cpu_env, arg);
- rn = "VPEOpt";
+ register_name = "VPEOpt";
break;
default:
goto cp0_unimplemented;
}
break;
- case 2:
+ case CP0_REGISTER_02:
switch (sel) {
case 0:
gen_helper_dmtc0_entrylo0(cpu_env, arg);
- rn = "EntryLo0";
+ register_name = "EntryLo0";
break;
case 1:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcstatus(cpu_env, arg);
- rn = "TCStatus";
+ register_name = "TCStatus";
break;
case 2:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcbind(cpu_env, arg);
- rn = "TCBind";
+ register_name = "TCBind";
break;
case 3:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcrestart(cpu_env, arg);
- rn = "TCRestart";
+ register_name = "TCRestart";
break;
case 4:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tchalt(cpu_env, arg);
- rn = "TCHalt";
+ register_name = "TCHalt";
break;
case 5:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tccontext(cpu_env, arg);
- rn = "TCContext";
+ register_name = "TCContext";
break;
case 6:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschedule(cpu_env, arg);
- rn = "TCSchedule";
+ register_name = "TCSchedule";
break;
case 7:
CP0_CHECK(ctx->insn_flags & ASE_MT);
gen_helper_mtc0_tcschefback(cpu_env, arg);
- rn = "TCScheFBack";
+ register_name = "TCScheFBack";
break;
default:
goto cp0_unimplemented;
}
break;
- case 3:
+ case CP0_REGISTER_03:
switch (sel) {
case 0:
gen_helper_dmtc0_entrylo1(cpu_env, arg);
- rn = "EntryLo1";
+ register_name = "EntryLo1";
break;
case 1:
CP0_CHECK(ctx->vp);
/* ignored */
- rn = "GlobalNumber";
+ register_name = "GlobalNumber";
break;
default:
goto cp0_unimplemented;
}
break;
- case 4:
+ case CP0_REGISTER_04:
switch (sel) {
case 0:
gen_helper_mtc0_context(cpu_env, arg);
- rn = "Context";
+ register_name = "Context";
break;
case 1:
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
- rn = "ContextConfig";
+ register_name = "ContextConfig";
goto cp0_unimplemented;
case 2:
CP0_CHECK(ctx->ulri);
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, active_tc.CP0_UserLocal));
- rn = "UserLocal";
+ register_name = "UserLocal";
break;
default:
goto cp0_unimplemented;
}
break;
- case 5:
+ case CP0_REGISTER_05:
switch (sel) {
case 0:
gen_helper_mtc0_pagemask(cpu_env, arg);
- rn = "PageMask";
+ register_name = "PageMask";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg);
- rn = "PageGrain";
+ register_name = "PageGrain";
break;
case 2:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl0(cpu_env, arg);
- rn = "SegCtl0";
+ register_name = "SegCtl0";
break;
case 3:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl1(cpu_env, arg);
- rn = "SegCtl1";
+ register_name = "SegCtl1";
break;
case 4:
CP0_CHECK(ctx->sc);
gen_helper_mtc0_segctl2(cpu_env, arg);
- rn = "SegCtl2";
+ register_name = "SegCtl2";
break;
case 5:
check_pw(ctx);
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_PWBase));
- rn = "PWBase";
+ register_name = "PWBase";
break;
case 6:
check_pw(ctx);
gen_helper_mtc0_pwfield(cpu_env, arg);
- rn = "PWField";
+ register_name = "PWField";
break;
case 7:
check_pw(ctx);
gen_helper_mtc0_pwsize(cpu_env, arg);
- rn = "PWSize";
+ register_name = "PWSize";
break;
default:
goto cp0_unimplemented;
}
break;
- case 6:
+ case CP0_REGISTER_06:
switch (sel) {
case 0:
gen_helper_mtc0_wired(cpu_env, arg);
- rn = "Wired";
+ register_name = "Wired";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf0(cpu_env, arg);
- rn = "SRSConf0";
+ register_name = "SRSConf0";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf1(cpu_env, arg);
- rn = "SRSConf1";
+ register_name = "SRSConf1";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf2(cpu_env, arg);
- rn = "SRSConf2";
+ register_name = "SRSConf2";
break;
case 4:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf3(cpu_env, arg);
- rn = "SRSConf3";
+ register_name = "SRSConf3";
break;
case 5:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsconf4(cpu_env, arg);
- rn = "SRSConf4";
+ register_name = "SRSConf4";
break;
case 6:
check_pw(ctx);
gen_helper_mtc0_pwctl(cpu_env, arg);
- rn = "PWCtl";
+ register_name = "PWCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 7:
+ case CP0_REGISTER_07:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
- rn = "HWREna";
+ register_name = "HWREna";
break;
default:
goto cp0_unimplemented;
}
break;
- case 8:
+ case CP0_REGISTER_08:
switch (sel) {
case 0:
/* ignored */
- rn = "BadVAddr";
+ register_name = "BadVAddr";
break;
case 1:
/* ignored */
- rn = "BadInstr";
+ register_name = "BadInstr";
break;
case 2:
/* ignored */
- rn = "BadInstrP";
+ register_name = "BadInstrP";
break;
case 3:
/* ignored */
- rn = "BadInstrX";
+ register_name = "BadInstrX";
break;
default:
goto cp0_unimplemented;
}
break;
- case 9:
+ case CP0_REGISTER_09:
switch (sel) {
case 0:
gen_helper_mtc0_count(cpu_env, arg);
- rn = "Count";
+ register_name = "Count";
+ break;
+ case 6:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mtc0_saari(cpu_env, arg);
+ register_name = "SAARI";
+ break;
+ case 7:
+ CP0_CHECK(ctx->saar);
+ gen_helper_mtc0_saar(cpu_env, arg);
+ register_name = "SAAR";
break;
- /* 6,7 are implementation dependent */
default:
goto cp0_unimplemented;
}
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 10:
+ case CP0_REGISTER_10:
switch (sel) {
case 0:
gen_helper_mtc0_entryhi(cpu_env, arg);
- rn = "EntryHi";
+ register_name = "EntryHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 11:
+ case CP0_REGISTER_11:
switch (sel) {
case 0:
gen_helper_mtc0_compare(cpu_env, arg);
- rn = "Compare";
+ register_name = "Compare";
break;
/* 6,7 are implementation dependent */
default:
@@ -9122,7 +9284,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
- case 12:
+ case CP0_REGISTER_12:
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
@@ -9130,34 +9292,34 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Status";
+ register_name = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "IntCtl";
+ register_name = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "SRSCtl";
+ register_name = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "SRSMap";
+ register_name = "SRSMap";
break;
default:
goto cp0_unimplemented;
}
break;
- case 13:
+ case CP0_REGISTER_13:
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
@@ -9167,98 +9329,98 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
* translated code to check for pending interrupts. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Cause";
+ register_name = "Cause";
break;
default:
goto cp0_unimplemented;
}
break;
- case 14:
+ case CP0_REGISTER_14:
switch (sel) {
case 0:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EPC));
- rn = "EPC";
+ register_name = "EPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 15:
+ case CP0_REGISTER_15:
switch (sel) {
case 0:
/* ignored */
- rn = "PRid";
+ register_name = "PRid";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_ebase(cpu_env, arg);
- rn = "EBase";
+ register_name = "EBase";
break;
default:
goto cp0_unimplemented;
}
break;
- case 16:
+ case CP0_REGISTER_16:
switch (sel) {
case 0:
gen_helper_mtc0_config0(cpu_env, arg);
- rn = "Config";
+ register_name = "Config";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 1:
/* ignored, read only */
- rn = "Config1";
+ register_name = "Config1";
break;
case 2:
gen_helper_mtc0_config2(cpu_env, arg);
- rn = "Config2";
+ register_name = "Config2";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 3:
gen_helper_mtc0_config3(cpu_env, arg);
- rn = "Config3";
+ register_name = "Config3";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
case 4:
/* currently ignored */
- rn = "Config4";
+ register_name = "Config4";
break;
case 5:
gen_helper_mtc0_config5(cpu_env, arg);
- rn = "Config5";
+ register_name = "Config5";
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
break;
/* 6,7 are implementation dependent */
default:
- rn = "Invalid config selector";
+ register_name = "Invalid config selector";
goto cp0_unimplemented;
}
break;
- case 17:
+ case CP0_REGISTER_17:
switch (sel) {
case 0:
gen_helper_mtc0_lladdr(cpu_env, arg);
- rn = "LLAddr";
+ register_name = "LLAddr";
break;
case 1:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maar(cpu_env, arg);
- rn = "MAAR";
+ register_name = "MAAR";
break;
case 2:
CP0_CHECK(ctx->mrp);
gen_helper_mtc0_maari(cpu_env, arg);
- rn = "MAARI";
+ register_name = "MAARI";
break;
default:
goto cp0_unimplemented;
}
break;
- case 18:
+ case CP0_REGISTER_18:
switch (sel) {
case 0:
case 1:
@@ -9270,13 +9432,13 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchlo, arg, sel);
- rn = "WatchLo";
+ register_name = "WatchLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 19:
+ case CP0_REGISTER_19:
switch (sel) {
case 0:
case 1:
@@ -9288,206 +9450,206 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case 7:
CP0_CHECK(ctx->CP0_Config1 & (1 << CP0C1_WR));
gen_helper_0e1i(mtc0_watchhi, arg, sel);
- rn = "WatchHi";
+ register_name = "WatchHi";
break;
default:
goto cp0_unimplemented;
}
break;
- case 20:
+ case CP0_REGISTER_20:
switch (sel) {
case 0:
check_insn(ctx, ISA_MIPS3);
gen_helper_mtc0_xcontext(cpu_env, arg);
- rn = "XContext";
+ register_name = "XContext";
break;
default:
goto cp0_unimplemented;
}
break;
- case 21:
+ case CP0_REGISTER_21:
/* Officially reserved, but sel 0 is used for R1x000 framemask */
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
switch (sel) {
case 0:
gen_helper_mtc0_framemask(cpu_env, arg);
- rn = "Framemask";
+ register_name = "Framemask";
break;
default:
goto cp0_unimplemented;
}
break;
- case 22:
+ case CP0_REGISTER_22:
/* ignored */
- rn = "Diagnostic"; /* implementation dependent */
+ register_name = "Diagnostic"; /* implementation dependent */
break;
- case 23:
+ case CP0_REGISTER_23:
switch (sel) {
case 0:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
/* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
- rn = "Debug";
+ register_name = "Debug";
break;
case 1:
// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "TraceControl";
+ register_name = "TraceControl";
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "TraceControl2";
+ register_name = "TraceControl2";
goto cp0_unimplemented;
case 3:
// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "UserTraceData";
+ register_name = "UserTraceData";
goto cp0_unimplemented;
case 4:
// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
ctx->base.is_jmp = DISAS_STOP;
- rn = "TraceBPC";
+ register_name = "TraceBPC";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 24:
+ case CP0_REGISTER_24:
switch (sel) {
case 0:
/* EJTAG support */
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_DEPC));
- rn = "DEPC";
+ register_name = "DEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 25:
+ case CP0_REGISTER_25:
switch (sel) {
case 0:
gen_helper_mtc0_performance0(cpu_env, arg);
- rn = "Performance0";
+ register_name = "Performance0";
break;
case 1:
// gen_helper_mtc0_performance1(cpu_env, arg);
- rn = "Performance1";
+ register_name = "Performance1";
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_performance2(cpu_env, arg);
- rn = "Performance2";
+ register_name = "Performance2";
goto cp0_unimplemented;
case 3:
// gen_helper_mtc0_performance3(cpu_env, arg);
- rn = "Performance3";
+ register_name = "Performance3";
goto cp0_unimplemented;
case 4:
// gen_helper_mtc0_performance4(cpu_env, arg);
- rn = "Performance4";
+ register_name = "Performance4";
goto cp0_unimplemented;
case 5:
// gen_helper_mtc0_performance5(cpu_env, arg);
- rn = "Performance5";
+ register_name = "Performance5";
goto cp0_unimplemented;
case 6:
// gen_helper_mtc0_performance6(cpu_env, arg);
- rn = "Performance6";
+ register_name = "Performance6";
goto cp0_unimplemented;
case 7:
// gen_helper_mtc0_performance7(cpu_env, arg);
- rn = "Performance7";
+ register_name = "Performance7";
goto cp0_unimplemented;
default:
goto cp0_unimplemented;
}
break;
- case 26:
+ case CP0_REGISTER_26:
switch (sel) {
case 0:
gen_helper_mtc0_errctl(cpu_env, arg);
ctx->base.is_jmp = DISAS_STOP;
- rn = "ErrCtl";
+ register_name = "ErrCtl";
break;
default:
goto cp0_unimplemented;
}
break;
- case 27:
+ case CP0_REGISTER_27:
switch (sel) {
case 0:
case 1:
case 2:
case 3:
/* ignored */
- rn = "CacheErr";
+ register_name = "CacheErr";
break;
default:
goto cp0_unimplemented;
}
break;
- case 28:
+ case CP0_REGISTER_28:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_helper_mtc0_taglo(cpu_env, arg);
- rn = "TagLo";
+ register_name = "TagLo";
break;
case 1:
case 3:
case 5:
case 7:
gen_helper_mtc0_datalo(cpu_env, arg);
- rn = "DataLo";
+ register_name = "DataLo";
break;
default:
goto cp0_unimplemented;
}
break;
- case 29:
+ case CP0_REGISTER_29:
switch (sel) {
case 0:
case 2:
case 4:
case 6:
gen_helper_mtc0_taghi(cpu_env, arg);
- rn = "TagHi";
+ register_name = "TagHi";
break;
case 1:
case 3:
case 5:
case 7:
gen_helper_mtc0_datahi(cpu_env, arg);
- rn = "DataHi";
+ register_name = "DataHi";
break;
default:
- rn = "invalid sel";
+ register_name = "invalid sel";
goto cp0_unimplemented;
}
break;
- case 30:
+ case CP0_REGISTER_30:
switch (sel) {
case 0:
tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_ErrorEPC));
- rn = "ErrorEPC";
+ register_name = "ErrorEPC";
break;
default:
goto cp0_unimplemented;
}
break;
- case 31:
+ case CP0_REGISTER_31:
switch (sel) {
case 0:
/* EJTAG support */
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_DESAVE));
- rn = "DESAVE";
+ register_name = "DESAVE";
break;
case 2:
case 3:
@@ -9498,7 +9660,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_st_tl(arg, cpu_env,
offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
- rn = "KScratch";
+ register_name = "KScratch";
break;
default:
goto cp0_unimplemented;
@@ -9507,7 +9669,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
default:
goto cp0_unimplemented;
}
- trace_mips_translate_c0("dmtc0", rn, reg, sel);
+ trace_mips_translate_c0("dmtc0", register_name, reg, sel);
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
@@ -9520,7 +9682,8 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
return;
cp0_unimplemented:
- qemu_log_mask(LOG_UNIMP, "dmtc0 %s (reg %d sel %d)\n", rn, reg, sel);
+ qemu_log_mask(LOG_UNIMP, "dmtc0 %s (reg %d sel %d)\n",
+ register_name, reg, sel);
}
#endif /* TARGET_MIPS64 */
@@ -24201,6 +24364,8 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
}
+#if !defined(TARGET_MIPS64)
+
/* MXU accumulate add/subtract 1-bit pattern 'aptn1' */
#define MXU_APTN1_A 0
#define MXU_APTN1_S 1
@@ -24218,6 +24383,11 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
#define MXU_EPTN2_SS 3
/* MXU operand getting pattern 'optn2' */
+#define MXU_OPTN2_PTN0 0
+#define MXU_OPTN2_PTN1 1
+#define MXU_OPTN2_PTN2 2
+#define MXU_OPTN2_PTN3 3
+/* alternative naming scheme for 'optn2' */
#define MXU_OPTN2_WW 0
#define MXU_OPTN2_LW 1
#define MXU_OPTN2_HW 2
@@ -24611,6 +24781,641 @@ static void gen_mxu_s32ldd_s32lddr(DisasContext *ctx)
/*
+ * MXU instruction category: logic
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32NOR S32AND S32OR S32XOR
+ */
+
+/*
+ * S32NOR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'nor' operation
+ * applied to the content of XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_S32NOR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 1s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0xFFFFFFFF);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the negation of XRc */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRa zero register -> just set destination to the negation of XRb */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to the negation of XRb */
+ tcg_gen_not_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_nor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32AND XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'and' operation
+ * applied to the content of XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_S32AND(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* one of operands zero register -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_and_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32OR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'or' operation
+ * applied to the content of XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_S32OR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the content of XRc */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just set destination to the content of XRb */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+/*
+ * S32XOR XRa, XRb, XRc
+ * Update XRa with the result of logical bitwise 'xor' operation
+ * applied to the content of XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_S32XOR(DisasContext *ctx)
+{
+ uint32_t pad, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just set destination to the content of XRc */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just set destination to the content of XRb */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else {
+ /* the most general case */
+ tcg_gen_xor_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], mxu_gpr[XRc - 1]);
+ }
+}
+
+
+/*
+ * MXU instruction category max/min
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32MAX D16MAX Q8MAX
+ * S32MIN D16MIN Q8MIN
+ */
+
+/*
+ * S32MAX XRa, XRb, XRc
+ * Update XRa with the maximum of signed 32-bit integers contained
+ * in XRb and XRc.
+ *
+ * S32MIN XRa, XRb, XRc
+ * Update XRa with the minimum of signed 32-bit integers contained
+ * in XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_S32MAX_S32MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* exactly one operand is zero register - find which one is not...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do max/min operation with one operand 0 */
+ if (opc == OPC_MXU_S32MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRx - 1], 0);
+ }
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ if (opc == OPC_MXU_S32MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
+ mxu_gpr[XRc - 1]);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1],
+ mxu_gpr[XRc - 1]);
+ }
+ }
+}
+
+/*
+ * D16MAX
+ * Update XRa with the 16-bit-wise maximums of signed integers
+ * contained in XRb and XRc.
+ *
+ * D16MIN
+ * Update XRa with the 16-bit-wise minimums of signed integers
+ * contained in XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_D16MAX_D16MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRc == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRa == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRc - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRa == 0))) {
+ /* exactly one operand is zero register - find which one is not...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do half-word-wise max/min with one operand 0 */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_const_i32(0);
+
+ /* the left half-word first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFFFF0000);
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* the right half-word */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0x0000FFFF);
+ /* move half-words to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 16);
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting half-words to its original position */
+ tcg_gen_shri_i32(t0, t0, 16);
+ /* finaly update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ /* the left half-word first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFFFF0000);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* the right half-word */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0x0000FFFF);
+ /* move half-words to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 16);
+ tcg_gen_shli_i32(t1, t1, 16);
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_D16MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting half-words to its original position */
+ tcg_gen_shri_i32(t0, t0, 16);
+ /* finaly update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+}
+
+/*
+ * Q8MAX
+ * Update XRa with the 8-bit-wise maximums of signed integers
+ * contained in XRb and XRc.
+ *
+ * Q8MIN
+ * Update XRa with the 8-bit-wise minimums of signed integers
+ * contained in XRb and XRc.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0| opc | XRc | XRb | XRa |MXU__POOL00|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ */
+static void gen_mxu_Q8MAX_Q8MIN(DisasContext *ctx)
+{
+ uint32_t pad, opc, XRc, XRb, XRa;
+
+ pad = extract32(ctx->opcode, 21, 5);
+ opc = extract32(ctx->opcode, 18, 3);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to zero */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely((XRb == 0) || (XRc == 0))) {
+ /* exactly one operand is zero register - make it be the first...*/
+ uint32_t XRx = XRb ? XRb : XRc;
+ /* ...and do byte-wise max/min with one operand 0 */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_const_i32(0);
+ int32_t i;
+
+ /* the leftmost byte (byte 3) first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF000000);
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* bytes 2, 1, 0 */
+ for (i = 2; i >= 0; i--) {
+ /* extract the byte */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRx - 1], 0xFF << (8 * i));
+ /* move the byte to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting byte to its original position */
+ tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
+ /* finaly update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+ }
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just set destination to one of them */
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ } else {
+ /* the most general case */
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+ int32_t i;
+
+ /* the leftmost bytes (bytes 3) first */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF000000);
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(mxu_gpr[XRa - 1], t0, t1);
+ } else {
+ tcg_gen_smin_i32(mxu_gpr[XRa - 1], t0, t1);
+ }
+
+ /* bytes 2, 1, 0 */
+ for (i = 2; i >= 0; i--) {
+ /* extract corresponding bytes */
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0xFF << (8 * i));
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF << (8 * i));
+ /* move the bytes to the leftmost position */
+ tcg_gen_shli_i32(t0, t0, 8 * (3 - i));
+ tcg_gen_shli_i32(t1, t1, 8 * (3 - i));
+ /* t0 will be max/min of t0 and t1 */
+ if (opc == OPC_MXU_Q8MAX) {
+ tcg_gen_smax_i32(t0, t0, t1);
+ } else {
+ tcg_gen_smin_i32(t0, t0, t1);
+ }
+ /* return resulting byte to its original position */
+ tcg_gen_shri_i32(t0, t0, 8 * (3 - i));
+ /* finaly update the destination */
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], mxu_gpr[XRa - 1], t0);
+ }
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+}
+
+
+/*
+ * MXU instruction category: align
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * S32ALN S32ALNI
+ */
+
+/*
+ * S32ALNI XRc, XRb, XRa, optn3
+ * Arrange bytes from XRb and XRc according to one of five sets of
+ * rules determined by optn3, and place the result in XRa.
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+-----+---+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |optn3|0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+-----+---+-----+-------+-------+-------+-----------+
+ *
+ */
+static void gen_mxu_S32ALNI(DisasContext *ctx)
+{
+ uint32_t optn3, pad, XRc, XRb, XRa;
+
+ optn3 = extract32(ctx->opcode, 23, 3);
+ pad = extract32(ctx->opcode, 21, 2);
+ XRc = extract32(ctx->opcode, 14, 4);
+ XRb = extract32(ctx->opcode, 10, 4);
+ XRa = extract32(ctx->opcode, 6, 4);
+
+ if (unlikely(pad != 0)) {
+ /* opcode padding incorrect -> do nothing */
+ } else if (unlikely(XRa == 0)) {
+ /* destination is zero register -> do nothing */
+ } else if (unlikely((XRb == 0) && (XRc == 0))) {
+ /* both operands zero registers -> just set destination to all 0s */
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ } else if (unlikely(XRb == 0)) {
+ /* XRb zero register -> just appropriatelly shift XRc into XRa */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1],
+ 8 * (4 - optn3));
+ break;
+ case MXU_OPTN3_PTN4:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ break;
+ }
+ } else if (unlikely(XRc == 0)) {
+ /* XRc zero register -> just appropriatelly shift XRb into XRa */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_shri_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
+ break;
+ case MXU_OPTN3_PTN4:
+ tcg_gen_movi_i32(mxu_gpr[XRa - 1], 0);
+ break;
+ }
+ } else if (unlikely(XRb == XRc)) {
+ /* both operands same -> just rotation or moving from any of them */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ case MXU_OPTN3_PTN4:
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ break;
+ case MXU_OPTN3_PTN1:
+ case MXU_OPTN3_PTN2:
+ case MXU_OPTN3_PTN3:
+ tcg_gen_rotli_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1], 8 * optn3);
+ break;
+ }
+ } else {
+ /* the most general case */
+ switch (optn3) {
+ case MXU_OPTN3_PTN0:
+ {
+ /* */
+ /* XRb XRc */
+ /* +---------------+ */
+ /* | A B C D | E F G H */
+ /* +-------+-------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRb - 1]);
+ }
+ break;
+ case MXU_OPTN3_PTN1:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A | B C D E | F G H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x00FFFFFF);
+ tcg_gen_shli_i32(t0, t0, 8);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFF000000);
+ tcg_gen_shri_i32(t1, t1, 24);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN2:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A B | C D E F | G H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x0000FFFF);
+ tcg_gen_shli_i32(t0, t0, 16);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFF0000);
+ tcg_gen_shri_i32(t1, t1, 16);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN3:
+ {
+ /* */
+ /* XRb XRc */
+ /* +-------------------+ */
+ /* A B C | D E F G | H */
+ /* +---------+---------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ TCGv_i32 t0 = tcg_temp_new();
+ TCGv_i32 t1 = tcg_temp_new();
+
+ tcg_gen_andi_i32(t0, mxu_gpr[XRb - 1], 0x000000FF);
+ tcg_gen_shli_i32(t0, t0, 24);
+
+ tcg_gen_andi_i32(t1, mxu_gpr[XRc - 1], 0xFFFFFF00);
+ tcg_gen_shri_i32(t1, t1, 8);
+
+ tcg_gen_or_i32(mxu_gpr[XRa - 1], t0, t1);
+
+ tcg_temp_free(t1);
+ tcg_temp_free(t0);
+ }
+ break;
+ case MXU_OPTN3_PTN4:
+ {
+ /* */
+ /* XRb XRc */
+ /* +---------------+ */
+ /* A B C D | E F G H | */
+ /* +-------+-------+ */
+ /* | */
+ /* XRa */
+ /* */
+
+ tcg_gen_mov_i32(mxu_gpr[XRa - 1], mxu_gpr[XRc - 1]);
+ }
+ break;
+ }
+ }
+}
+
+
+/*
* Decoding engine for MXU
* =======================
*/
@@ -24631,34 +25436,16 @@ static void decode_opc_mxu__pool00(CPUMIPSState *env, DisasContext *ctx)
switch (opcode) {
case OPC_MXU_S32MAX:
- /* TODO: Implement emulation of S32MAX instruction. */
- MIPS_INVAL("OPC_MXU_S32MAX");
- generate_exception_end(ctx, EXCP_RI);
- break;
case OPC_MXU_S32MIN:
- /* TODO: Implement emulation of S32MIN instruction. */
- MIPS_INVAL("OPC_MXU_S32MIN");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_S32MAX_S32MIN(ctx);
break;
case OPC_MXU_D16MAX:
- /* TODO: Implement emulation of D16MAX instruction. */
- MIPS_INVAL("OPC_MXU_D16MAX");
- generate_exception_end(ctx, EXCP_RI);
- break;
case OPC_MXU_D16MIN:
- /* TODO: Implement emulation of D16MIN instruction. */
- MIPS_INVAL("OPC_MXU_D16MIN");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_D16MAX_D16MIN(ctx);
break;
case OPC_MXU_Q8MAX:
- /* TODO: Implement emulation of Q8MAX instruction. */
- MIPS_INVAL("OPC_MXU_Q8MAX");
- generate_exception_end(ctx, EXCP_RI);
- break;
case OPC_MXU_Q8MIN:
- /* TODO: Implement emulation of Q8MIN instruction. */
- MIPS_INVAL("OPC_MXU_Q8MIN");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_Q8MAX_Q8MIN(ctx);
break;
case OPC_MXU_Q8SLT:
/* TODO: Implement emulation of Q8SLT instruction. */
@@ -25261,18 +26048,18 @@ static void decode_opc_mxu__pool15(CPUMIPSState *env, DisasContext *ctx)
* | SPECIAL2 | s3 |0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
* +-----------+-----+---+-----+-------+-------+-------+-----------+
*
- * S32NOR, S32AND, S32OR, S32XOR:
- * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- * +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
- * +-----------+---------+-----+-------+-------+-------+-----------+
- *
* S32LUI:
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------+-----+---+-----+-------+---------------+-----------+
* | SPECIAL2 |optn3|0 0|x x x| XRc | s8 |MXU__POOL16|
* +-----------+-----+---+-----+-------+---------------+-----------+
*
+ * S32NOR, S32AND, S32OR, S32XOR:
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL16|
+ * +-----------+---------+-----+-------+-------+-------+-----------+
+ *
*/
static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx)
{
@@ -25290,33 +26077,70 @@ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx)
generate_exception_end(ctx, EXCP_RI);
break;
case OPC_MXU_S32ALNI:
- /* TODO: Implement emulation of S32ALNI instruction. */
- MIPS_INVAL("OPC_MXU_S32ALNI");
+ gen_mxu_S32ALNI(ctx);
+ break;
+ case OPC_MXU_S32LUI:
+ /* TODO: Implement emulation of S32LUI instruction. */
+ MIPS_INVAL("OPC_MXU_S32LUI");
generate_exception_end(ctx, EXCP_RI);
break;
case OPC_MXU_S32NOR:
- /* TODO: Implement emulation of S32NOR instruction. */
- MIPS_INVAL("OPC_MXU_S32NOR");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_S32NOR(ctx);
break;
case OPC_MXU_S32AND:
- /* TODO: Implement emulation of S32AND instruction. */
- MIPS_INVAL("OPC_MXU_S32AND");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_S32AND(ctx);
break;
case OPC_MXU_S32OR:
- /* TODO: Implement emulation of S32OR instruction. */
- MIPS_INVAL("OPC_MXU_S32OR");
- generate_exception_end(ctx, EXCP_RI);
+ gen_mxu_S32OR(ctx);
break;
case OPC_MXU_S32XOR:
- /* TODO: Implement emulation of S32XOR instruction. */
- MIPS_INVAL("OPC_MXU_S32XOR");
+ gen_mxu_S32XOR(ctx);
+ break;
+ default:
+ MIPS_INVAL("decode_opc_mxu");
generate_exception_end(ctx, EXCP_RI);
break;
- case OPC_MXU_S32LUI:
- /* TODO: Implement emulation of S32LUI instruction. */
- MIPS_INVAL("OPC_MXU_S32LUI");
+ }
+}
+
+/*
+ *
+ * Decode MXU pool17
+ *
+ * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +-----------+---------+---------+---+---------+-----+-----------+
+ * | SPECIAL2 | rs | rt |0 0| rd |x x x|MXU__POOL15|
+ * +-----------+---------+---------+---+---------+-----+-----------+
+ *
+ */
+static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx)
+{
+ uint32_t opcode = extract32(ctx->opcode, 6, 2);
+
+ switch (opcode) {
+ case OPC_MXU_LXW:
+ /* TODO: Implement emulation of LXW instruction. */
+ MIPS_INVAL("OPC_MXU_LXW");
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ case OPC_MXU_LXH:
+ /* TODO: Implement emulation of LXH instruction. */
+ MIPS_INVAL("OPC_MXU_LXH");
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ case OPC_MXU_LXHU:
+ /* TODO: Implement emulation of LXHU instruction. */
+ MIPS_INVAL("OPC_MXU_LXHU");
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ case OPC_MXU_LXB:
+ /* TODO: Implement emulation of LXB instruction. */
+ MIPS_INVAL("OPC_MXU_LXB");
+ generate_exception_end(ctx, EXCP_RI);
+ break;
+ case OPC_MXU_LXBU:
+ /* TODO: Implement emulation of LXBU instruction. */
+ MIPS_INVAL("OPC_MXU_LXBU");
generate_exception_end(ctx, EXCP_RI);
break;
default:
@@ -25325,18 +26149,17 @@ static void decode_opc_mxu__pool16(CPUMIPSState *env, DisasContext *ctx)
break;
}
}
-
/*
*
- * Decode MXU pool17
+ * Decode MXU pool18
*
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 | rb |x x x| XRd | XRa |0 0 0 0|MXU__POOL17|
+ * | SPECIAL2 | rb |x x x| XRd | XRa |0 0 0 0|MXU__POOL18|
* +-----------+---------+-----+-------+-------+-------+-----------+
*
*/
-static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = extract32(ctx->opcode, 18, 3);
@@ -25380,15 +26203,15 @@ static void decode_opc_mxu__pool17(CPUMIPSState *env, DisasContext *ctx)
/*
*
- * Decode MXU pool18
+ * Decode MXU pool19
*
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL18|
+ * | SPECIAL2 |0 0|x x| XRd | XRc | XRb | XRa |MXU__POOL19|
* +-----------+---+---+-------+-------+-------+-------+-----------+
*
*/
-static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = extract32(ctx->opcode, 22, 2);
@@ -25406,15 +26229,15 @@ static void decode_opc_mxu__pool18(CPUMIPSState *env, DisasContext *ctx)
/*
*
- * Decode MXU pool19
+ * Decode MXU pool20
*
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------+---------+-----+-------+-------+-------+-----------+
- * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL19|
+ * | SPECIAL2 |0 0 0 0 0|x x x| XRc | XRb | XRa |MXU__POOL20|
* +-----------+---------+-----+-------+-------+-------+-----------+
*
*/
-static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_mxu__pool20(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = extract32(ctx->opcode, 18, 3);
@@ -25458,15 +26281,15 @@ static void decode_opc_mxu__pool19(CPUMIPSState *env, DisasContext *ctx)
/*
*
- * Decode MXU pool20
+ * Decode MXU pool21
*
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
* +-----------+---+---+-------+-------+-------+-------+-----------+
- * | SPECIAL2 |an2|x x| XRd | XRc | XRb | XRa |MXU__POOL20|
+ * | SPECIAL2 |an2|x x| XRd | XRc | XRb | XRa |MXU__POOL21|
* +-----------+---+---+-------+-------+-------+-------+-----------+
*
*/
-static void decode_opc_mxu__pool20(CPUMIPSState *env, DisasContext *ctx)
+static void decode_opc_mxu__pool21(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = extract32(ctx->opcode, 22, 2);
@@ -25669,10 +26492,8 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx)
case OPC_MXU__POOL16:
decode_opc_mxu__pool16(env, ctx);
break;
- case OPC_MXU_LXB:
- /* TODO: Implement emulation of LXB instruction. */
- MIPS_INVAL("OPC_MXU_LXB");
- generate_exception_end(ctx, EXCP_RI);
+ case OPC_MXU__POOL17:
+ decode_opc_mxu__pool17(env, ctx);
break;
case OPC_MXU_S16LDD:
/* TODO: Implement emulation of S16LDD instruction. */
@@ -25724,23 +26545,23 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx)
MIPS_INVAL("OPC_MXU_Q16SLR");
generate_exception_end(ctx, EXCP_RI);
break;
- case OPC_MXU__POOL17:
- decode_opc_mxu__pool17(env, ctx);
+ case OPC_MXU__POOL18:
+ decode_opc_mxu__pool18(env, ctx);
break;
case OPC_MXU_Q16SAR:
/* TODO: Implement emulation of Q16SAR instruction. */
MIPS_INVAL("OPC_MXU_Q16SAR");
generate_exception_end(ctx, EXCP_RI);
break;
- case OPC_MXU__POOL18:
- decode_opc_mxu__pool18(env, ctx);
- break;
case OPC_MXU__POOL19:
decode_opc_mxu__pool19(env, ctx);
break;
case OPC_MXU__POOL20:
decode_opc_mxu__pool20(env, ctx);
break;
+ case OPC_MXU__POOL21:
+ decode_opc_mxu__pool21(env, ctx);
+ break;
case OPC_MXU_Q16SCOP:
/* TODO: Implement emulation of Q16SCOP instruction. */
MIPS_INVAL("OPC_MXU_Q16SCOP");
@@ -25771,6 +26592,8 @@ static void decode_opc_mxu(CPUMIPSState *env, DisasContext *ctx)
}
}
+#endif /* !defined(TARGET_MIPS64) */
+
static void decode_opc_special2_legacy(CPUMIPSState *env, DisasContext *ctx)
{
@@ -26620,6 +27443,10 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
break;
case MMI_OPC_MULT1:
case MMI_OPC_MULTU1:
+ case MMI_OPC_MADD:
+ case MMI_OPC_MADDU:
+ case MMI_OPC_MADD1:
+ case MMI_OPC_MADDU1:
gen_mul_txx9(ctx, opc, rd, rs, rt);
break;
case MMI_OPC_DIV1:
@@ -26634,11 +27461,7 @@ static void decode_mmi(CPUMIPSState *env, DisasContext *ctx)
case MMI_OPC_MFHI1:
gen_HILO1_tx79(ctx, opc, rd);
break;
- case MMI_OPC_MADD: /* TODO: MMI_OPC_MADD */
- case MMI_OPC_MADDU: /* TODO: MMI_OPC_MADDU */
case MMI_OPC_PLZCW: /* TODO: MMI_OPC_PLZCW */
- case MMI_OPC_MADD1: /* TODO: MMI_OPC_MADD1 */
- case MMI_OPC_MADDU1: /* TODO: MMI_OPC_MADDU1 */
case MMI_OPC_PMFHL: /* TODO: MMI_OPC_PMFHL */
case MMI_OPC_PMTHL: /* TODO: MMI_OPC_PMTHL */
case MMI_OPC_PSLLH: /* TODO: MMI_OPC_PSLLH */
@@ -28015,8 +28838,10 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
case OPC_SPECIAL2:
if ((ctx->insn_flags & INSN_R5900) && (ctx->insn_flags & ASE_MMI)) {
decode_mmi(env, ctx);
+#if !defined(TARGET_MIPS64)
} else if (ctx->insn_flags & ASE_MXU) {
decode_opc_mxu(env, ctx);
+#endif
} else {
decode_opc_special2_legacy(env, ctx);
}
@@ -29026,6 +29851,17 @@ void mips_tcg_init(void)
offsetof(CPUMIPSState, active_fpu.fcr31),
"fcr31");
+#if defined(TARGET_MIPS64)
+ cpu_mmr[0] = NULL;
+ for (i = 1; i < 32; i++) {
+ cpu_mmr[i] = tcg_global_mem_new_i64(cpu_env,
+ offsetof(CPUMIPSState,
+ active_tc.mmr[i]),
+ regnames[i]);
+ }
+#endif
+
+#if !defined(TARGET_MIPS64)
for (i = 0; i < NUMBER_OF_MXU_REGISTERS - 1; i++) {
mxu_gpr[i] = tcg_global_mem_new(cpu_env,
offsetof(CPUMIPSState,
@@ -29036,6 +29872,7 @@ void mips_tcg_init(void)
mxu_CR = tcg_global_mem_new(cpu_env,
offsetof(CPUMIPSState, active_tc.mxu_cr),
mxuregnames[NUMBER_OF_MXU_REGISTERS - 1]);
+#endif
}
#include "translate_init.inc.c"
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index cc1460e4e3..3a00606d01 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -140,7 +140,8 @@ static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
memset(fpregset, 0, sizeof(*fpregset));
for (i = 0; i < 32; i++) {
- fpregset->fpr[i] = cpu_to_dump64(s, cpu->env.fpr[i]);
+ uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i);
+ fpregset->fpr[i] = cpu_to_dump64(s, *fpr);
}
fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr);
}
@@ -158,6 +159,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
for (i = 0; i < 32; i++) {
bool needs_byteswap;
+ ppc_avr_t *avr = cpu_avr_ptr(&cpu->env, i);
#ifdef HOST_WORDS_BIGENDIAN
needs_byteswap = s->dump_info.d_endian == ELFDATA2LSB;
@@ -166,11 +168,11 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
#endif
if (needs_byteswap) {
- vmxregset->avr[i].u64[0] = bswap64(cpu->env.avr[i].u64[1]);
- vmxregset->avr[i].u64[1] = bswap64(cpu->env.avr[i].u64[0]);
+ vmxregset->avr[i].u64[0] = bswap64(avr->u64[1]);
+ vmxregset->avr[i].u64[1] = bswap64(avr->u64[0]);
} else {
- vmxregset->avr[i].u64[0] = cpu->env.avr[i].u64[0];
- vmxregset->avr[i].u64[1] = cpu->env.avr[i].u64[1];
+ vmxregset->avr[i].u64[0] = avr->u64[0];
+ vmxregset->avr[i].u64[1] = avr->u64[1];
}
}
vmxregset->vscr.u32[3] = cpu_to_dump32(s, cpu->env.vscr);
@@ -188,7 +190,8 @@ static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
memset(vsxregset, 0, sizeof(*vsxregset));
for (i = 0; i < 32; i++) {
- vsxregset->vsr[i] = cpu_to_dump64(s, cpu->env.vsr[i]);
+ uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i);
+ vsxregset->vsr[i] = cpu_to_dump64(s, *vsrl);
}
}
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index ab68abe8a2..a62ff60414 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -70,26 +70,14 @@
#define PPC_ELF_MACHINE EM_PPC
#endif
-#define PPC_BIT(bit) (0x8000000000000000UL >> (bit))
-#define PPC_BIT32(bit) (0x80000000UL >> (bit))
-#define PPC_BIT8(bit) (0x80UL >> (bit))
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BIT32(bit) (0x80000000 >> (bit))
+#define PPC_BIT8(bit) (0x80 >> (bit))
#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \
PPC_BIT32(bs))
#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs))
-#if HOST_LONG_BITS == 32
-# define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
-#elif HOST_LONG_BITS == 64
-# define MASK_TO_LSH(m) (__builtin_ffsl(m) - 1)
-#else
-# error Unknown sizeof long
-#endif
-
-#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
-#define SETFIELD(m, v, val) \
- (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
-
/*****************************************************************************/
/* Exception vectors definitions */
enum {
@@ -230,7 +218,6 @@ typedef struct opc_handler_t opc_handler_t;
/* Types used to describe some PowerPC registers etc. */
typedef struct DisasContext DisasContext;
typedef struct ppc_spr_t ppc_spr_t;
-typedef union ppc_avr_t ppc_avr_t;
typedef union ppc_tlb_t ppc_tlb_t;
typedef struct ppc_hash_pte64 ppc_hash_pte64_t;
@@ -254,22 +241,26 @@ struct ppc_spr_t {
#endif
};
-/* Altivec registers (128 bits) */
-union ppc_avr_t {
- float32 f[4];
+/* VSX/Altivec registers (128 bits) */
+typedef union _ppc_vsr_t {
uint8_t u8[16];
uint16_t u16[8];
uint32_t u32[4];
+ uint64_t u64[2];
int8_t s8[16];
int16_t s16[8];
int32_t s32[4];
- uint64_t u64[2];
int64_t s64[2];
+ float32 f32[4];
+ float64 f64[2];
+ float128 f128;
#ifdef CONFIG_INT128
__uint128_t u128;
#endif
- Int128 s128;
-};
+ Int128 s128;
+} ppc_vsr_t;
+
+typedef ppc_vsr_t ppc_avr_t;
#if !defined(CONFIG_USER_ONLY)
/* Software TLB cache */
@@ -1013,8 +1004,6 @@ struct CPUPPCState {
/* Floating point execution context */
float_status fp_status;
- /* floating point registers */
- float64 fpr[32];
/* floating point status and control register */
target_ulong fpscr;
@@ -1064,11 +1053,10 @@ struct CPUPPCState {
/* Special purpose registers */
target_ulong spr[1024];
ppc_spr_t spr_cb[1024];
- /* Altivec registers */
- ppc_avr_t avr[32];
+ /* Vector status and control register */
uint32_t vscr;
- /* VSX registers */
- uint64_t vsr[32];
+ /* VSX registers (including FP and AVR) */
+ ppc_vsr_t vsr[64] QEMU_ALIGNED(16);
/* SPE registers */
uint64_t spe_acc;
uint32_t spe_fscr;
@@ -1190,6 +1178,9 @@ do { \
typedef struct PPCVirtualHypervisor PPCVirtualHypervisor;
typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
+struct XiveTCTX;
+struct ICPState;
+
/**
* PowerPCCPU:
* @env: #CPUPPCState
@@ -1207,7 +1198,8 @@ struct PowerPCCPU {
int vcpu_id;
uint32_t compat_pvr;
PPCVirtualHypervisor *vhyp;
- Object *intc;
+ struct ICPState *icp;
+ struct XiveTCTX *tctx;
void *machine_data;
int32_t node_id; /* NUMA node this CPU belongs to */
PPCHash64Options *hash64_opts;
@@ -2549,6 +2541,22 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
(start + nregs > 32 && (rx >= start || rx < start + nregs - 32));
}
+/* Accessors for FP, VMX and VSX registers */
+static inline uint64_t *cpu_fpr_ptr(CPUPPCState *env, int i)
+{
+ return &env->vsr[i].u64[0];
+}
+
+static inline uint64_t *cpu_vsrl_ptr(CPUPPCState *env, int i)
+{
+ return &env->vsr[i].u64[1];
+}
+
+static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i)
+{
+ return &env->vsr[32 + i];
+}
+
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index b6f6693583..19565b584d 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -126,7 +126,7 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
gdb_get_regl(mem_buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, env->fpr[n-32]);
+ stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
} else {
switch (n) {
case 64:
@@ -178,7 +178,7 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
gdb_get_reg64(mem_buf, env->gpr[n]);
} else if (n < 64) {
/* fprs */
- stfq_p(mem_buf, env->fpr[n-32]);
+ stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
} else if (n < 96) {
/* Altivec */
stq_p(mem_buf, n - 64);
@@ -234,7 +234,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->gpr[n] = ldtul_p(mem_buf);
} else if (n < 64) {
/* fprs */
- env->fpr[n-32] = ldfq_p(mem_buf);
+ *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf);
} else {
switch (n) {
case 64:
@@ -284,7 +284,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
env->gpr[n] = ldq_p(mem_buf);
} else if (n < 64) {
/* fprs */
- env->fpr[n-32] = ldfq_p(mem_buf);
+ *cpu_fpr_ptr(env, n - 32) = ldfq_p(mem_buf);
} else {
switch (n) {
case 64 + 32:
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index fcac90a4a9..598731d47a 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -391,13 +391,9 @@ target_ulong helper_602_mfrom(target_ulong arg)
#if defined(HOST_WORDS_BIGENDIAN)
#define HI_IDX 0
#define LO_IDX 1
-#define AVRB(i) u8[i]
-#define AVRW(i) u32[i]
#else
#define HI_IDX 1
#define LO_IDX 0
-#define AVRB(i) u8[15-(i)]
-#define AVRW(i) u32[3-(i)]
#endif
#if defined(HOST_WORDS_BIGENDIAN)
@@ -548,8 +544,8 @@ VARITH_DO(muluwm, *, u32)
{ \
int i; \
\
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
+ r->f32[i] = func(a->f32[i], b->f32[i], &env->vec_status); \
} \
}
VARITHFP(addfp, float32_add)
@@ -563,9 +559,9 @@ VARITHFP(maxfp, float32_max)
ppc_avr_t *b, ppc_avr_t *c) \
{ \
int i; \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- r->f[i] = float32_muladd(a->f[i], c->f[i], b->f[i], \
- type, &env->vec_status); \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
+ r->f32[i] = float32_muladd(a->f32[i], c->f32[i], b->f32[i], \
+ type, &env->vec_status); \
} \
}
VARITHFPFMA(maddfp, 0);
@@ -670,9 +666,9 @@ VABSDU(w, u32)
{ \
int i; \
\
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
float32 t = cvt(b->element[i], &env->vec_status); \
- r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
+ r->f32[i] = float32_scalbn(t, -uim, &env->vec_status); \
} \
}
VCF(ux, uint32_to_float32, u32)
@@ -782,9 +778,9 @@ VCMPNE(w, u32, uint32_t, 0)
uint32_t none = 0; \
int i; \
\
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
uint32_t result; \
- int rel = float32_compare_quiet(a->f[i], b->f[i], \
+ int rel = float32_compare_quiet(a->f32[i], b->f32[i], \
&env->vec_status); \
if (rel == float_relation_unordered) { \
result = 0; \
@@ -816,14 +812,16 @@ static inline void vcmpbfp_internal(CPUPPCState *env, ppc_avr_t *r,
int i;
int all_in = 0;
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
+ int le_rel = float32_compare_quiet(a->f32[i], b->f32[i],
+ &env->vec_status);
if (le_rel == float_relation_unordered) {
r->u32[i] = 0xc0000000;
all_in = 1;
} else {
- float32 bneg = float32_chs(b->f[i]);
- int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
+ float32 bneg = float32_chs(b->f32[i]);
+ int ge_rel = float32_compare_quiet(a->f32[i], bneg,
+ &env->vec_status);
int le = le_rel != float_relation_greater;
int ge = ge_rel != float_relation_less;
@@ -856,11 +854,11 @@ void helper_vcmpbfp_dot(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
float_status s = env->vec_status; \
\
set_float_rounding_mode(float_round_to_zero, &s); \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- if (float32_is_any_nan(b->f[i])) { \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
+ if (float32_is_any_nan(b->f32[i])) { \
r->element[i] = 0; \
} else { \
- float64 t = float32_to_float64(b->f[i], &s); \
+ float64 t = float32_to_float64(b->f32[i], &s); \
int64_t j; \
\
t = float64_scalbn(t, uim, &s); \
@@ -1661,8 +1659,8 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
+ r->f32[i] = float32_div(float32_one, b->f32[i], &env->vec_status);
}
}
@@ -1674,8 +1672,8 @@ void helper_vrefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
float_status s = env->vec_status; \
\
set_float_rounding_mode(rounding, &s); \
- for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
- r->f[i] = float32_round_to_int (b->f[i], &s); \
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) { \
+ r->f32[i] = float32_round_to_int (b->f32[i], &s); \
} \
}
VRFI(n, float_round_nearest_even)
@@ -1705,10 +1703,10 @@ void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- float32 t = float32_sqrt(b->f[i], &env->vec_status);
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
+ float32 t = float32_sqrt(b->f32[i], &env->vec_status);
- r->f[i] = float32_div(float32_one, t, &env->vec_status);
+ r->f32[i] = float32_div(float32_one, t, &env->vec_status);
}
}
@@ -1751,8 +1749,8 @@ void helper_vexptefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- r->f[i] = float32_exp2(b->f[i], &env->vec_status);
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
+ r->f32[i] = float32_exp2(b->f32[i], &env->vec_status);
}
}
@@ -1760,8 +1758,8 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
{
int i;
- for (i = 0; i < ARRAY_SIZE(r->f); i++) {
- r->f[i] = float32_log2(b->f[i], &env->vec_status);
+ for (i = 0; i < ARRAY_SIZE(r->f32); i++) {
+ r->f32[i] = float32_log2(b->f32[i], &env->vec_status);
}
}
@@ -3275,11 +3273,11 @@ void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
int i;
VECTOR_FOR_INORDER_I(i, u32) {
- result.AVRW(i) = b->AVRW(i) ^
- (AES_Te0[a->AVRB(AES_shifts[4*i + 0])] ^
- AES_Te1[a->AVRB(AES_shifts[4*i + 1])] ^
- AES_Te2[a->AVRB(AES_shifts[4*i + 2])] ^
- AES_Te3[a->AVRB(AES_shifts[4*i + 3])]);
+ result.VsrW(i) = b->VsrW(i) ^
+ (AES_Te0[a->VsrB(AES_shifts[4 * i + 0])] ^
+ AES_Te1[a->VsrB(AES_shifts[4 * i + 1])] ^
+ AES_Te2[a->VsrB(AES_shifts[4 * i + 2])] ^
+ AES_Te3[a->VsrB(AES_shifts[4 * i + 3])]);
}
*r = result;
}
@@ -3290,7 +3288,7 @@ void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
int i;
VECTOR_FOR_INORDER_I(i, u8) {
- result.AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]);
+ result.VsrB(i) = b->VsrB(i) ^ (AES_sbox[a->VsrB(AES_shifts[i])]);
}
*r = result;
}
@@ -3303,15 +3301,15 @@ void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
ppc_avr_t tmp;
VECTOR_FOR_INORDER_I(i, u8) {
- tmp.AVRB(i) = b->AVRB(i) ^ AES_isbox[a->AVRB(AES_ishifts[i])];
+ tmp.VsrB(i) = b->VsrB(i) ^ AES_isbox[a->VsrB(AES_ishifts[i])];
}
VECTOR_FOR_INORDER_I(i, u32) {
- r->AVRW(i) =
- AES_imc[tmp.AVRB(4*i + 0)][0] ^
- AES_imc[tmp.AVRB(4*i + 1)][1] ^
- AES_imc[tmp.AVRB(4*i + 2)][2] ^
- AES_imc[tmp.AVRB(4*i + 3)][3];
+ r->VsrW(i) =
+ AES_imc[tmp.VsrB(4 * i + 0)][0] ^
+ AES_imc[tmp.VsrB(4 * i + 1)][1] ^
+ AES_imc[tmp.VsrB(4 * i + 2)][2] ^
+ AES_imc[tmp.VsrB(4 * i + 3)][3];
}
}
@@ -3321,7 +3319,7 @@ void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
int i;
VECTOR_FOR_INORDER_I(i, u8) {
- result.AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]);
+ result.VsrB(i) = b->VsrB(i) ^ (AES_isbox[a->VsrB(AES_ishifts[i])]);
}
*r = result;
}
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index a9bcadff42..c7c0f77dd6 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -52,20 +52,20 @@ FUNC_MASK(mask_u64, uint64_t, 64, UINT64_MAX);
#define EXTRACT_HELPER(name, shift, nb) \
static inline uint32_t name(uint32_t opcode) \
{ \
- return (opcode >> (shift)) & ((1 << (nb)) - 1); \
+ return extract32(opcode, shift, nb); \
}
#define EXTRACT_SHELPER(name, shift, nb) \
static inline int32_t name(uint32_t opcode) \
{ \
- return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
+ return sextract32(opcode, shift, nb); \
}
#define EXTRACT_HELPER_SPLIT(name, shift1, nb1, shift2, nb2) \
static inline uint32_t name(uint32_t opcode) \
{ \
- return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
- ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \
+ return extract32(opcode, shift1, nb1) << nb2 | \
+ extract32(opcode, shift2, nb2); \
}
#define EXTRACT_HELPER_SPLIT_3(name, \
@@ -124,7 +124,7 @@ EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */
EXTRACT_HELPER(UIMM, 0, 16);
/* 5 bits signed immediate value */
-EXTRACT_HELPER(SIMM5, 16, 5);
+EXTRACT_SHELPER(SIMM5, 16, 5);
/* 5 bits signed immediate value */
EXTRACT_HELPER(UIMM5, 16, 5);
/* 4 bits unsigned immediate value */
@@ -204,17 +204,6 @@ EXTRACT_HELPER(IMM8, 11, 8);
EXTRACT_HELPER(DCMX, 16, 7);
EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6);
-typedef union _ppc_vsr_t {
- uint8_t u8[16];
- uint16_t u16[8];
- uint32_t u32[4];
- uint64_t u64[2];
- float32 f32[4];
- float64 f64[2];
- float128 f128;
- Int128 s128;
-} ppc_vsr_t;
-
#if defined(HOST_WORDS_BIGENDIAN)
#define VsrB(i) u8[i]
#define VsrH(i) u16[i]
@@ -229,24 +218,14 @@ typedef union _ppc_vsr_t {
static inline void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
{
- if (n < 32) {
- vsr->VsrD(0) = env->fpr[n];
- vsr->VsrD(1) = env->vsr[n];
- } else {
- vsr->u64[0] = env->avr[n - 32].u64[0];
- vsr->u64[1] = env->avr[n - 32].u64[1];
- }
+ vsr->VsrD(0) = env->vsr[n].u64[0];
+ vsr->VsrD(1) = env->vsr[n].u64[1];
}
static inline void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
{
- if (n < 32) {
- env->fpr[n] = vsr->VsrD(0);
- env->vsr[n] = vsr->VsrD(1);
- } else {
- env->avr[n - 32].u64[0] = vsr->u64[0];
- env->avr[n - 32].u64[1] = vsr->u64[1];
- }
+ env->vsr[n].u64[0] = vsr->VsrD(0);
+ env->vsr[n].u64[1] = vsr->VsrD(1);
}
void helper_compute_fprf_float16(CPUPPCState *env, float16 arg);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index f81327d6cd..ebbb48c42f 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -629,13 +629,15 @@ static int kvm_put_fp(CPUState *cs)
for (i = 0; i < 32; i++) {
uint64_t vsr[2];
+ uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i);
+ uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i);
#ifdef HOST_WORDS_BIGENDIAN
- vsr[0] = float64_val(env->fpr[i]);
- vsr[1] = env->vsr[i];
+ vsr[0] = float64_val(*fpr);
+ vsr[1] = *vsrl;
#else
- vsr[0] = env->vsr[i];
- vsr[1] = float64_val(env->fpr[i]);
+ vsr[0] = *vsrl;
+ vsr[1] = float64_val(*fpr);
#endif
reg.addr = (uintptr_t) &vsr;
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
@@ -660,7 +662,7 @@ static int kvm_put_fp(CPUState *cs)
for (i = 0; i < 32; i++) {
reg.id = KVM_REG_PPC_VR(i);
- reg.addr = (uintptr_t)&env->avr[i];
+ reg.addr = (uintptr_t)cpu_avr_ptr(env, i);
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret < 0) {
DPRINTF("Unable to set VR%d to KVM: %s\n", i, strerror(errno));
@@ -696,6 +698,8 @@ static int kvm_get_fp(CPUState *cs)
for (i = 0; i < 32; i++) {
uint64_t vsr[2];
+ uint64_t *fpr = cpu_fpr_ptr(&cpu->env, i);
+ uint64_t *vsrl = cpu_vsrl_ptr(&cpu->env, i);
reg.addr = (uintptr_t) &vsr;
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
@@ -707,14 +711,14 @@ static int kvm_get_fp(CPUState *cs)
return ret;
} else {
#ifdef HOST_WORDS_BIGENDIAN
- env->fpr[i] = vsr[0];
+ *fpr = vsr[0];
if (vsx) {
- env->vsr[i] = vsr[1];
+ *vsrl = vsr[1];
}
#else
- env->fpr[i] = vsr[1];
+ *fpr = vsr[1];
if (vsx) {
- env->vsr[i] = vsr[0];
+ *vsrl = vsr[0];
}
#endif
}
@@ -732,7 +736,7 @@ static int kvm_get_fp(CPUState *cs)
for (i = 0; i < 32; i++) {
reg.id = KVM_REG_PPC_VR(i);
- reg.addr = (uintptr_t)&env->avr[i];
+ reg.addr = (uintptr_t)cpu_avr_ptr(env, i);
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret < 0) {
DPRINTF("Unable to get VR%d from KVM: %s\n",
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index e7b3725273..eff30053b0 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -45,7 +45,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
uint64_t l;
} u;
u.l = qemu_get_be64(f);
- env->fpr[i] = u.d;
+ *cpu_fpr_ptr(env, i) = u.d;
}
qemu_get_be32s(f, &fpscr);
env->fpscr = fpscr;
@@ -138,11 +138,73 @@ static const VMStateInfo vmstate_info_avr = {
};
#define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \
- VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_avr, ppc_avr_t)
+ VMSTATE_SUB_ARRAY(_f, _s, 32, _n, _v, vmstate_info_avr, ppc_avr_t)
#define VMSTATE_AVR_ARRAY(_f, _s, _n) \
VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0)
+static int get_fpr(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field)
+{
+ ppc_vsr_t *v = pv;
+
+ v->u64[0] = qemu_get_be64(f);
+
+ return 0;
+}
+
+static int put_fpr(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field, QJSON *vmdesc)
+{
+ ppc_vsr_t *v = pv;
+
+ qemu_put_be64(f, v->u64[0]);
+ return 0;
+}
+
+static const VMStateInfo vmstate_info_fpr = {
+ .name = "fpr",
+ .get = get_fpr,
+ .put = put_fpr,
+};
+
+#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_fpr, ppc_vsr_t)
+
+#define VMSTATE_FPR_ARRAY(_f, _s, _n) \
+ VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0)
+
+static int get_vsr(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field)
+{
+ ppc_vsr_t *v = pv;
+
+ v->u64[1] = qemu_get_be64(f);
+
+ return 0;
+}
+
+static int put_vsr(QEMUFile *f, void *pv, size_t size,
+ const VMStateField *field, QJSON *vmdesc)
+{
+ ppc_vsr_t *v = pv;
+
+ qemu_put_be64(f, v->u64[1]);
+ return 0;
+}
+
+static const VMStateInfo vmstate_info_vsr = {
+ .name = "vsr",
+ .get = get_vsr,
+ .put = put_vsr,
+};
+
+#define VMSTATE_VSR_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_SUB_ARRAY(_f, _s, 0, _n, _v, vmstate_info_vsr, ppc_vsr_t)
+
+#define VMSTATE_VSR_ARRAY(_f, _s, _n) \
+ VMSTATE_VSR_ARRAY_V(_f, _s, _n, 0)
+
static bool cpu_pre_2_8_migration(void *opaque, int version_id)
{
PowerPCCPU *cpu = opaque;
@@ -354,7 +416,7 @@ static const VMStateDescription vmstate_fpu = {
.minimum_version_id = 1,
.needed = fpu_needed,
.fields = (VMStateField[]) {
- VMSTATE_FLOAT64_ARRAY(env.fpr, PowerPCCPU, 32),
+ VMSTATE_FPR_ARRAY(env.vsr, PowerPCCPU, 32),
VMSTATE_UINTTL(env.fpscr, PowerPCCPU),
VMSTATE_END_OF_LIST()
},
@@ -373,7 +435,7 @@ static const VMStateDescription vmstate_altivec = {
.minimum_version_id = 1,
.needed = altivec_needed,
.fields = (VMStateField[]) {
- VMSTATE_AVR_ARRAY(env.avr, PowerPCCPU, 32),
+ VMSTATE_AVR_ARRAY(env.vsr, PowerPCCPU, 32),
VMSTATE_UINT32(env.vscr, PowerPCCPU),
VMSTATE_END_OF_LIST()
},
@@ -392,7 +454,7 @@ static const VMStateDescription vmstate_vsx = {
.minimum_version_id = 1,
.needed = vsx_needed,
.fields = (VMStateField[]) {
- VMSTATE_UINT64_ARRAY(env.vsr, PowerPCCPU, 32),
+ VMSTATE_VSR_ARRAY(env.vsr, PowerPCCPU, 32),
VMSTATE_END_OF_LIST()
},
};
diff --git a/target/ppc/monitor.c b/target/ppc/monitor.c
index 14915119fc..04deec8030 100644
--- a/target/ppc/monitor.c
+++ b/target/ppc/monitor.c
@@ -123,8 +123,8 @@ int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval)
/* Floating point registers */
if ((qemu_tolower(name[0]) == 'f') &&
- ppc_cpu_get_reg_num(name + 1, ARRAY_SIZE(env->fpr), &regnum)) {
- *pval = env->fpr[regnum];
+ ppc_cpu_get_reg_num(name + 1, 32, &regnum)) {
+ *pval = *cpu_fpr_ptr(env, regnum);
return 0;
}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 2b37910248..e169c43643 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -55,15 +55,9 @@
/* global register indexes */
static char cpu_reg_names[10*3 + 22*4 /* GPR */
+ 10*4 + 22*5 /* SPE GPRh */
- + 10*4 + 22*5 /* FPR */
- + 2*(10*6 + 22*7) /* AVRh, AVRl */
- + 10*5 + 22*6 /* VSR */
+ 8*5 /* CRF */];
static TCGv cpu_gpr[32];
static TCGv cpu_gprh[32];
-static TCGv_i64 cpu_fpr[32];
-static TCGv_i64 cpu_avrh[32], cpu_avrl[32];
-static TCGv_i64 cpu_vsr[32];
static TCGv_i32 cpu_crf[8];
static TCGv cpu_nip;
static TCGv cpu_msr;
@@ -108,39 +102,6 @@ void ppc_translate_init(void)
offsetof(CPUPPCState, gprh[i]), p);
p += (i < 10) ? 4 : 5;
cpu_reg_names_size -= (i < 10) ? 4 : 5;
-
- snprintf(p, cpu_reg_names_size, "fp%d", i);
- cpu_fpr[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, fpr[i]), p);
- p += (i < 10) ? 4 : 5;
- cpu_reg_names_size -= (i < 10) ? 4 : 5;
-
- snprintf(p, cpu_reg_names_size, "avr%dH", i);
-#ifdef HOST_WORDS_BIGENDIAN
- cpu_avrh[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, avr[i].u64[0]), p);
-#else
- cpu_avrh[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, avr[i].u64[1]), p);
-#endif
- p += (i < 10) ? 6 : 7;
- cpu_reg_names_size -= (i < 10) ? 6 : 7;
-
- snprintf(p, cpu_reg_names_size, "avr%dL", i);
-#ifdef HOST_WORDS_BIGENDIAN
- cpu_avrl[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, avr[i].u64[1]), p);
-#else
- cpu_avrl[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, avr[i].u64[0]), p);
-#endif
- p += (i < 10) ? 6 : 7;
- cpu_reg_names_size -= (i < 10) ? 6 : 7;
- snprintf(p, cpu_reg_names_size, "vsr%d", i);
- cpu_vsr[i] = tcg_global_mem_new_i64(cpu_env,
- offsetof(CPUPPCState, vsr[i]), p);
- p += (i < 10) ? 5 : 6;
- cpu_reg_names_size -= (i < 10) ? 5 : 6;
}
cpu_nip = tcg_global_mem_new(cpu_env,
@@ -849,7 +810,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
TCGv res, TCGv arg0, TCGv arg1,
- int sub)
+ TCGv ca32, int sub)
{
TCGv t0;
@@ -864,13 +825,14 @@ static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
tcg_gen_xor_tl(t0, arg0, arg1);
}
tcg_gen_xor_tl(t0, t0, res);
- tcg_gen_extract_tl(cpu_ca32, t0, 32, 1);
+ tcg_gen_extract_tl(ca32, t0, 32, 1);
tcg_temp_free(t0);
}
/* Common add function */
static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
- TCGv arg2, bool add_ca, bool compute_ca,
+ TCGv arg2, TCGv ca, TCGv ca32,
+ bool add_ca, bool compute_ca,
bool compute_ov, bool compute_rc0)
{
TCGv t0 = ret;
@@ -888,29 +850,29 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
tcg_gen_xor_tl(t1, arg1, arg2); /* add without carry */
tcg_gen_add_tl(t0, arg1, arg2);
if (add_ca) {
- tcg_gen_add_tl(t0, t0, cpu_ca);
+ tcg_gen_add_tl(t0, t0, ca);
}
- tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changed w/ carry */
+ tcg_gen_xor_tl(ca, t0, t1); /* bits changed w/ carry */
tcg_temp_free(t1);
- tcg_gen_extract_tl(cpu_ca, cpu_ca, 32, 1);
+ tcg_gen_extract_tl(ca, ca, 32, 1);
if (is_isa300(ctx)) {
- tcg_gen_mov_tl(cpu_ca32, cpu_ca);
+ tcg_gen_mov_tl(ca32, ca);
}
} else {
TCGv zero = tcg_const_tl(0);
if (add_ca) {
- tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, cpu_ca, zero);
- tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, arg2, zero);
+ tcg_gen_add2_tl(t0, ca, arg1, zero, ca, zero);
+ tcg_gen_add2_tl(t0, ca, t0, ca, arg2, zero);
} else {
- tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
+ tcg_gen_add2_tl(t0, ca, arg1, zero, arg2, zero);
}
- gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 0);
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, ca32, 0);
tcg_temp_free(zero);
}
} else {
tcg_gen_add_tl(t0, arg1, arg2);
if (add_ca) {
- tcg_gen_add_tl(t0, t0, cpu_ca);
+ tcg_gen_add_tl(t0, t0, ca);
}
}
@@ -927,40 +889,44 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
}
}
/* Add functions with two operands */
-#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov) \
+#define GEN_INT_ARITH_ADD(name, opc3, ca, add_ca, compute_ca, compute_ov) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
+ ca, glue(ca, 32), \
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
}
/* Add functions with one operand and one immediate */
-#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, \
+#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val, ca, \
add_ca, compute_ca, compute_ov) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
TCGv t0 = tcg_const_tl(const_val); \
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], \
cpu_gpr[rA(ctx->opcode)], t0, \
+ ca, glue(ca, 32), \
add_ca, compute_ca, compute_ov, Rc(ctx->opcode)); \
tcg_temp_free(t0); \
}
/* add add. addo addo. */
-GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
-GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
+GEN_INT_ARITH_ADD(add, 0x08, cpu_ca, 0, 0, 0)
+GEN_INT_ARITH_ADD(addo, 0x18, cpu_ca, 0, 0, 1)
/* addc addc. addco addco. */
-GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
-GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
+GEN_INT_ARITH_ADD(addc, 0x00, cpu_ca, 0, 1, 0)
+GEN_INT_ARITH_ADD(addco, 0x10, cpu_ca, 0, 1, 1)
/* adde adde. addeo addeo. */
-GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
-GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
+GEN_INT_ARITH_ADD(adde, 0x04, cpu_ca, 1, 1, 0)
+GEN_INT_ARITH_ADD(addeo, 0x14, cpu_ca, 1, 1, 1)
/* addme addme. addmeo addmeo. */
-GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
-GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
+GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, cpu_ca, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, cpu_ca, 1, 1, 1)
+/* addex */
+GEN_INT_ARITH_ADD(addex, 0x05, cpu_ov, 1, 1, 0);
/* addze addze. addzeo addzeo.*/
-GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
-GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
+GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, cpu_ca, 1, 1, 0)
+GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, cpu_ca, 1, 1, 1)
/* addi */
static void gen_addi(DisasContext *ctx)
{
@@ -979,7 +945,7 @@ static inline void gen_op_addic(DisasContext *ctx, bool compute_rc0)
{
TCGv c = tcg_const_tl(SIMM(ctx->opcode));
gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
- c, 0, 1, 0, compute_rc0);
+ c, cpu_ca, cpu_ca32, 0, 1, 0, compute_rc0);
tcg_temp_free(c);
}
@@ -1432,13 +1398,13 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
zero = tcg_const_tl(0);
tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
- gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, 0);
+ gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, cpu_ca32, 0);
tcg_temp_free(zero);
tcg_temp_free(inv1);
} else {
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
tcg_gen_sub_tl(t0, arg2, arg1);
- gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 1);
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, cpu_ca32, 1);
}
} else if (add_ca) {
/* Since we're ignoring carry-out, we can simplify the
@@ -6694,6 +6660,38 @@ static inline void gen_##name(DisasContext *ctx) \
GEN_TM_PRIV_NOOP(treclaim);
GEN_TM_PRIV_NOOP(trechkpt);
+static inline void get_fpr(TCGv_i64 dst, int regno)
+{
+ tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0]));
+}
+
+static inline void set_fpr(int regno, TCGv_i64 src)
+{
+ tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[regno].u64[0]));
+}
+
+static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState,
+ vsr[32 + regno].u64[(high ? 0 : 1)]));
+#else
+ tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState,
+ vsr[32 + regno].u64[(high ? 1 : 0)]));
+#endif
+}
+
+static inline void set_avr64(int regno, TCGv_i64 src, bool high)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState,
+ vsr[32 + regno].u64[(high ? 0 : 1)]));
+#else
+ tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState,
+ vsr[32 + regno].u64[(high ? 1 : 0)]));
+#endif
+}
+
#include "translate/fp-impl.inc.c"
#include "translate/vmx-impl.inc.c"
@@ -7087,6 +7085,7 @@ GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
+GEN_HANDLER_E(addex, 0x1F, 0x0A, 0x05, 0x00000000, PPC_NONE, PPC2_ISA300),
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
@@ -7441,7 +7440,7 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
if ((i & (RFPL - 1)) == 0) {
cpu_fprintf(f, "FPR%02d", i);
}
- cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
+ cpu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i));
if ((i & (RFPL - 1)) == (RFPL - 1)) {
cpu_fprintf(f, "\n");
}
diff --git a/target/ppc/translate/dfp-impl.inc.c b/target/ppc/translate/dfp-impl.inc.c
index 634ef73b8a..6c556dc2e1 100644
--- a/target/ppc/translate/dfp-impl.inc.c
+++ b/target/ppc/translate/dfp-impl.inc.c
@@ -3,7 +3,7 @@
static inline TCGv_ptr gen_fprp_ptr(int reg)
{
TCGv_ptr r = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, fpr[reg]));
+ tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[reg].u64[0]));
return r;
}
diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c
index 08770ba9f5..0f21a4e477 100644
--- a/target/ppc/translate/fp-impl.inc.c
+++ b/target/ppc/translate/fp-impl.inc.c
@@ -34,24 +34,37 @@ static void gen_set_cr1_from_fpscr(DisasContext *ctx)
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 t2; \
+ TCGv_i64 t3; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ t2 = tcg_temp_new_i64(); \
+ t3 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rA(ctx->opcode)], \
- cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); \
+ get_fpr(t0, rA(ctx->opcode)); \
+ get_fpr(t1, rC(ctx->opcode)); \
+ get_fpr(t2, rB(ctx->opcode)); \
+ gen_helper_f##op(t3, cpu_env, t0, t1, t2); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(t3, cpu_env, t3); \
} \
+ set_fpr(rD(ctx->opcode), t3); \
if (set_fprf) { \
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(t3); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
+ tcg_temp_free_i64(t2); \
+ tcg_temp_free_i64(t3); \
}
#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \
@@ -61,24 +74,33 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 t2; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ t2 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rA(ctx->opcode)], \
- cpu_fpr[rB(ctx->opcode)]); \
+ get_fpr(t0, rA(ctx->opcode)); \
+ get_fpr(t1, rB(ctx->opcode)); \
+ gen_helper_f##op(t2, cpu_env, t0, t1); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(t2, cpu_env, t2); \
} \
+ set_fpr(rD(ctx->opcode), t2); \
if (set_fprf) { \
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(t2); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
+ tcg_temp_free_i64(t2); \
}
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
@@ -87,24 +109,33 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 t2; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ t2 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
- gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rA(ctx->opcode)], \
- cpu_fpr[rC(ctx->opcode)]); \
+ get_fpr(t0, rA(ctx->opcode)); \
+ get_fpr(t1, rC(ctx->opcode)); \
+ gen_helper_f##op(t2, cpu_env, t0, t1); \
if (isfloat) { \
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rD(ctx->opcode)]); \
+ gen_helper_frsp(t2, cpu_env, t2); \
} \
+ set_fpr(rD(ctx->opcode), t2); \
if (set_fprf) { \
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(t2); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
+ tcg_temp_free_i64(t2); \
}
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
@@ -113,37 +144,51 @@ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
- gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rB(ctx->opcode)]); \
+ get_fpr(t0, rB(ctx->opcode)); \
+ gen_helper_f##name(t1, cpu_env, t0); \
+ set_fpr(rD(ctx->opcode), t1); \
if (set_fprf) { \
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(t1); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
}
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
gen_reset_fpstatus(); \
- gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
- cpu_fpr[rB(ctx->opcode)]); \
+ get_fpr(t0, rB(ctx->opcode)); \
+ gen_helper_f##name(t1, cpu_env, t0); \
+ set_fpr(rD(ctx->opcode), t1); \
if (set_fprf) { \
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(t1); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
}
/* fadd - fadds */
@@ -165,19 +210,25 @@ GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
/* frsqrtes */
static void gen_frsqrtes(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_reset_fpstatus();
- gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_env,
- cpu_fpr[rB(ctx->opcode)]);
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
- cpu_fpr[rD(ctx->opcode)]);
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
+ get_fpr(t0, rB(ctx->opcode));
+ gen_helper_frsqrte(t1, cpu_env, t0);
+ gen_helper_frsp(t1, cpu_env, t1);
+ set_fpr(rD(ctx->opcode), t1);
+ gen_compute_fprf_float64(t1);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/* fsel */
@@ -189,34 +240,47 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
/* fsqrt */
static void gen_fsqrt(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_reset_fpstatus();
- gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
- cpu_fpr[rB(ctx->opcode)]);
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
+ get_fpr(t0, rB(ctx->opcode));
+ gen_helper_fsqrt(t1, cpu_env, t0);
+ set_fpr(rD(ctx->opcode), t1);
+ gen_compute_fprf_float64(t1);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
static void gen_fsqrts(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_reset_fpstatus();
- gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
- cpu_fpr[rB(ctx->opcode)]);
- gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
- cpu_fpr[rD(ctx->opcode)]);
- gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
+ get_fpr(t0, rB(ctx->opcode));
+ gen_helper_fsqrt(t1, cpu_env, t0);
+ gen_helper_frsp(t1, cpu_env, t1);
+ set_fpr(rD(ctx->opcode), t1);
+ gen_compute_fprf_float64(t1);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/*** Floating-Point multiply-and-add ***/
@@ -268,21 +332,32 @@ GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
static void gen_ftdiv(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
- cpu_fpr[rB(ctx->opcode)]);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t0, rA(ctx->opcode));
+ get_fpr(t1, rB(ctx->opcode));
+ gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
static void gen_ftsqrt(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+ t0 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0);
+ tcg_temp_free_i64(t0);
}
@@ -293,32 +368,46 @@ static void gen_ftsqrt(DisasContext *ctx)
static void gen_fcmpo(DisasContext *ctx)
{
TCGv_i32 crf;
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
- gen_helper_fcmpo(cpu_env, cpu_fpr[rA(ctx->opcode)],
- cpu_fpr[rB(ctx->opcode)], crf);
+ get_fpr(t0, rA(ctx->opcode));
+ get_fpr(t1, rB(ctx->opcode));
+ gen_helper_fcmpo(cpu_env, t0, t1, crf);
tcg_temp_free_i32(crf);
gen_helper_float_check_status(cpu_env);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/* fcmpu */
static void gen_fcmpu(DisasContext *ctx)
{
TCGv_i32 crf;
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_reset_fpstatus();
crf = tcg_const_i32(crfD(ctx->opcode));
- gen_helper_fcmpu(cpu_env, cpu_fpr[rA(ctx->opcode)],
- cpu_fpr[rB(ctx->opcode)], crf);
+ get_fpr(t0, rA(ctx->opcode));
+ get_fpr(t1, rB(ctx->opcode));
+ gen_helper_fcmpu(cpu_env, t0, t1, crf);
tcg_temp_free_i32(crf);
gen_helper_float_check_status(cpu_env);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/*** Floating-point move ***/
@@ -326,100 +415,153 @@ static void gen_fcmpu(DisasContext *ctx)
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
static void gen_fabs(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
- ~(1ULL << 63));
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ tcg_gen_andi_i64(t1, t0, ~(1ULL << 63));
+ set_fpr(rD(ctx->opcode), t1);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/* fmr - fmr. */
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
static void gen_fmr(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+ t0 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ set_fpr(rD(ctx->opcode), t0);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
}
/* fnabs */
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
static void gen_fnabs(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
- 1ULL << 63);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ tcg_gen_ori_i64(t1, t0, 1ULL << 63);
+ set_fpr(rD(ctx->opcode), t1);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/* fneg */
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
static void gen_fneg(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
- 1ULL << 63);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ tcg_gen_xori_i64(t1, t0, 1ULL << 63);
+ set_fpr(rD(ctx->opcode), t1);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
/* fcpsgn: PowerPC 2.05 specification */
/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
static void gen_fcpsgn(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
+ TCGv_i64 t2;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
- cpu_fpr[rB(ctx->opcode)], 0, 63);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ get_fpr(t0, rA(ctx->opcode));
+ get_fpr(t1, rB(ctx->opcode));
+ tcg_gen_deposit_i64(t2, t0, t1, 0, 63);
+ set_fpr(rD(ctx->opcode), t2);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
}
static void gen_fmrgew(DisasContext *ctx)
{
TCGv_i64 b0;
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
b0 = tcg_temp_new_i64();
- tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32);
- tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
- b0, 0, 32);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ tcg_gen_shri_i64(b0, t0, 32);
+ get_fpr(t0, rA(ctx->opcode));
+ tcg_gen_deposit_i64(t1, t0, b0, 0, 32);
+ set_fpr(rD(ctx->opcode), t1);
tcg_temp_free_i64(b0);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
static void gen_fmrgow(DisasContext *ctx)
{
+ TCGv_i64 t0;
+ TCGv_i64 t1;
+ TCGv_i64 t2;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)],
- cpu_fpr[rB(ctx->opcode)],
- cpu_fpr[rA(ctx->opcode)],
- 32, 32);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ get_fpr(t0, rB(ctx->opcode));
+ get_fpr(t1, rA(ctx->opcode));
+ tcg_gen_deposit_i64(t2, t0, t1, 32, 32);
+ set_fpr(rD(ctx->opcode), t2);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
}
/*** Floating-Point status & ctrl register ***/
@@ -458,15 +600,19 @@ static void gen_mcrfs(DisasContext *ctx)
/* mffs */
static void gen_mffs(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ t0 = tcg_temp_new_i64();
gen_reset_fpstatus();
- tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
+ tcg_gen_extu_tl_i64(t0, cpu_fpscr);
+ set_fpr(rD(ctx->opcode), t0);
if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
+ tcg_temp_free_i64(t0);
}
/* mtfsb0 */
@@ -522,6 +668,7 @@ static void gen_mtfsb1(DisasContext *ctx)
static void gen_mtfsf(DisasContext *ctx)
{
TCGv_i32 t0;
+ TCGv_i64 t1;
int flm, l, w;
if (unlikely(!ctx->fpu_enabled)) {
@@ -541,7 +688,9 @@ static void gen_mtfsf(DisasContext *ctx)
} else {
t0 = tcg_const_i32(flm << (w * 8));
}
- gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
+ t1 = tcg_temp_new_i64();
+ get_fpr(t1, rB(ctx->opcode));
+ gen_helper_store_fpscr(cpu_env, t1, t0);
tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) {
tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
@@ -549,6 +698,7 @@ static void gen_mtfsf(DisasContext *ctx)
}
/* We can raise a differed exception */
gen_helper_float_check_status(cpu_env);
+ tcg_temp_free_i64(t1);
}
/* mtfsfi */
@@ -588,21 +738,26 @@ static void gen_mtfsfi(DisasContext *ctx)
static void glue(gen_, name)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_imm_index(ctx, EA, 0); \
- gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \
+ gen_qemu_##ldop(ctx, t0, EA); \
+ set_fpr(rD(ctx->opcode), t0); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_LDUF(name, ldop, opc, type) \
static void glue(gen_, name##u)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
@@ -613,20 +768,25 @@ static void glue(gen_, name##u)(DisasContext *ctx)
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_imm_index(ctx, EA, 0); \
- gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \
+ gen_qemu_##ldop(ctx, t0, EA); \
+ set_fpr(rD(ctx->opcode), t0); \
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_LDUXF(name, ldop, opc, type) \
static void glue(gen_, name##ux)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
if (unlikely(rA(ctx->opcode) == 0)) { \
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \
return; \
@@ -634,24 +794,30 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \
+ gen_qemu_##ldop(ctx, t0, EA); \
+ set_fpr(rD(ctx->opcode), t0); \
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_LDXF(name, ldop, opc2, opc3, type) \
static void glue(gen_, name##x)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA); \
+ gen_qemu_##ldop(ctx, t0, EA); \
+ set_fpr(rD(ctx->opcode), t0); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_LDFS(name, ldop, op, type) \
@@ -677,6 +843,7 @@ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
static void gen_lfdepx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
CHK_SV;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
@@ -684,16 +851,19 @@ static void gen_lfdepx(DisasContext *ctx)
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
+ t0 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_ld_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD,
- DEF_MEMOP(MO_Q));
+ tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_Q));
+ set_fpr(rD(ctx->opcode), t0);
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* lfdp */
static void gen_lfdp(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
@@ -701,24 +871,31 @@ static void gen_lfdp(DisasContext *ctx)
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_imm_index(ctx, EA, 0);
+ t0 = tcg_temp_new_i64();
/* We only need to swap high and low halves. gen_qemu_ld64_i64 does
necessary 64-bit byteswap already. */
if (unlikely(ctx->le_mode)) {
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode) + 1, t0);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode), t0);
} else {
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode), t0);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode) + 1, t0);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* lfdpx */
static void gen_lfdpx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
@@ -726,18 +903,24 @@ static void gen_lfdpx(DisasContext *ctx)
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
+ t0 = tcg_temp_new_i64();
/* We only need to swap high and low halves. gen_qemu_ld64_i64 does
necessary 64-bit byteswap already. */
if (unlikely(ctx->le_mode)) {
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode) + 1, t0);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode), t0);
} else {
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode), t0);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode) + 1, t0);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* lfiwax */
@@ -745,6 +928,7 @@ static void gen_lfiwax(DisasContext *ctx)
{
TCGv EA;
TCGv t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
@@ -752,47 +936,59 @@ static void gen_lfiwax(DisasContext *ctx)
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
t0 = tcg_temp_new();
+ t1 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, EA);
gen_qemu_ld32s(ctx, t0, EA);
- tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0);
+ tcg_gen_ext_tl_i64(t1, t0);
+ set_fpr(rD(ctx->opcode), t1);
tcg_temp_free(EA);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t1);
}
/* lfiwzx */
static void gen_lfiwzx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
+ t0 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, EA);
- gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ gen_qemu_ld32u_i64(ctx, t0, EA);
+ set_fpr(rD(ctx->opcode), t0);
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/*** Floating-point store ***/
#define GEN_STF(name, stop, opc, type) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_imm_index(ctx, EA, 0); \
- gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \
+ get_fpr(t0, rS(ctx->opcode)); \
+ gen_qemu_##stop(ctx, t0, EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_STUF(name, stop, opc, type) \
static void glue(gen_, name##u)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
@@ -803,16 +999,20 @@ static void glue(gen_, name##u)(DisasContext *ctx)
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_imm_index(ctx, EA, 0); \
- gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \
+ get_fpr(t0, rS(ctx->opcode)); \
+ gen_qemu_##stop(ctx, t0, EA); \
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_STUXF(name, stop, opc, type) \
static void glue(gen_, name##ux)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
@@ -823,25 +1023,32 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \
+ get_fpr(t0, rS(ctx->opcode)); \
+ gen_qemu_##stop(ctx, t0, EA); \
tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_STXF(name, stop, opc2, opc3, type) \
static void glue(gen_, name##x)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->fpu_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_FPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_FLOAT); \
EA = tcg_temp_new(); \
+ t0 = tcg_temp_new_i64(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA); \
+ get_fpr(t0, rS(ctx->opcode)); \
+ gen_qemu_##stop(ctx, t0, EA); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
#define GEN_STFS(name, stop, op, type) \
@@ -867,6 +1074,7 @@ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
static void gen_stfdepx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
CHK_SV;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
@@ -874,60 +1082,76 @@ static void gen_stfdepx(DisasContext *ctx)
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
+ t0 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_st_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE,
- DEF_MEMOP(MO_Q));
+ get_fpr(t0, rD(ctx->opcode));
+ tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_Q));
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* stfdp */
static void gen_stfdp(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
+ t0 = tcg_temp_new_i64();
gen_addr_imm_index(ctx, EA, 0);
/* We only need to swap high and low halves. gen_qemu_st64_i64 does
necessary 64-bit byteswap already. */
if (unlikely(ctx->le_mode)) {
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ get_fpr(t0, rD(ctx->opcode) + 1);
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ get_fpr(t0, rD(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
} else {
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ get_fpr(t0, rD(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ get_fpr(t0, rD(ctx->opcode) + 1);
+ gen_qemu_st64_i64(ctx, t0, EA);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* stfdpx */
static void gen_stfdpx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
+ t0 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, EA);
/* We only need to swap high and low halves. gen_qemu_st64_i64 does
necessary 64-bit byteswap already. */
if (unlikely(ctx->le_mode)) {
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ get_fpr(t0, rD(ctx->opcode) + 1);
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ get_fpr(t0, rD(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
} else {
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ get_fpr(t0, rD(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ get_fpr(t0, rD(ctx->opcode) + 1);
+ gen_qemu_st64_i64(ctx, t0, EA);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
/* Optional: */
@@ -949,13 +1173,18 @@ static void gen_lfq(DisasContext *ctx)
{
int rd = rD(ctx->opcode);
TCGv t0;
+ TCGv_i64 t1;
gen_set_access_type(ctx, ACCESS_FLOAT);
t0 = tcg_temp_new();
+ t1 = tcg_temp_new_i64();
gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0);
+ gen_qemu_ld64_i64(ctx, t1, t0);
+ set_fpr(rd, t1);
gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+ gen_qemu_ld64_i64(ctx, t1, t0);
+ set_fpr((rd + 1) % 32, t1);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t1);
}
/* lfqu */
@@ -964,17 +1193,22 @@ static void gen_lfqu(DisasContext *ctx)
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
TCGv t0, t1;
+ TCGv_i64 t2;
gen_set_access_type(ctx, ACCESS_FLOAT);
t0 = tcg_temp_new();
t1 = tcg_temp_new();
+ t2 = tcg_temp_new_i64();
gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0);
+ gen_qemu_ld64_i64(ctx, t2, t0);
+ set_fpr(rd, t2);
gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+ gen_qemu_ld64_i64(ctx, t2, t1);
+ set_fpr((rd + 1) % 32, t2);
if (ra != 0)
tcg_gen_mov_tl(cpu_gpr[ra], t0);
tcg_temp_free(t0);
tcg_temp_free(t1);
+ tcg_temp_free_i64(t2);
}
/* lfqux */
@@ -984,16 +1218,21 @@ static void gen_lfqux(DisasContext *ctx)
int rd = rD(ctx->opcode);
gen_set_access_type(ctx, ACCESS_FLOAT);
TCGv t0, t1;
+ TCGv_i64 t2;
+ t2 = tcg_temp_new_i64();
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0);
+ gen_qemu_ld64_i64(ctx, t2, t0);
+ set_fpr(rd, t2);
t1 = tcg_temp_new();
gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+ gen_qemu_ld64_i64(ctx, t2, t1);
+ set_fpr((rd + 1) % 32, t2);
tcg_temp_free(t1);
if (ra != 0)
tcg_gen_mov_tl(cpu_gpr[ra], t0);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t2);
}
/* lfqx */
@@ -1001,13 +1240,18 @@ static void gen_lfqx(DisasContext *ctx)
{
int rd = rD(ctx->opcode);
TCGv t0;
+ TCGv_i64 t1;
gen_set_access_type(ctx, ACCESS_FLOAT);
t0 = tcg_temp_new();
+ t1 = tcg_temp_new_i64();
gen_addr_reg_index(ctx, t0);
- gen_qemu_ld64_i64(ctx, cpu_fpr[rd], t0);
+ gen_qemu_ld64_i64(ctx, t1, t0);
+ set_fpr(rd, t1);
gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_ld64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+ gen_qemu_ld64_i64(ctx, t1, t0);
+ set_fpr((rd + 1) % 32, t1);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t1);
}
/* stfq */
@@ -1015,13 +1259,18 @@ static void gen_stfq(DisasContext *ctx)
{
int rd = rD(ctx->opcode);
TCGv t0;
+ TCGv_i64 t1;
gen_set_access_type(ctx, ACCESS_FLOAT);
t0 = tcg_temp_new();
+ t1 = tcg_temp_new_i64();
gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0);
+ get_fpr(t1, rd);
+ gen_qemu_st64_i64(ctx, t1, t0);
gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+ get_fpr(t1, (rd + 1) % 32);
+ gen_qemu_st64_i64(ctx, t1, t0);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t1);
}
/* stfqu */
@@ -1030,17 +1279,23 @@ static void gen_stfqu(DisasContext *ctx)
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
TCGv t0, t1;
+ TCGv_i64 t2;
gen_set_access_type(ctx, ACCESS_FLOAT);
+ t2 = tcg_temp_new_i64();
t0 = tcg_temp_new();
gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0);
+ get_fpr(t2, rd);
+ gen_qemu_st64_i64(ctx, t2, t0);
t1 = tcg_temp_new();
gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+ get_fpr(t2, (rd + 1) % 32);
+ gen_qemu_st64_i64(ctx, t2, t1);
tcg_temp_free(t1);
- if (ra != 0)
+ if (ra != 0) {
tcg_gen_mov_tl(cpu_gpr[ra], t0);
+ }
tcg_temp_free(t0);
+ tcg_temp_free_i64(t2);
}
/* stfqux */
@@ -1049,17 +1304,23 @@ static void gen_stfqux(DisasContext *ctx)
int ra = rA(ctx->opcode);
int rd = rD(ctx->opcode);
TCGv t0, t1;
+ TCGv_i64 t2;
gen_set_access_type(ctx, ACCESS_FLOAT);
+ t2 = tcg_temp_new_i64();
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0);
+ get_fpr(t2, rd);
+ gen_qemu_st64_i64(ctx, t2, t0);
t1 = tcg_temp_new();
gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t1);
+ get_fpr(t2, (rd + 1) % 32);
+ gen_qemu_st64_i64(ctx, t2, t1);
tcg_temp_free(t1);
- if (ra != 0)
+ if (ra != 0) {
tcg_gen_mov_tl(cpu_gpr[ra], t0);
+ }
tcg_temp_free(t0);
+ tcg_temp_free_i64(t2);
}
/* stfqx */
@@ -1067,13 +1328,18 @@ static void gen_stfqx(DisasContext *ctx)
{
int rd = rD(ctx->opcode);
TCGv t0;
+ TCGv_i64 t1;
gen_set_access_type(ctx, ACCESS_FLOAT);
+ t1 = tcg_temp_new_i64();
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
- gen_qemu_st64_i64(ctx, cpu_fpr[rd], t0);
+ get_fpr(t1, rd);
+ gen_qemu_st64_i64(ctx, t1, t0);
gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_st64_i64(ctx, cpu_fpr[(rd + 1) % 32], t0);
+ get_fpr(t1, (rd + 1) % 32);
+ gen_qemu_st64_i64(ctx, t1, t0);
tcg_temp_free(t0);
+ tcg_temp_free_i64(t1);
}
#undef _GEN_FLOAT_ACB
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index 3cb6fc2926..f99d0284c2 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -10,60 +10,79 @@
static inline TCGv_ptr gen_avr_ptr(int reg)
{
TCGv_ptr r = tcg_temp_new_ptr();
- tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
+ tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[32 + reg].u64[0]));
return r;
}
+static inline long avr64_offset(int reg, bool high)
+{
+ return offsetof(CPUPPCState, vsr[32 + reg].u64[(high ? 0 : 1)]);
+}
+
#define GEN_VR_LDX(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 avr; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_INT); \
+ avr = tcg_temp_new_i64(); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_gen_andi_tl(EA, EA, ~0xf); \
/* We only need to swap high and low halves. gen_qemu_ld64_i64 does \
necessary 64-bit byteswap already. */ \
if (ctx->le_mode) { \
- gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \
+ gen_qemu_ld64_i64(ctx, avr, EA); \
+ set_avr64(rD(ctx->opcode), avr, false); \
tcg_gen_addi_tl(EA, EA, 8); \
- gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \
+ gen_qemu_ld64_i64(ctx, avr, EA); \
+ set_avr64(rD(ctx->opcode), avr, true); \
} else { \
- gen_qemu_ld64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \
+ gen_qemu_ld64_i64(ctx, avr, EA); \
+ set_avr64(rD(ctx->opcode), avr, true); \
tcg_gen_addi_tl(EA, EA, 8); \
- gen_qemu_ld64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \
+ gen_qemu_ld64_i64(ctx, avr, EA); \
+ set_avr64(rD(ctx->opcode), avr, false); \
} \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(avr); \
}
#define GEN_VR_STX(name, opc2, opc3) \
static void gen_st##name(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 avr; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
gen_set_access_type(ctx, ACCESS_INT); \
+ avr = tcg_temp_new_i64(); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_gen_andi_tl(EA, EA, ~0xf); \
/* We only need to swap high and low halves. gen_qemu_st64_i64 does \
necessary 64-bit byteswap already. */ \
if (ctx->le_mode) { \
- gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \
+ get_avr64(avr, rD(ctx->opcode), false); \
+ gen_qemu_st64_i64(ctx, avr, EA); \
tcg_gen_addi_tl(EA, EA, 8); \
- gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \
+ get_avr64(avr, rD(ctx->opcode), true); \
+ gen_qemu_st64_i64(ctx, avr, EA); \
} else { \
- gen_qemu_st64_i64(ctx, cpu_avrh[rD(ctx->opcode)], EA); \
+ get_avr64(avr, rD(ctx->opcode), true); \
+ gen_qemu_st64_i64(ctx, avr, EA); \
tcg_gen_addi_tl(EA, EA, 8); \
- gen_qemu_st64_i64(ctx, cpu_avrl[rD(ctx->opcode)], EA); \
+ get_avr64(avr, rD(ctx->opcode), false); \
+ gen_qemu_st64_i64(ctx, avr, EA); \
} \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(avr); \
}
#define GEN_VR_LVE(name, opc2, opc3, size) \
@@ -159,15 +178,20 @@ static void gen_lvsr(DisasContext *ctx)
static void gen_mfvscr(DisasContext *ctx)
{
TCGv_i32 t;
+ TCGv_i64 avr;
if (unlikely(!ctx->altivec_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VPU);
return;
}
- tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0);
+ avr = tcg_temp_new_i64();
+ tcg_gen_movi_i64(avr, 0);
+ set_avr64(rD(ctx->opcode), avr, true);
t = tcg_temp_new_i32();
tcg_gen_ld_i32(t, cpu_env, offsetof(CPUPPCState, vscr));
- tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t);
+ tcg_gen_extu_i32_i64(avr, t);
+ set_avr64(rD(ctx->opcode), avr, false);
tcg_temp_free_i32(t);
+ tcg_temp_free_i64(avr);
}
static void gen_mtvscr(DisasContext *ctx)
@@ -185,9 +209,10 @@ static void gen_mtvscr(DisasContext *ctx)
#define GEN_VX_VMUL10(name, add_cin, ret_carry) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
- TCGv_i64 t0 = tcg_temp_new_i64(); \
- TCGv_i64 t1 = tcg_temp_new_i64(); \
- TCGv_i64 t2 = tcg_temp_new_i64(); \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 t2; \
+ TCGv_i64 avr; \
TCGv_i64 ten, z; \
\
if (unlikely(!ctx->altivec_enabled)) { \
@@ -195,30 +220,43 @@ static void glue(gen_, name)(DisasContext *ctx) \
return; \
} \
\
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ t2 = tcg_temp_new_i64(); \
+ avr = tcg_temp_new_i64(); \
ten = tcg_const_i64(10); \
z = tcg_const_i64(0); \
\
if (add_cin) { \
- tcg_gen_mulu2_i64(t0, t1, cpu_avrl[rA(ctx->opcode)], ten); \
- tcg_gen_andi_i64(t2, cpu_avrl[rB(ctx->opcode)], 0xF); \
- tcg_gen_add2_i64(cpu_avrl[rD(ctx->opcode)], t2, t0, t1, t2, z); \
+ get_avr64(avr, rA(ctx->opcode), false); \
+ tcg_gen_mulu2_i64(t0, t1, avr, ten); \
+ get_avr64(avr, rB(ctx->opcode), false); \
+ tcg_gen_andi_i64(t2, avr, 0xF); \
+ tcg_gen_add2_i64(avr, t2, t0, t1, t2, z); \
+ set_avr64(rD(ctx->opcode), avr, false); \
} else { \
- tcg_gen_mulu2_i64(cpu_avrl[rD(ctx->opcode)], t2, \
- cpu_avrl[rA(ctx->opcode)], ten); \
+ get_avr64(avr, rA(ctx->opcode), false); \
+ tcg_gen_mulu2_i64(avr, t2, avr, ten); \
+ set_avr64(rD(ctx->opcode), avr, false); \
} \
\
if (ret_carry) { \
- tcg_gen_mulu2_i64(t0, t1, cpu_avrh[rA(ctx->opcode)], ten); \
- tcg_gen_add2_i64(t0, cpu_avrl[rD(ctx->opcode)], t0, t1, t2, z); \
- tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0); \
+ get_avr64(avr, rA(ctx->opcode), true); \
+ tcg_gen_mulu2_i64(t0, t1, avr, ten); \
+ tcg_gen_add2_i64(t0, avr, t0, t1, t2, z); \
+ set_avr64(rD(ctx->opcode), avr, false); \
+ set_avr64(rD(ctx->opcode), z, true); \
} else { \
- tcg_gen_mul_i64(t0, cpu_avrh[rA(ctx->opcode)], ten); \
- tcg_gen_add_i64(cpu_avrh[rD(ctx->opcode)], t0, t2); \
+ get_avr64(avr, rA(ctx->opcode), true); \
+ tcg_gen_mul_i64(t0, avr, ten); \
+ tcg_gen_add_i64(avr, t0, t2); \
+ set_avr64(rD(ctx->opcode), avr, true); \
} \
\
tcg_temp_free_i64(t0); \
tcg_temp_free_i64(t1); \
tcg_temp_free_i64(t2); \
+ tcg_temp_free_i64(avr); \
tcg_temp_free_i64(ten); \
tcg_temp_free_i64(z); \
} \
@@ -232,12 +270,31 @@ GEN_VX_VMUL10(vmul10ecuq, 1, 1);
#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 avr; \
+ \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
- tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
- tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ avr = tcg_temp_new_i64(); \
+ \
+ get_avr64(t0, rA(ctx->opcode), true); \
+ get_avr64(t1, rB(ctx->opcode), true); \
+ tcg_op(avr, t0, t1); \
+ set_avr64(rD(ctx->opcode), avr, true); \
+ \
+ get_avr64(t0, rA(ctx->opcode), false); \
+ get_avr64(t1, rB(ctx->opcode), false); \
+ tcg_op(avr, t0, t1); \
+ set_avr64(rD(ctx->opcode), avr, false); \
+ \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
+ tcg_temp_free_i64(avr); \
}
GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
@@ -406,6 +463,7 @@ GEN_VXFORM(vmrglw, 6, 6);
static void gen_vmrgew(DisasContext *ctx)
{
TCGv_i64 tmp;
+ TCGv_i64 avr;
int VT, VA, VB;
if (unlikely(!ctx->altivec_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VPU);
@@ -415,15 +473,28 @@ static void gen_vmrgew(DisasContext *ctx)
VA = rA(ctx->opcode);
VB = rB(ctx->opcode);
tmp = tcg_temp_new_i64();
- tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32);
- tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32);
- tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32);
- tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32);
+ avr = tcg_temp_new_i64();
+
+ get_avr64(avr, VB, true);
+ tcg_gen_shri_i64(tmp, avr, 32);
+ get_avr64(avr, VA, true);
+ tcg_gen_deposit_i64(avr, avr, tmp, 0, 32);
+ set_avr64(VT, avr, true);
+
+ get_avr64(avr, VB, false);
+ tcg_gen_shri_i64(tmp, avr, 32);
+ get_avr64(avr, VA, false);
+ tcg_gen_deposit_i64(avr, avr, tmp, 0, 32);
+ set_avr64(VT, avr, false);
+
tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(avr);
}
static void gen_vmrgow(DisasContext *ctx)
{
+ TCGv_i64 t0, t1;
+ TCGv_i64 avr;
int VT, VA, VB;
if (unlikely(!ctx->altivec_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VPU);
@@ -432,9 +503,23 @@ static void gen_vmrgow(DisasContext *ctx)
VT = rD(ctx->opcode);
VA = rA(ctx->opcode);
VB = rB(ctx->opcode);
-
- tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32);
- tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32);
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ avr = tcg_temp_new_i64();
+
+ get_avr64(t0, VB, true);
+ get_avr64(t1, VA, true);
+ tcg_gen_deposit_i64(avr, t0, t1, 32, 32);
+ set_avr64(VT, avr, true);
+
+ get_avr64(t0, VB, false);
+ get_avr64(t1, VA, false);
+ tcg_gen_deposit_i64(avr, t0, t1, 32, 32);
+ set_avr64(VT, avr, false);
+
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(avr);
}
GEN_VXFORM(vmuloub, 4, 0);
@@ -790,7 +875,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
{ \
TCGv_ptr rb, rd; \
uint8_t uimm = UIMM4(ctx->opcode); \
- TCGv_i32 t0 = tcg_temp_new_i32(); \
+ TCGv_i32 t0; \
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
@@ -798,6 +883,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
if (uimm > splat_max) { \
uimm = 0; \
} \
+ t0 = tcg_temp_new_i32(); \
tcg_gen_movi_i32(t0, uimm); \
rb = gen_avr_ptr(rB(ctx->opcode)); \
rd = gen_avr_ptr(rD(ctx->opcode)); \
diff --git a/target/ppc/translate/vmx-ops.inc.c b/target/ppc/translate/vmx-ops.inc.c
index 139f80cb24..84e05fb827 100644
--- a/target/ppc/translate/vmx-ops.inc.c
+++ b/target/ppc/translate/vmx-ops.inc.c
@@ -143,7 +143,7 @@ GEN_VXFORM(vaddsws, 0, 14),
GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vsubuws, 0, 26),
-GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_NONE, PPC2_ISA300),
+GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
GEN_VXFORM(vsubshs, 0, 29),
GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_207(vadduqm, 0, 4),
diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c
index 85ed135d44..ed4fdceacf 100644
--- a/target/ppc/translate/vsx-impl.inc.c
+++ b/target/ppc/translate/vsx-impl.inc.c
@@ -1,20 +1,48 @@
/*** VSX extension ***/
-static inline TCGv_i64 cpu_vsrh(int n)
+static inline void get_vsr(TCGv_i64 dst, int n)
+{
+ tcg_gen_ld_i64(dst, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1]));
+}
+
+static inline void set_vsr(int n, TCGv_i64 src)
+{
+ tcg_gen_st_i64(src, cpu_env, offsetof(CPUPPCState, vsr[n].u64[1]));
+}
+
+static inline void get_cpu_vsrh(TCGv_i64 dst, int n)
+{
+ if (n < 32) {
+ get_fpr(dst, n);
+ } else {
+ get_avr64(dst, n - 32, true);
+ }
+}
+
+static inline void get_cpu_vsrl(TCGv_i64 dst, int n)
+{
+ if (n < 32) {
+ get_vsr(dst, n);
+ } else {
+ get_avr64(dst, n - 32, false);
+ }
+}
+
+static inline void set_cpu_vsrh(int n, TCGv_i64 src)
{
if (n < 32) {
- return cpu_fpr[n];
+ set_fpr(n, src);
} else {
- return cpu_avrh[n-32];
+ set_avr64(n - 32, src, true);
}
}
-static inline TCGv_i64 cpu_vsrl(int n)
+static inline void set_cpu_vsrl(int n, TCGv_i64 src)
{
if (n < 32) {
- return cpu_vsr[n];
+ set_vsr(n, src);
} else {
- return cpu_avrl[n-32];
+ set_avr64(n - 32, src, false);
}
}
@@ -22,16 +50,20 @@ static inline TCGv_i64 cpu_vsrl(int n)
static void gen_##name(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \
+ gen_qemu_##operation(ctx, t0, EA); \
+ set_cpu_vsrh(xT(ctx->opcode), t0); \
/* NOTE: cpu_vsrl is undefined */ \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
VSX_LOAD_SCALAR(lxsdx, ld64_i64)
@@ -44,43 +76,60 @@ VSX_LOAD_SCALAR(lxsspx, ld32fs)
static void gen_lxvd2x(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
- gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_cpu_vsrh(xT(ctx->opcode), t0);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, cpu_vsrl(xT(ctx->opcode)), EA);
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_cpu_vsrl(xT(ctx->opcode), t0);
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
static void gen_lxvdsx(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
+ TCGv_i64 t1;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
- gen_qemu_ld64_i64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
+ gen_qemu_ld64_i64(ctx, t0, EA);
+ set_cpu_vsrh(xT(ctx->opcode), t0);
+ tcg_gen_mov_i64(t1, t0);
+ set_cpu_vsrl(xT(ctx->opcode), t1);
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
}
static void gen_lxvw4x(DisasContext *ctx)
{
TCGv EA;
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ get_cpu_vsrh(xth, xT(ctx->opcode));
+ get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
@@ -104,6 +153,8 @@ static void gen_lxvw4x(DisasContext *ctx)
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
}
static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl,
@@ -151,13 +202,17 @@ static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl,
static void gen_lxvh8x(DisasContext *ctx)
{
TCGv EA;
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ get_cpu_vsrh(xth, xT(ctx->opcode));
+ get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
@@ -169,18 +224,24 @@ static void gen_lxvh8x(DisasContext *ctx)
gen_bswap16x8(xth, xtl, xth, xtl);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
}
static void gen_lxvb16x(DisasContext *ctx)
{
TCGv EA;
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ get_cpu_vsrh(xth, xT(ctx->opcode));
+ get_cpu_vsrl(xtl, xT(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
@@ -188,6 +249,8 @@ static void gen_lxvb16x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ);
tcg_temp_free(EA);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
}
#define VSX_VECTOR_LOAD_STORE(name, op, indexed) \
@@ -195,15 +258,14 @@ static void gen_##name(DisasContext *ctx) \
{ \
int xt; \
TCGv EA; \
- TCGv_i64 xth, xtl; \
+ TCGv_i64 xth; \
+ TCGv_i64 xtl; \
\
if (indexed) { \
xt = xT(ctx->opcode); \
} else { \
xt = DQxT(ctx->opcode); \
} \
- xth = cpu_vsrh(xt); \
- xtl = cpu_vsrl(xt); \
\
if (xt < 32) { \
if (unlikely(!ctx->vsx_enabled)) { \
@@ -216,6 +278,10 @@ static void gen_##name(DisasContext *ctx) \
return; \
} \
} \
+ xth = tcg_temp_new_i64(); \
+ xtl = tcg_temp_new_i64(); \
+ get_cpu_vsrh(xth, xt); \
+ get_cpu_vsrl(xtl, xt); \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
if (indexed) { \
@@ -225,14 +291,20 @@ static void gen_##name(DisasContext *ctx) \
} \
if (ctx->le_mode) { \
tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_LEQ); \
+ set_cpu_vsrl(xt, xtl); \
tcg_gen_addi_tl(EA, EA, 8); \
tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_LEQ); \
+ set_cpu_vsrh(xt, xth); \
} else { \
tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_BEQ); \
+ set_cpu_vsrh(xt, xth); \
tcg_gen_addi_tl(EA, EA, 8); \
tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_BEQ); \
+ set_cpu_vsrl(xt, xtl); \
} \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(xth); \
+ tcg_temp_free_i64(xtl); \
}
VSX_VECTOR_LOAD_STORE(lxv, ld_i64, 0)
@@ -276,18 +348,22 @@ VSX_VECTOR_LOAD_STORE_LENGTH(stxvll)
static void gen_##name(DisasContext *ctx) \
{ \
TCGv EA; \
- TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \
+ TCGv_i64 xth; \
\
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
+ xth = tcg_temp_new_i64(); \
+ get_cpu_vsrh(xth, rD(ctx->opcode) + 32); \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_imm_index(ctx, EA, 0x03); \
gen_qemu_##operation(ctx, xth, EA); \
+ set_cpu_vsrh(rD(ctx->opcode) + 32, xth); \
/* NOTE: cpu_vsrl is undefined */ \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(xth); \
}
VSX_LOAD_SCALAR_DS(lxsd, ld64_i64)
@@ -297,15 +373,19 @@ VSX_LOAD_SCALAR_DS(lxssp, ld32fs)
static void gen_##name(DisasContext *ctx) \
{ \
TCGv EA; \
+ TCGv_i64 t0; \
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
} \
+ t0 = tcg_temp_new_i64(); \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
- gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \
+ gen_qemu_##operation(ctx, t0, EA); \
+ set_cpu_vsrh(xS(ctx->opcode), t0); \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(t0); \
}
VSX_STORE_SCALAR(stxsdx, st64_i64)
@@ -318,28 +398,38 @@ VSX_STORE_SCALAR(stxsspx, st32fs)
static void gen_stxvd2x(DisasContext *ctx)
{
TCGv EA;
+ TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
- gen_qemu_st64_i64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
+ get_cpu_vsrh(t0, xS(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_st64_i64(ctx, cpu_vsrl(xS(ctx->opcode)), EA);
+ get_cpu_vsrl(t0, xS(ctx->opcode));
+ gen_qemu_st64_i64(ctx, t0, EA);
tcg_temp_free(EA);
+ tcg_temp_free_i64(t0);
}
static void gen_stxvw4x(DisasContext *ctx)
{
- TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode));
- TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode));
TCGv EA;
+ TCGv_i64 xsh;
+ TCGv_i64 xsl;
+
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xsh = tcg_temp_new_i64();
+ xsl = tcg_temp_new_i64();
+ get_cpu_vsrh(xsh, xS(ctx->opcode));
+ get_cpu_vsrl(xsl, xS(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
@@ -362,18 +452,24 @@ static void gen_stxvw4x(DisasContext *ctx)
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(xsh);
+ tcg_temp_free_i64(xsl);
}
static void gen_stxvh8x(DisasContext *ctx)
{
- TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode));
- TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode));
TCGv EA;
+ TCGv_i64 xsh;
+ TCGv_i64 xsl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xsh = tcg_temp_new_i64();
+ xsl = tcg_temp_new_i64();
+ get_cpu_vsrh(xsh, xS(ctx->opcode));
+ get_cpu_vsrl(xsl, xS(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
@@ -393,18 +489,24 @@ static void gen_stxvh8x(DisasContext *ctx)
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
}
tcg_temp_free(EA);
+ tcg_temp_free_i64(xsh);
+ tcg_temp_free_i64(xsl);
}
static void gen_stxvb16x(DisasContext *ctx)
{
- TCGv_i64 xsh = cpu_vsrh(xS(ctx->opcode));
- TCGv_i64 xsl = cpu_vsrl(xS(ctx->opcode));
TCGv EA;
+ TCGv_i64 xsh;
+ TCGv_i64 xsl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xsh = tcg_temp_new_i64();
+ xsl = tcg_temp_new_i64();
+ get_cpu_vsrh(xsh, xS(ctx->opcode));
+ get_cpu_vsrl(xsl, xS(ctx->opcode));
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
@@ -412,80 +514,144 @@ static void gen_stxvb16x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ);
tcg_temp_free(EA);
+ tcg_temp_free_i64(xsh);
+ tcg_temp_free_i64(xsl);
}
#define VSX_STORE_SCALAR_DS(name, operation) \
static void gen_##name(DisasContext *ctx) \
{ \
TCGv EA; \
- TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \
+ TCGv_i64 xth; \
\
if (unlikely(!ctx->altivec_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VPU); \
return; \
} \
+ xth = tcg_temp_new_i64(); \
+ get_cpu_vsrh(xth, rD(ctx->opcode) + 32); \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_imm_index(ctx, EA, 0x03); \
gen_qemu_##operation(ctx, xth, EA); \
/* NOTE: cpu_vsrl is undefined */ \
tcg_temp_free(EA); \
+ tcg_temp_free_i64(xth); \
}
VSX_LOAD_SCALAR_DS(stxsd, st64_i64)
VSX_LOAD_SCALAR_DS(stxssp, st32fs)
-#define MV_VSRW(name, tcgop1, tcgop2, target, source) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- if (xS(ctx->opcode) < 32) { \
- if (unlikely(!ctx->fpu_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_FPU); \
- return; \
- } \
- } else { \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- } \
- TCGv_i64 tmp = tcg_temp_new_i64(); \
- tcg_gen_##tcgop1(tmp, source); \
- tcg_gen_##tcgop2(target, tmp); \
- tcg_temp_free_i64(tmp); \
+static void gen_mfvsrwz(DisasContext *ctx)
+{
+ if (xS(ctx->opcode) < 32) {
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ } else {
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ }
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv_i64 xsh = tcg_temp_new_i64();
+ get_cpu_vsrh(xsh, xS(ctx->opcode));
+ tcg_gen_ext32u_i64(tmp, xsh);
+ tcg_gen_trunc_i64_tl(cpu_gpr[rA(ctx->opcode)], tmp);
+ tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(xsh);
}
+static void gen_mtvsrwa(DisasContext *ctx)
+{
+ if (xS(ctx->opcode) < 32) {
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ } else {
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ }
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv_i64 xsh = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_ext32s_i64(xsh, tmp);
+ set_cpu_vsrh(xT(ctx->opcode), xsh);
+ tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(xsh);
+}
-MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \
- cpu_vsrh(xS(ctx->opcode)))
-MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \
- cpu_gpr[rA(ctx->opcode)])
-MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \
- cpu_gpr[rA(ctx->opcode)])
+static void gen_mtvsrwz(DisasContext *ctx)
+{
+ if (xS(ctx->opcode) < 32) {
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ } else {
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ }
+ TCGv_i64 tmp = tcg_temp_new_i64();
+ TCGv_i64 xsh = tcg_temp_new_i64();
+ tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_ext32u_i64(xsh, tmp);
+ set_cpu_vsrh(xT(ctx->opcode), xsh);
+ tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(xsh);
+}
#if defined(TARGET_PPC64)
-#define MV_VSRD(name, target, source) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- if (xS(ctx->opcode) < 32) { \
- if (unlikely(!ctx->fpu_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_FPU); \
- return; \
- } \
- } else { \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- } \
- tcg_gen_mov_i64(target, source); \
+static void gen_mfvsrd(DisasContext *ctx)
+{
+ TCGv_i64 t0;
+ if (xS(ctx->opcode) < 32) {
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ } else {
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ }
+ t0 = tcg_temp_new_i64();
+ get_cpu_vsrh(t0, xS(ctx->opcode));
+ tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0);
+ tcg_temp_free_i64(t0);
}
-MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode)))
-MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)])
+static void gen_mtvsrd(DisasContext *ctx)
+{
+ TCGv_i64 t0;
+ if (xS(ctx->opcode) < 32) {
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ } else {
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ }
+ t0 = tcg_temp_new_i64();
+ tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]);
+ set_cpu_vsrh(xT(ctx->opcode), t0);
+ tcg_temp_free_i64(t0);
+}
static void gen_mfvsrld(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (xS(ctx->opcode) < 32) {
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
@@ -497,12 +663,15 @@ static void gen_mfvsrld(DisasContext *ctx)
return;
}
}
-
- tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], cpu_vsrl(xS(ctx->opcode)));
+ t0 = tcg_temp_new_i64();
+ get_cpu_vsrl(t0, xS(ctx->opcode));
+ tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0);
+ tcg_temp_free_i64(t0);
}
static void gen_mtvsrdd(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (xT(ctx->opcode) < 32) {
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
@@ -515,17 +684,22 @@ static void gen_mtvsrdd(DisasContext *ctx)
}
}
+ t0 = tcg_temp_new_i64();
if (!rA(ctx->opcode)) {
- tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0);
+ tcg_gen_movi_i64(t0, 0);
} else {
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)]);
+ tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]);
}
+ set_cpu_vsrh(xT(ctx->opcode), t0);
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rB(ctx->opcode)]);
+ tcg_gen_mov_i64(t0, cpu_gpr[rB(ctx->opcode)]);
+ set_cpu_vsrl(xT(ctx->opcode), t0);
+ tcg_temp_free_i64(t0);
}
static void gen_mtvsrws(DisasContext *ctx)
{
+ TCGv_i64 t0;
if (xT(ctx->opcode) < 32) {
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
@@ -538,55 +712,61 @@ static void gen_mtvsrws(DisasContext *ctx)
}
}
- tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)],
+ t0 = tcg_temp_new_i64();
+ tcg_gen_deposit_i64(t0, cpu_gpr[rA(ctx->opcode)],
cpu_gpr[rA(ctx->opcode)], 32, 32);
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xT(ctx->opcode)));
+ set_cpu_vsrl(xT(ctx->opcode), t0);
+ set_cpu_vsrh(xT(ctx->opcode), t0);
+ tcg_temp_free_i64(t0);
}
#endif
static void gen_xxpermdi(DisasContext *ctx)
{
+ TCGv_i64 xh, xl;
+
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xh = tcg_temp_new_i64();
+ xl = tcg_temp_new_i64();
+
if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) ||
(xT(ctx->opcode) == xB(ctx->opcode)))) {
- TCGv_i64 xh, xl;
-
- xh = tcg_temp_new_i64();
- xl = tcg_temp_new_i64();
-
if ((DM(ctx->opcode) & 2) == 0) {
- tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode)));
+ get_cpu_vsrh(xh, xA(ctx->opcode));
} else {
- tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrl(xh, xA(ctx->opcode));
}
if ((DM(ctx->opcode) & 1) == 0) {
- tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrh(xl, xB(ctx->opcode));
} else {
- tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode)));
+ get_cpu_vsrl(xl, xB(ctx->opcode));
}
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh);
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl);
-
- tcg_temp_free_i64(xh);
- tcg_temp_free_i64(xl);
+ set_cpu_vsrh(xT(ctx->opcode), xh);
+ set_cpu_vsrl(xT(ctx->opcode), xl);
} else {
if ((DM(ctx->opcode) & 2) == 0) {
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)));
+ get_cpu_vsrh(xh, xA(ctx->opcode));
+ set_cpu_vsrh(xT(ctx->opcode), xh);
} else {
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrl(xh, xA(ctx->opcode));
+ set_cpu_vsrh(xT(ctx->opcode), xh);
}
if ((DM(ctx->opcode) & 1) == 0) {
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrh(xl, xB(ctx->opcode));
+ set_cpu_vsrl(xT(ctx->opcode), xl);
} else {
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode)));
+ get_cpu_vsrl(xl, xB(ctx->opcode));
+ set_cpu_vsrl(xT(ctx->opcode), xl);
}
}
+ tcg_temp_free_i64(xh);
+ tcg_temp_free_i64(xl);
}
#define OP_ABS 1
@@ -606,7 +786,7 @@ static void glue(gen_, name)(DisasContext * ctx) \
} \
xb = tcg_temp_new_i64(); \
sgm = tcg_temp_new_i64(); \
- tcg_gen_mov_i64(xb, cpu_vsrh(xB(ctx->opcode))); \
+ get_cpu_vsrh(xb, xB(ctx->opcode)); \
tcg_gen_movi_i64(sgm, sgn_mask); \
switch (op) { \
case OP_ABS: { \
@@ -623,7 +803,7 @@ static void glue(gen_, name)(DisasContext * ctx) \
} \
case OP_CPSGN: { \
TCGv_i64 xa = tcg_temp_new_i64(); \
- tcg_gen_mov_i64(xa, cpu_vsrh(xA(ctx->opcode))); \
+ get_cpu_vsrh(xa, xA(ctx->opcode)); \
tcg_gen_and_i64(xa, xa, sgm); \
tcg_gen_andc_i64(xb, xb, sgm); \
tcg_gen_or_i64(xb, xb, xa); \
@@ -631,7 +811,7 @@ static void glue(gen_, name)(DisasContext * ctx) \
break; \
} \
} \
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xb); \
+ set_cpu_vsrh(xT(ctx->opcode), xb); \
tcg_temp_free_i64(xb); \
tcg_temp_free_i64(sgm); \
}
@@ -647,7 +827,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
int xa; \
int xt = rD(ctx->opcode) + 32; \
int xb = rB(ctx->opcode) + 32; \
- TCGv_i64 xah, xbh, xbl, sgm; \
+ TCGv_i64 xah, xbh, xbl, sgm, tmp; \
\
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
@@ -656,8 +836,9 @@ static void glue(gen_, name)(DisasContext *ctx) \
xbh = tcg_temp_new_i64(); \
xbl = tcg_temp_new_i64(); \
sgm = tcg_temp_new_i64(); \
- tcg_gen_mov_i64(xbh, cpu_vsrh(xb)); \
- tcg_gen_mov_i64(xbl, cpu_vsrl(xb)); \
+ tmp = tcg_temp_new_i64(); \
+ get_cpu_vsrh(xbh, xb); \
+ get_cpu_vsrl(xbl, xb); \
tcg_gen_movi_i64(sgm, sgn_mask); \
switch (op) { \
case OP_ABS: \
@@ -672,17 +853,19 @@ static void glue(gen_, name)(DisasContext *ctx) \
case OP_CPSGN: \
xah = tcg_temp_new_i64(); \
xa = rA(ctx->opcode) + 32; \
- tcg_gen_and_i64(xah, cpu_vsrh(xa), sgm); \
+ get_cpu_vsrh(tmp, xa); \
+ tcg_gen_and_i64(xah, tmp, sgm); \
tcg_gen_andc_i64(xbh, xbh, sgm); \
tcg_gen_or_i64(xbh, xbh, xah); \
tcg_temp_free_i64(xah); \
break; \
} \
- tcg_gen_mov_i64(cpu_vsrh(xt), xbh); \
- tcg_gen_mov_i64(cpu_vsrl(xt), xbl); \
+ set_cpu_vsrh(xt, xbh); \
+ set_cpu_vsrl(xt, xbl); \
tcg_temp_free_i64(xbl); \
tcg_temp_free_i64(xbh); \
tcg_temp_free_i64(sgm); \
+ tcg_temp_free_i64(tmp); \
}
VSX_SCALAR_MOVE_QP(xsabsqp, OP_ABS, SGN_MASK_DP)
@@ -701,8 +884,8 @@ static void glue(gen_, name)(DisasContext * ctx) \
xbh = tcg_temp_new_i64(); \
xbl = tcg_temp_new_i64(); \
sgm = tcg_temp_new_i64(); \
- tcg_gen_mov_i64(xbh, cpu_vsrh(xB(ctx->opcode))); \
- tcg_gen_mov_i64(xbl, cpu_vsrl(xB(ctx->opcode))); \
+ set_cpu_vsrh(xB(ctx->opcode), xbh); \
+ set_cpu_vsrl(xB(ctx->opcode), xbl); \
tcg_gen_movi_i64(sgm, sgn_mask); \
switch (op) { \
case OP_ABS: { \
@@ -723,8 +906,8 @@ static void glue(gen_, name)(DisasContext * ctx) \
case OP_CPSGN: { \
TCGv_i64 xah = tcg_temp_new_i64(); \
TCGv_i64 xal = tcg_temp_new_i64(); \
- tcg_gen_mov_i64(xah, cpu_vsrh(xA(ctx->opcode))); \
- tcg_gen_mov_i64(xal, cpu_vsrl(xA(ctx->opcode))); \
+ get_cpu_vsrh(xah, xA(ctx->opcode)); \
+ get_cpu_vsrl(xal, xA(ctx->opcode)); \
tcg_gen_and_i64(xah, xah, sgm); \
tcg_gen_and_i64(xal, xal, sgm); \
tcg_gen_andc_i64(xbh, xbh, sgm); \
@@ -736,8 +919,8 @@ static void glue(gen_, name)(DisasContext * ctx) \
break; \
} \
} \
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xbh); \
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xbl); \
+ set_cpu_vsrh(xT(ctx->opcode), xbh); \
+ set_cpu_vsrl(xT(ctx->opcode), xbl); \
tcg_temp_free_i64(xbh); \
tcg_temp_free_i64(xbl); \
tcg_temp_free_i64(sgm); \
@@ -768,12 +951,19 @@ static void gen_##name(DisasContext * ctx) \
#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \
static void gen_##name(DisasContext * ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
} \
- gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \
- cpu_vsrh(xB(ctx->opcode))); \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ get_cpu_vsrh(t0, xB(ctx->opcode)); \
+ gen_helper_##name(t1, cpu_env, t0); \
+ set_cpu_vsrh(xT(ctx->opcode), t1); \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
}
GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
@@ -949,76 +1139,146 @@ GEN_VSX_HELPER_2(xxpermr, 0x08, 0x07, 0, PPC2_ISA300)
static void gen_xxbrd(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+
tcg_gen_bswap64_i64(xth, xbh);
tcg_gen_bswap64_i64(xtl, xbl);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xxbrh(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+
gen_bswap16x8(xth, xtl, xbh, xbl);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xxbrq(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
- TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
+ TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+ t0 = tcg_temp_new_i64();
+
tcg_gen_bswap64_i64(t0, xbl);
tcg_gen_bswap64_i64(xtl, xbh);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_gen_mov_i64(xth, t0);
+ set_cpu_vsrl(xT(ctx->opcode), xth);
+
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xxbrw(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+
gen_bswap32x4(xth, xtl, xbh, xbl);
+ set_cpu_vsrl(xT(ctx->opcode), xth);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
#define VSX_LOGICAL(name, tcg_op) \
static void glue(gen_, name)(DisasContext * ctx) \
{ \
+ TCGv_i64 t0; \
+ TCGv_i64 t1; \
+ TCGv_i64 t2; \
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
} \
- tcg_op(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)), \
- cpu_vsrh(xB(ctx->opcode))); \
- tcg_op(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)), \
- cpu_vsrl(xB(ctx->opcode))); \
+ t0 = tcg_temp_new_i64(); \
+ t1 = tcg_temp_new_i64(); \
+ t2 = tcg_temp_new_i64(); \
+ get_cpu_vsrh(t0, xA(ctx->opcode)); \
+ get_cpu_vsrh(t1, xB(ctx->opcode)); \
+ tcg_op(t2, t0, t1); \
+ set_cpu_vsrh(xT(ctx->opcode), t2); \
+ get_cpu_vsrl(t0, xA(ctx->opcode)); \
+ get_cpu_vsrl(t1, xB(ctx->opcode)); \
+ tcg_op(t2, t0, t1); \
+ set_cpu_vsrl(xT(ctx->opcode), t2); \
+ tcg_temp_free_i64(t0); \
+ tcg_temp_free_i64(t1); \
+ tcg_temp_free_i64(t2); \
}
VSX_LOGICAL(xxland, tcg_gen_and_i64)
@@ -1033,7 +1293,7 @@ VSX_LOGICAL(xxlorc, tcg_gen_orc_i64)
#define VSX_XXMRG(name, high) \
static void glue(gen_, name)(DisasContext * ctx) \
{ \
- TCGv_i64 a0, a1, b0, b1; \
+ TCGv_i64 a0, a1, b0, b1, tmp; \
if (unlikely(!ctx->vsx_enabled)) { \
gen_exception(ctx, POWERPC_EXCP_VSXU); \
return; \
@@ -1042,27 +1302,29 @@ static void glue(gen_, name)(DisasContext * ctx) \
a1 = tcg_temp_new_i64(); \
b0 = tcg_temp_new_i64(); \
b1 = tcg_temp_new_i64(); \
+ tmp = tcg_temp_new_i64(); \
if (high) { \
- tcg_gen_mov_i64(a0, cpu_vsrh(xA(ctx->opcode))); \
- tcg_gen_mov_i64(a1, cpu_vsrh(xA(ctx->opcode))); \
- tcg_gen_mov_i64(b0, cpu_vsrh(xB(ctx->opcode))); \
- tcg_gen_mov_i64(b1, cpu_vsrh(xB(ctx->opcode))); \
+ get_cpu_vsrh(a0, xA(ctx->opcode)); \
+ get_cpu_vsrh(a1, xA(ctx->opcode)); \
+ get_cpu_vsrh(b0, xB(ctx->opcode)); \
+ get_cpu_vsrh(b1, xB(ctx->opcode)); \
} else { \
- tcg_gen_mov_i64(a0, cpu_vsrl(xA(ctx->opcode))); \
- tcg_gen_mov_i64(a1, cpu_vsrl(xA(ctx->opcode))); \
- tcg_gen_mov_i64(b0, cpu_vsrl(xB(ctx->opcode))); \
- tcg_gen_mov_i64(b1, cpu_vsrl(xB(ctx->opcode))); \
+ get_cpu_vsrl(a0, xA(ctx->opcode)); \
+ get_cpu_vsrl(a1, xA(ctx->opcode)); \
+ get_cpu_vsrl(b0, xB(ctx->opcode)); \
+ get_cpu_vsrl(b1, xB(ctx->opcode)); \
} \
tcg_gen_shri_i64(a0, a0, 32); \
tcg_gen_shri_i64(b0, b0, 32); \
- tcg_gen_deposit_i64(cpu_vsrh(xT(ctx->opcode)), \
- b0, a0, 32, 32); \
- tcg_gen_deposit_i64(cpu_vsrl(xT(ctx->opcode)), \
- b1, a1, 32, 32); \
+ tcg_gen_deposit_i64(tmp, b0, a0, 32, 32); \
+ set_cpu_vsrh(xT(ctx->opcode), tmp); \
+ tcg_gen_deposit_i64(tmp, b1, a1, 32, 32); \
+ set_cpu_vsrl(xT(ctx->opcode), tmp); \
tcg_temp_free_i64(a0); \
tcg_temp_free_i64(a1); \
tcg_temp_free_i64(b0); \
tcg_temp_free_i64(b1); \
+ tcg_temp_free_i64(tmp); \
}
VSX_XXMRG(xxmrghw, 1)
@@ -1070,7 +1332,7 @@ VSX_XXMRG(xxmrglw, 0)
static void gen_xxsel(DisasContext * ctx)
{
- TCGv_i64 a, b, c;
+ TCGv_i64 a, b, c, tmp;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
@@ -1078,40 +1340,49 @@ static void gen_xxsel(DisasContext * ctx)
a = tcg_temp_new_i64();
b = tcg_temp_new_i64();
c = tcg_temp_new_i64();
+ tmp = tcg_temp_new_i64();
- tcg_gen_mov_i64(a, cpu_vsrh(xA(ctx->opcode)));
- tcg_gen_mov_i64(b, cpu_vsrh(xB(ctx->opcode)));
- tcg_gen_mov_i64(c, cpu_vsrh(xC(ctx->opcode)));
+ get_cpu_vsrh(a, xA(ctx->opcode));
+ get_cpu_vsrh(b, xB(ctx->opcode));
+ get_cpu_vsrh(c, xC(ctx->opcode));
tcg_gen_and_i64(b, b, c);
tcg_gen_andc_i64(a, a, c);
- tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), a, b);
+ tcg_gen_or_i64(tmp, a, b);
+ set_cpu_vsrh(xT(ctx->opcode), tmp);
- tcg_gen_mov_i64(a, cpu_vsrl(xA(ctx->opcode)));
- tcg_gen_mov_i64(b, cpu_vsrl(xB(ctx->opcode)));
- tcg_gen_mov_i64(c, cpu_vsrl(xC(ctx->opcode)));
+ get_cpu_vsrl(a, xA(ctx->opcode));
+ get_cpu_vsrl(b, xB(ctx->opcode));
+ get_cpu_vsrl(c, xC(ctx->opcode));
tcg_gen_and_i64(b, b, c);
tcg_gen_andc_i64(a, a, c);
- tcg_gen_or_i64(cpu_vsrl(xT(ctx->opcode)), a, b);
+ tcg_gen_or_i64(tmp, a, b);
+ set_cpu_vsrl(xT(ctx->opcode), tmp);
tcg_temp_free_i64(a);
tcg_temp_free_i64(b);
tcg_temp_free_i64(c);
+ tcg_temp_free_i64(tmp);
}
static void gen_xxspltw(DisasContext *ctx)
{
TCGv_i64 b, b2;
- TCGv_i64 vsr = (UIM(ctx->opcode) & 2) ?
- cpu_vsrl(xB(ctx->opcode)) :
- cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 vsr;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ vsr = tcg_temp_new_i64();
+ if (UIM(ctx->opcode) & 2) {
+ get_cpu_vsrl(vsr, xB(ctx->opcode));
+ } else {
+ get_cpu_vsrh(vsr, xB(ctx->opcode));
+ }
+
b = tcg_temp_new_i64();
b2 = tcg_temp_new_i64();
@@ -1122,9 +1393,11 @@ static void gen_xxspltw(DisasContext *ctx)
}
tcg_gen_shli_i64(b2, b, 32);
- tcg_gen_or_i64(cpu_vsrh(xT(ctx->opcode)), b, b2);
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xT(ctx->opcode)));
+ tcg_gen_or_i64(vsr, b, b2);
+ set_cpu_vsrh(xT(ctx->opcode), vsr);
+ set_cpu_vsrl(xT(ctx->opcode), vsr);
+ tcg_temp_free_i64(vsr);
tcg_temp_free_i64(b);
tcg_temp_free_i64(b2);
}
@@ -1134,6 +1407,7 @@ static void gen_xxspltw(DisasContext *ctx)
static void gen_xxspltib(DisasContext *ctx)
{
unsigned char uim8 = IMM8(ctx->opcode);
+ TCGv_i64 vsr;
if (xS(ctx->opcode) < 32) {
if (unlikely(!ctx->altivec_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VPU);
@@ -1145,8 +1419,11 @@ static void gen_xxspltib(DisasContext *ctx)
return;
}
}
- tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), pattern(uim8));
- tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), pattern(uim8));
+ vsr = tcg_temp_new_i64();
+ tcg_gen_movi_i64(vsr, pattern(uim8));
+ set_cpu_vsrh(xT(ctx->opcode), vsr);
+ set_cpu_vsrl(xT(ctx->opcode), vsr);
+ tcg_temp_free_i64(vsr);
}
static void gen_xxsldwi(DisasContext *ctx)
@@ -1161,40 +1438,40 @@ static void gen_xxsldwi(DisasContext *ctx)
switch (SHW(ctx->opcode)) {
case 0: {
- tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
- tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrh(xth, xA(ctx->opcode));
+ get_cpu_vsrl(xtl, xA(ctx->opcode));
break;
}
case 1: {
TCGv_i64 t0 = tcg_temp_new_i64();
- tcg_gen_mov_i64(xth, cpu_vsrh(xA(ctx->opcode)));
+ get_cpu_vsrh(xth, xA(ctx->opcode));
tcg_gen_shli_i64(xth, xth, 32);
- tcg_gen_mov_i64(t0, cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrl(t0, xA(ctx->opcode));
tcg_gen_shri_i64(t0, t0, 32);
tcg_gen_or_i64(xth, xth, t0);
- tcg_gen_mov_i64(xtl, cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrl(xtl, xA(ctx->opcode));
tcg_gen_shli_i64(xtl, xtl, 32);
- tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrh(t0, xB(ctx->opcode));
tcg_gen_shri_i64(t0, t0, 32);
tcg_gen_or_i64(xtl, xtl, t0);
tcg_temp_free_i64(t0);
break;
}
case 2: {
- tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
- tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrl(xth, xA(ctx->opcode));
+ get_cpu_vsrh(xtl, xB(ctx->opcode));
break;
}
case 3: {
TCGv_i64 t0 = tcg_temp_new_i64();
- tcg_gen_mov_i64(xth, cpu_vsrl(xA(ctx->opcode)));
+ get_cpu_vsrl(xth, xA(ctx->opcode));
tcg_gen_shli_i64(xth, xth, 32);
- tcg_gen_mov_i64(t0, cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrh(t0, xB(ctx->opcode));
tcg_gen_shri_i64(t0, t0, 32);
tcg_gen_or_i64(xth, xth, t0);
- tcg_gen_mov_i64(xtl, cpu_vsrh(xB(ctx->opcode)));
+ get_cpu_vsrh(xtl, xB(ctx->opcode));
tcg_gen_shli_i64(xtl, xtl, 32);
- tcg_gen_mov_i64(t0, cpu_vsrl(xB(ctx->opcode)));
+ get_cpu_vsrl(t0, xB(ctx->opcode));
tcg_gen_shri_i64(t0, t0, 32);
tcg_gen_or_i64(xtl, xtl, t0);
tcg_temp_free_i64(t0);
@@ -1202,8 +1479,8 @@ static void gen_xxsldwi(DisasContext *ctx)
}
}
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xth);
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xtl);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free_i64(xth);
tcg_temp_free_i64(xtl);
@@ -1213,7 +1490,8 @@ static void gen_xxsldwi(DisasContext *ctx)
static void gen_##name(DisasContext *ctx) \
{ \
TCGv xt, xb; \
- TCGv_i32 t0 = tcg_temp_new_i32(); \
+ TCGv_i32 t0; \
+ TCGv_i64 t1; \
uint8_t uimm = UIMM4(ctx->opcode); \
\
if (unlikely(!ctx->vsx_enabled)) { \
@@ -1222,12 +1500,15 @@ static void gen_##name(DisasContext *ctx) \
} \
xt = tcg_const_tl(xT(ctx->opcode)); \
xb = tcg_const_tl(xB(ctx->opcode)); \
+ t0 = tcg_temp_new_i32(); \
+ t1 = tcg_temp_new_i64(); \
/* uimm > 15 out of bound and for \
* uimm > 12 handle as per hardware in helper \
*/ \
if (uimm > 15) { \
- tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); \
- tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), 0); \
+ tcg_gen_movi_i64(t1, 0); \
+ set_cpu_vsrh(xT(ctx->opcode), t1); \
+ set_cpu_vsrl(xT(ctx->opcode), t1); \
return; \
} \
tcg_gen_movi_i32(t0, uimm); \
@@ -1235,6 +1516,7 @@ static void gen_##name(DisasContext *ctx) \
tcg_temp_free(xb); \
tcg_temp_free(xt); \
tcg_temp_free_i32(t0); \
+ tcg_temp_free_i64(t1); \
}
VSX_EXTRACT_INSERT(xxextractuw)
@@ -1244,30 +1526,45 @@ VSX_EXTRACT_INSERT(xxinsertw)
static void gen_xsxexpdp(DisasContext *ctx)
{
TCGv rt = cpu_gpr[rD(ctx->opcode)];
+ TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
- tcg_gen_extract_i64(rt, cpu_vsrh(xB(ctx->opcode)), 52, 11);
+ t0 = tcg_temp_new_i64();
+ get_cpu_vsrh(t0, xB(ctx->opcode));
+ tcg_gen_extract_i64(rt, t0, 52, 11);
+ tcg_temp_free_i64(t0);
}
static void gen_xsxexpqp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
- TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
- TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32);
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, rB(ctx->opcode) + 32);
+
tcg_gen_extract_i64(xth, xbh, 48, 15);
+ set_cpu_vsrh(rD(ctx->opcode) + 32, xth);
tcg_gen_movi_i64(xtl, 0);
+ set_cpu_vsrl(rD(ctx->opcode) + 32, xtl);
+
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
}
static void gen_xsiexpdp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xth;
TCGv ra = cpu_gpr[rA(ctx->opcode)];
TCGv rb = cpu_gpr[rB(ctx->opcode)];
TCGv_i64 t0;
@@ -1277,40 +1574,60 @@ static void gen_xsiexpdp(DisasContext *ctx)
return;
}
t0 = tcg_temp_new_i64();
+ xth = tcg_temp_new_i64();
tcg_gen_andi_i64(xth, ra, 0x800FFFFFFFFFFFFF);
tcg_gen_andi_i64(t0, rb, 0x7FF);
tcg_gen_shli_i64(t0, t0, 52);
tcg_gen_or_i64(xth, xth, t0);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
/* dword[1] is undefined */
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(xth);
}
static void gen_xsiexpqp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
- TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
- TCGv_i64 xah = cpu_vsrh(rA(ctx->opcode) + 32);
- TCGv_i64 xal = cpu_vsrl(rA(ctx->opcode) + 32);
- TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32);
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xah;
+ TCGv_i64 xal;
+ TCGv_i64 xbh;
TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xah = tcg_temp_new_i64();
+ xal = tcg_temp_new_i64();
+ get_cpu_vsrh(xah, rA(ctx->opcode) + 32);
+ get_cpu_vsrl(xal, rA(ctx->opcode) + 32);
+ xbh = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, rB(ctx->opcode) + 32);
t0 = tcg_temp_new_i64();
+
tcg_gen_andi_i64(xth, xah, 0x8000FFFFFFFFFFFF);
tcg_gen_andi_i64(t0, xbh, 0x7FFF);
tcg_gen_shli_i64(t0, t0, 48);
tcg_gen_or_i64(xth, xth, t0);
+ set_cpu_vsrh(rD(ctx->opcode) + 32, xth);
tcg_gen_mov_i64(xtl, xal);
+ set_cpu_vsrl(rD(ctx->opcode) + 32, xtl);
+
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xah);
+ tcg_temp_free_i64(xal);
+ tcg_temp_free_i64(xbh);
}
static void gen_xsxsigdp(DisasContext *ctx)
{
TCGv rt = cpu_gpr[rD(ctx->opcode)];
- TCGv_i64 t0, zr, nan, exp;
+ TCGv_i64 t0, t1, zr, nan, exp;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
@@ -1318,17 +1635,21 @@ static void gen_xsxsigdp(DisasContext *ctx)
}
exp = tcg_temp_new_i64();
t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
zr = tcg_const_i64(0);
nan = tcg_const_i64(2047);
- tcg_gen_extract_i64(exp, cpu_vsrh(xB(ctx->opcode)), 52, 11);
+ get_cpu_vsrh(t1, xB(ctx->opcode));
+ tcg_gen_extract_i64(exp, t1, 52, 11);
tcg_gen_movi_i64(t0, 0x0010000000000000);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
- tcg_gen_andi_i64(rt, cpu_vsrh(xB(ctx->opcode)), 0x000FFFFFFFFFFFFF);
+ get_cpu_vsrh(t1, xB(ctx->opcode));
+ tcg_gen_andi_i64(rt, t1, 0x000FFFFFFFFFFFFF);
tcg_gen_or_i64(rt, rt, t0);
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(t1);
tcg_temp_free_i64(exp);
tcg_temp_free_i64(zr);
tcg_temp_free_i64(nan);
@@ -1337,132 +1658,219 @@ static void gen_xsxsigdp(DisasContext *ctx)
static void gen_xsxsigqp(DisasContext *ctx)
{
TCGv_i64 t0, zr, nan, exp;
- TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
- TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, rB(ctx->opcode) + 32);
+ get_cpu_vsrl(xbl, rB(ctx->opcode) + 32);
exp = tcg_temp_new_i64();
t0 = tcg_temp_new_i64();
zr = tcg_const_i64(0);
nan = tcg_const_i64(32767);
- tcg_gen_extract_i64(exp, cpu_vsrh(rB(ctx->opcode) + 32), 48, 15);
+ tcg_gen_extract_i64(exp, xbh, 48, 15);
tcg_gen_movi_i64(t0, 0x0001000000000000);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
- tcg_gen_andi_i64(xth, cpu_vsrh(rB(ctx->opcode) + 32), 0x0000FFFFFFFFFFFF);
+ tcg_gen_andi_i64(xth, xbh, 0x0000FFFFFFFFFFFF);
tcg_gen_or_i64(xth, xth, t0);
- tcg_gen_mov_i64(xtl, cpu_vsrl(rB(ctx->opcode) + 32));
+ set_cpu_vsrh(rD(ctx->opcode) + 32, xth);
+ tcg_gen_mov_i64(xtl, xbl);
+ set_cpu_vsrl(rD(ctx->opcode) + 32, xtl);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(exp);
tcg_temp_free_i64(zr);
tcg_temp_free_i64(nan);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
#endif
static void gen_xviexpsp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode));
- TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xah;
+ TCGv_i64 xal;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xah = tcg_temp_new_i64();
+ xal = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xah, xA(ctx->opcode));
+ get_cpu_vsrl(xal, xA(ctx->opcode));
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
t0 = tcg_temp_new_i64();
+
tcg_gen_andi_i64(xth, xah, 0x807FFFFF807FFFFF);
tcg_gen_andi_i64(t0, xbh, 0xFF000000FF);
tcg_gen_shli_i64(t0, t0, 23);
tcg_gen_or_i64(xth, xth, t0);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_andi_i64(xtl, xal, 0x807FFFFF807FFFFF);
tcg_gen_andi_i64(t0, xbl, 0xFF000000FF);
tcg_gen_shli_i64(t0, t0, 23);
tcg_gen_or_i64(xtl, xtl, t0);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xah);
+ tcg_temp_free_i64(xal);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xviexpdp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode));
- TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xah;
+ TCGv_i64 xal;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
TCGv_i64 t0;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xah = tcg_temp_new_i64();
+ xal = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xah, xA(ctx->opcode));
+ get_cpu_vsrl(xal, xA(ctx->opcode));
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
t0 = tcg_temp_new_i64();
+
tcg_gen_andi_i64(xth, xah, 0x800FFFFFFFFFFFFF);
tcg_gen_andi_i64(t0, xbh, 0x7FF);
tcg_gen_shli_i64(t0, t0, 52);
tcg_gen_or_i64(xth, xth, t0);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_andi_i64(xtl, xal, 0x800FFFFFFFFFFFFF);
tcg_gen_andi_i64(t0, xbl, 0x7FF);
tcg_gen_shli_i64(t0, t0, 52);
tcg_gen_or_i64(xtl, xtl, t0);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xah);
+ tcg_temp_free_i64(xal);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xvxexpsp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+
tcg_gen_shri_i64(xth, xbh, 23);
tcg_gen_andi_i64(xth, xth, 0xFF000000FF);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_shri_i64(xtl, xbl, 23);
tcg_gen_andi_i64(xtl, xtl, 0xFF000000FF);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
static void gen_xvxexpdp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
+
tcg_gen_extract_i64(xth, xbh, 52, 11);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_extract_i64(xtl, xbl, 52, 11);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
+
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
GEN_VSX_HELPER_2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300)
static void gen_xvxsigdp(DisasContext *ctx)
{
- TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
- TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
- TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
- TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
-
+ TCGv_i64 xth;
+ TCGv_i64 xtl;
+ TCGv_i64 xbh;
+ TCGv_i64 xbl;
TCGv_i64 t0, zr, nan, exp;
if (unlikely(!ctx->vsx_enabled)) {
gen_exception(ctx, POWERPC_EXCP_VSXU);
return;
}
+ xth = tcg_temp_new_i64();
+ xtl = tcg_temp_new_i64();
+ xbh = tcg_temp_new_i64();
+ xbl = tcg_temp_new_i64();
+ get_cpu_vsrh(xbh, xB(ctx->opcode));
+ get_cpu_vsrl(xbl, xB(ctx->opcode));
exp = tcg_temp_new_i64();
t0 = tcg_temp_new_i64();
zr = tcg_const_i64(0);
@@ -1474,6 +1882,7 @@ static void gen_xvxsigdp(DisasContext *ctx)
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
tcg_gen_andi_i64(xth, xbh, 0x000FFFFFFFFFFFFF);
tcg_gen_or_i64(xth, xth, t0);
+ set_cpu_vsrh(xT(ctx->opcode), xth);
tcg_gen_extract_i64(exp, xbl, 52, 11);
tcg_gen_movi_i64(t0, 0x0010000000000000);
@@ -1481,11 +1890,16 @@ static void gen_xvxsigdp(DisasContext *ctx)
tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
tcg_gen_andi_i64(xtl, xbl, 0x000FFFFFFFFFFFFF);
tcg_gen_or_i64(xtl, xtl, t0);
+ set_cpu_vsrl(xT(ctx->opcode), xtl);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(exp);
tcg_temp_free_i64(zr);
tcg_temp_free_i64(nan);
+ tcg_temp_free_i64(xth);
+ tcg_temp_free_i64(xtl);
+ tcg_temp_free_i64(xbh);
+ tcg_temp_free_i64(xbl);
}
#undef GEN_XX2FORM
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 168d0cec28..ade06cc773 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -9081,13 +9081,13 @@ static void init_ppc_proc(PowerPCCPU *cpu)
nb_tlb *= 2;
switch (env->tlb_type) {
case TLB_6XX:
- env->tlb.tlb6 = g_malloc0(nb_tlb * sizeof(ppc6xx_tlb_t));
+ env->tlb.tlb6 = g_new0(ppc6xx_tlb_t, nb_tlb);
break;
case TLB_EMB:
- env->tlb.tlbe = g_malloc0(nb_tlb * sizeof(ppcemb_tlb_t));
+ env->tlb.tlbe = g_new0(ppcemb_tlb_t, nb_tlb);
break;
case TLB_MAS:
- env->tlb.tlbm = g_malloc0(nb_tlb * sizeof(ppcmas_tlb_t));
+ env->tlb.tlbm = g_new0(ppcmas_tlb_t, nb_tlb);
break;
}
/* Pre-compute some useful values */
@@ -9486,7 +9486,7 @@ static bool avr_need_swap(CPUPPCState *env)
static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
- stfq_p(mem_buf, env->fpr[n]);
+ stfq_p(mem_buf, *cpu_fpr_ptr(env, n));
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
@@ -9502,7 +9502,7 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
- env->fpr[n] = ldfq_p(mem_buf);
+ *cpu_fpr_ptr(env, n) = ldfq_p(mem_buf);
return 8;
}
if (n == 32) {
@@ -9516,12 +9516,13 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
+ ppc_avr_t *avr = cpu_avr_ptr(env, n);
if (!avr_need_swap(env)) {
- stq_p(mem_buf, env->avr[n].u64[0]);
- stq_p(mem_buf+8, env->avr[n].u64[1]);
+ stq_p(mem_buf, avr->u64[0]);
+ stq_p(mem_buf + 8, avr->u64[1]);
} else {
- stq_p(mem_buf, env->avr[n].u64[1]);
- stq_p(mem_buf+8, env->avr[n].u64[0]);
+ stq_p(mem_buf, avr->u64[1]);
+ stq_p(mem_buf + 8, avr->u64[0]);
}
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
@@ -9543,14 +9544,15 @@ static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
+ ppc_avr_t *avr = cpu_avr_ptr(env, n);
ppc_maybe_bswap_register(env, mem_buf, 8);
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
if (!avr_need_swap(env)) {
- env->avr[n].u64[0] = ldq_p(mem_buf);
- env->avr[n].u64[1] = ldq_p(mem_buf+8);
+ avr->u64[0] = ldq_p(mem_buf);
+ avr->u64[1] = ldq_p(mem_buf + 8);
} else {
- env->avr[n].u64[1] = ldq_p(mem_buf);
- env->avr[n].u64[0] = ldq_p(mem_buf+8);
+ avr->u64[1] = ldq_p(mem_buf);
+ avr->u64[0] = ldq_p(mem_buf + 8);
}
return 16;
}
@@ -9623,7 +9625,7 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
- stq_p(mem_buf, env->vsr[n]);
+ stq_p(mem_buf, *cpu_vsrl_ptr(env, n));
ppc_maybe_bswap_register(env, mem_buf, 8);
return 8;
}
@@ -9634,7 +9636,7 @@ static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
{
if (n < 32) {
ppc_maybe_bswap_register(env, mem_buf, 8);
- env->vsr[n] = ldq_p(mem_buf);
+ *cpu_vsrl_ptr(env, n) = ldq_p(mem_buf);
return 8;
}
return 0;
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index fcc5d34c1f..4072abe3e4 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1 +1 @@
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o fpu_helper.o gdbstub.o pmp.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a025a0a3ba..28d7e5302f 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -126,6 +126,7 @@ static void rv32gcsu_priv1_09_1_cpu_init(Object *obj)
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
+ set_feature(env, RISCV_FEATURE_PMP);
}
static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -135,6 +136,7 @@ static void rv32gcsu_priv1_10_0_cpu_init(Object *obj)
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
+ set_feature(env, RISCV_FEATURE_PMP);
}
static void rv32imacu_nommu_cpu_init(Object *obj)
@@ -143,6 +145,7 @@ static void rv32imacu_nommu_cpu_init(Object *obj)
set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
+ set_feature(env, RISCV_FEATURE_PMP);
}
#elif defined(TARGET_RISCV64)
@@ -154,6 +157,7 @@ static void rv64gcsu_priv1_09_1_cpu_init(Object *obj)
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
+ set_feature(env, RISCV_FEATURE_PMP);
}
static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
@@ -163,6 +167,7 @@ static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
set_feature(env, RISCV_FEATURE_MMU);
+ set_feature(env, RISCV_FEATURE_PMP);
}
static void rv64imacu_nommu_cpu_init(Object *obj)
@@ -171,6 +176,7 @@ static void rv64imacu_nommu_cpu_init(Object *obj)
set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU);
set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
+ set_feature(env, RISCV_FEATURE_PMP);
}
#endif
@@ -330,8 +336,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
CPUClass *cc = CPU_CLASS(c);
DeviceClass *dc = DEVICE_CLASS(c);
- mcc->parent_realize = dc->realize;
- dc->realize = riscv_cpu_realize;
+ device_class_set_parent_realize(dc, riscv_cpu_realize,
+ &mcc->parent_realize);
mcc->parent_reset = cc->reset;
cc->reset = riscv_cpu_reset;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4ee09b9cff..743f02c8b9 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -83,9 +83,10 @@
/* S extension denotes that Supervisor mode exists, however it is possible
to have a core that support S mode but does not have an MMU and there
is currently no bit in misa to indicate whether an MMU exists or not
- so a cpu features bitfield is required */
+ so a cpu features bitfield is required, likewise for optional PMP support */
enum {
- RISCV_FEATURE_MMU
+ RISCV_FEATURE_MMU,
+ RISCV_FEATURE_PMP
};
#define USER_VERSION_2_02_0 0x00020200
@@ -289,9 +290,39 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
#endif
}
-void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
- target_ulong csrno);
-target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno);
+int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask);
+
+static inline void csr_write_helper(CPURISCVState *env, target_ulong val,
+ int csrno)
+{
+ riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
+}
+
+static inline target_ulong csr_read_helper(CPURISCVState *env, int csrno)
+{
+ target_ulong val = 0;
+ riscv_csrrw(env, csrno, &val, 0, 0);
+ return val;
+}
+
+typedef int (*riscv_csr_predicate_fn)(CPURISCVState *env, int csrno);
+typedef int (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value);
+typedef int (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
+ target_ulong new_value);
+typedef int (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value, target_ulong new_value, target_ulong write_mask);
+
+typedef struct {
+ riscv_csr_predicate_fn predicate;
+ riscv_csr_read_fn read;
+ riscv_csr_write_fn write;
+ riscv_csr_op_fn op;
+} riscv_csr_operations;
+
+void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
+void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
#include "exec/cpu-all.h"
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 86f9f4730c..f257050f12 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -404,7 +404,8 @@ int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
" prot %d\n", __func__, address, ret, pa, prot);
- if (!pmp_hart_has_privs(env, pa, TARGET_PAGE_SIZE, 1 << rw)) {
+ if (riscv_feature(env, RISCV_FEATURE_PMP) &&
+ !pmp_hart_has_privs(env, pa, TARGET_PAGE_SIZE, 1 << rw)) {
ret = TRANSLATE_FAIL;
}
if (ret == TRANSLATE_SUCCESS) {
@@ -445,11 +446,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (RISCV_DEBUG_INTERRUPT) {
int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
if (cs->exception_index & RISCV_EXCP_INT_FLAG) {
- qemu_log_mask(LOG_TRACE, "core 0: trap %s, epc 0x" TARGET_FMT_lx,
- riscv_intr_names[log_cause], env->pc);
+ qemu_log_mask(LOG_TRACE, "core "
+ TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n",
+ env->mhartid, riscv_intr_names[log_cause], env->pc);
} else {
- qemu_log_mask(LOG_TRACE, "core 0: intr %s, epc 0x" TARGET_FMT_lx,
- riscv_excp_names[log_cause], env->pc);
+ qemu_log_mask(LOG_TRACE, "core "
+ TARGET_FMT_ld ": intr %s, epc 0x" TARGET_FMT_lx "\n",
+ env->mhartid, riscv_excp_names[log_cause], env->pc);
}
}
@@ -511,8 +514,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (hasbadaddr) {
if (RISCV_DEBUG_INTERRUPT) {
- qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
- ": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
+ qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
+ TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
}
env->sbadaddr = env->badaddr;
} else {
@@ -526,7 +529,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
s = set_field(s, MSTATUS_SPP, env->priv);
s = set_field(s, MSTATUS_SIE, 0);
- csr_write_helper(env, s, CSR_MSTATUS);
+ env->mstatus = s;
riscv_set_mode(env, PRV_S);
} else {
/* No need to check MTVEC for misaligned - lower 2 bits cannot be set */
@@ -536,8 +539,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (hasbadaddr) {
if (RISCV_DEBUG_INTERRUPT) {
- qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
- ": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
+ qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
+ TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
}
env->mbadaddr = env->badaddr;
} else {
@@ -551,7 +554,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
s = set_field(s, MSTATUS_MPP, env->priv);
s = set_field(s, MSTATUS_MIE, 0);
- csr_write_helper(env, s, CSR_MSTATUS);
+ env->mstatus = s;
riscv_set_mode(env, PRV_M);
}
/* TODO yield load reservation */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
new file mode 100644
index 0000000000..5e7e7d16b8
--- /dev/null
+++ b/target/riscv/csr.c
@@ -0,0 +1,863 @@
+/*
+ * RISC-V Control and Status Registers.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * 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 "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+
+/* CSR function table */
+static riscv_csr_operations csr_ops[];
+
+/* CSR function table constants */
+enum {
+ CSR_TABLE_SIZE = 0x1000
+};
+
+/* CSR function table public API */
+void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops)
+{
+ *ops = csr_ops[csrno & (CSR_TABLE_SIZE - 1)];
+}
+
+void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
+{
+ csr_ops[csrno & (CSR_TABLE_SIZE - 1)] = *ops;
+}
+
+/* Predicates */
+static int fs(CPURISCVState *env, int csrno)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+static int ctr(CPURISCVState *env, int csrno)
+{
+#if !defined(CONFIG_USER_ONLY)
+ target_ulong ctr_en = env->priv == PRV_U ? env->scounteren :
+ env->priv == PRV_S ? env->mcounteren : -1U;
+ if (!(ctr_en & (1 << (csrno & 31)))) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static int any(CPURISCVState *env, int csrno)
+{
+ return 0;
+}
+
+static int smode(CPURISCVState *env, int csrno)
+{
+ return -!riscv_has_ext(env, RVS);
+}
+
+static int pmp(CPURISCVState *env, int csrno)
+{
+ return -!riscv_feature(env, RISCV_FEATURE_PMP);
+}
+#endif
+
+/* User Floating-Point CSRs */
+static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+#endif
+ *val = cpu_riscv_get_fflags(env);
+ return 0;
+}
+
+static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+ env->mstatus |= MSTATUS_FS;
+#endif
+ cpu_riscv_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
+ return 0;
+}
+
+static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+#endif
+ *val = env->frm;
+ return 0;
+}
+
+static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+ env->mstatus |= MSTATUS_FS;
+#endif
+ env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
+ return 0;
+}
+
+static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+#endif
+ *val = (cpu_riscv_get_fflags(env) << FSR_AEXC_SHIFT)
+ | (env->frm << FSR_RD_SHIFT);
+ return 0;
+}
+
+static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (!(env->mstatus & MSTATUS_FS)) {
+ return -1;
+ }
+ env->mstatus |= MSTATUS_FS;
+#endif
+ env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
+ cpu_riscv_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
+ return 0;
+}
+
+/* User Timers and Counters */
+static int read_instret(CPURISCVState *env, int csrno, target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (use_icount) {
+ *val = cpu_get_icount();
+ } else {
+ *val = cpu_get_host_ticks();
+ }
+#else
+ *val = cpu_get_host_ticks();
+#endif
+ return 0;
+}
+
+#if defined(TARGET_RISCV32)
+static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val)
+{
+#if !defined(CONFIG_USER_ONLY)
+ if (use_icount) {
+ *val = cpu_get_icount() >> 32;
+ } else {
+ *val = cpu_get_host_ticks() >> 32;
+ }
+#else
+ *val = cpu_get_host_ticks() >> 32;
+#endif
+ return 0;
+}
+#endif /* TARGET_RISCV32 */
+
+#if defined(CONFIG_USER_ONLY)
+static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = cpu_get_host_ticks();
+ return 0;
+}
+
+#if defined(TARGET_RISCV32)
+static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = cpu_get_host_ticks() >> 32;
+ return 0;
+}
+#endif
+
+#else /* CONFIG_USER_ONLY */
+
+/* Machine constants */
+
+#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP)
+#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP)
+
+static const target_ulong delegable_ints = S_MODE_INTERRUPTS;
+static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS;
+static const target_ulong delegable_excps =
+ (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
+ (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
+ (1ULL << (RISCV_EXCP_ILLEGAL_INST)) |
+ (1ULL << (RISCV_EXCP_BREAKPOINT)) |
+ (1ULL << (RISCV_EXCP_LOAD_ADDR_MIS)) |
+ (1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT)) |
+ (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) |
+ (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) |
+ (1ULL << (RISCV_EXCP_U_ECALL)) |
+ (1ULL << (RISCV_EXCP_S_ECALL)) |
+ (1ULL << (RISCV_EXCP_H_ECALL)) |
+ (1ULL << (RISCV_EXCP_M_ECALL)) |
+ (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) |
+ (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) |
+ (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT));
+static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE |
+ SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
+ SSTATUS_SUM | SSTATUS_SD;
+static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
+ SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
+ SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
+
+#if defined(TARGET_RISCV32)
+static const char valid_vm_1_09[16] = {
+ [VM_1_09_MBARE] = 1,
+ [VM_1_09_SV32] = 1,
+};
+static const char valid_vm_1_10[16] = {
+ [VM_1_10_MBARE] = 1,
+ [VM_1_10_SV32] = 1
+};
+#elif defined(TARGET_RISCV64)
+static const char valid_vm_1_09[16] = {
+ [VM_1_09_MBARE] = 1,
+ [VM_1_09_SV39] = 1,
+ [VM_1_09_SV48] = 1,
+};
+static const char valid_vm_1_10[16] = {
+ [VM_1_10_MBARE] = 1,
+ [VM_1_10_SV39] = 1,
+ [VM_1_10_SV48] = 1,
+ [VM_1_10_SV57] = 1
+};
+#endif /* CONFIG_USER_ONLY */
+
+/* Machine Information Registers */
+static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ return *val = 0;
+}
+
+static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mhartid;
+ return 0;
+}
+
+/* Machine Trap Setup */
+static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mstatus;
+ return 0;
+}
+
+static int validate_vm(CPURISCVState *env, target_ulong vm)
+{
+ return (env->priv_ver >= PRIV_VERSION_1_10_0) ?
+ valid_vm_1_10[vm & 0xf] : valid_vm_1_09[vm & 0xf];
+}
+
+static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+ target_ulong mstatus = env->mstatus;
+ target_ulong mask = 0;
+ target_ulong mpp = get_field(val, MSTATUS_MPP);
+
+ /* flush tlb on mstatus fields that affect VM */
+ if (env->priv_ver <= PRIV_VERSION_1_09_1) {
+ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
+ MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_VM)) {
+ tlb_flush(CPU(riscv_env_get_cpu(env)));
+ }
+ mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
+ MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
+ MSTATUS_MPP | MSTATUS_MXR |
+ (validate_vm(env, get_field(val, MSTATUS_VM)) ?
+ MSTATUS_VM : 0);
+ }
+ if (env->priv_ver >= PRIV_VERSION_1_10_0) {
+ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
+ MSTATUS_MPRV | MSTATUS_SUM)) {
+ tlb_flush(CPU(riscv_env_get_cpu(env)));
+ }
+ mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
+ MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
+ MSTATUS_MPP | MSTATUS_MXR;
+ }
+
+ /* silenty discard mstatus.mpp writes for unsupported modes */
+ if (mpp == PRV_H ||
+ (!riscv_has_ext(env, RVS) && mpp == PRV_S) ||
+ (!riscv_has_ext(env, RVU) && mpp == PRV_U)) {
+ mask &= ~MSTATUS_MPP;
+ }
+
+ mstatus = (mstatus & ~mask) | (val & mask);
+
+ /* Note: this is a workaround for an issue where mstatus.FS
+ does not report dirty after floating point operations
+ that modify floating point state. This workaround is
+ technically compliant with the RISC-V Privileged
+ specification as it is legal to return only off, or dirty.
+ at the expense of extra floating point save/restore. */
+
+ /* FP is always dirty or off */
+ if (mstatus & MSTATUS_FS) {
+ mstatus |= MSTATUS_FS;
+ }
+
+ int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
+ ((mstatus & MSTATUS_XS) == MSTATUS_XS);
+ mstatus = set_field(mstatus, MSTATUS_SD, dirty);
+ env->mstatus = mstatus;
+
+ return 0;
+}
+
+static int read_misa(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->misa;
+ return 0;
+}
+
+static int read_medeleg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->medeleg;
+ return 0;
+}
+
+static int write_medeleg(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->medeleg = (env->medeleg & ~delegable_excps) | (val & delegable_excps);
+ return 0;
+}
+
+static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mideleg;
+ return 0;
+}
+
+static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
+ return 0;
+}
+
+static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mie;
+ return 0;
+}
+
+static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mie = (env->mie & ~all_ints) | (val & all_ints);
+ return 0;
+}
+
+static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mtvec;
+ return 0;
+}
+
+static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val)
+{
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ if ((val & 3) == 0) {
+ env->mtvec = val >> 2 << 2;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: vectored traps not supported");
+ }
+ return 0;
+}
+
+static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ return -1;
+ }
+ *val = env->mcounteren;
+ return 0;
+}
+
+static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ return -1;
+ }
+ env->mcounteren = val;
+ return 0;
+}
+
+static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ return -1;
+ }
+ *val = env->mcounteren;
+ return 0;
+}
+
+static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ return -1;
+ }
+ env->mcounteren = val;
+ return 0;
+}
+
+static int read_mucounteren(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ return -1;
+ }
+ *val = env->scounteren;
+ return 0;
+}
+
+static int write_mucounteren(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (env->priv_ver > PRIV_VERSION_1_09_1) {
+ return -1;
+ }
+ env->scounteren = val;
+ return 0;
+}
+
+/* Machine Trap Handling */
+static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mscratch;
+ return 0;
+}
+
+static int write_mscratch(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mscratch = val;
+ return 0;
+}
+
+static int read_mepc(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mepc;
+ return 0;
+}
+
+static int write_mepc(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mepc = val;
+ return 0;
+}
+
+static int read_mcause(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mcause;
+ return 0;
+}
+
+static int write_mcause(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mcause = val;
+ return 0;
+}
+
+static int read_mbadaddr(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mbadaddr;
+ return 0;
+}
+
+static int write_mbadaddr(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->mbadaddr = val;
+ return 0;
+}
+
+static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ target_ulong mask = write_mask & delegable_ints;
+ uint32_t old_mip;
+
+ /* We can't allow the supervisor to control SEIP as this would allow the
+ * supervisor to clear a pending external interrupt which will result in
+ * lost a interrupt in the case a PLIC is attached. The SEIP bit must be
+ * hardware controlled when a PLIC is attached. This should be an option
+ * for CPUs with software-delegated Supervisor External Interrupts. */
+ mask &= ~MIP_SEIP;
+
+ if (mask) {
+ qemu_mutex_lock_iothread();
+ old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
+ qemu_mutex_unlock_iothread();
+ } else {
+ old_mip = atomic_read(&env->mip);
+ }
+
+ if (ret_value) {
+ *ret_value = old_mip;
+ }
+
+ return 0;
+}
+
+/* Supervisor Trap Setup */
+static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
+ sstatus_v1_10_mask : sstatus_v1_9_mask);
+ *val = env->mstatus & mask;
+ return 0;
+}
+
+static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+ target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
+ sstatus_v1_10_mask : sstatus_v1_9_mask);
+ target_ulong newval = (env->mstatus & ~mask) | (val & mask);
+ return write_mstatus(env, CSR_MSTATUS, newval);
+}
+
+static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->mie & env->mideleg;
+ return 0;
+}
+
+static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
+{
+ target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg);
+ return write_mie(env, CSR_MIE, newval);
+}
+
+static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->stvec;
+ return 0;
+}
+
+static int write_stvec(CPURISCVState *env, int csrno, target_ulong val)
+{
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ if ((val & 3) == 0) {
+ env->stvec = val >> 2 << 2;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "CSR_STVEC: vectored traps not supported");
+ }
+ return 0;
+}
+
+static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ return -1;
+ }
+ *val = env->scounteren;
+ return 0;
+}
+
+static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ return -1;
+ }
+ env->scounteren = val;
+ return 0;
+}
+
+/* Supervisor Trap Handling */
+static int read_sscratch(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->sscratch;
+ return 0;
+}
+
+static int write_sscratch(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->sscratch = val;
+ return 0;
+}
+
+static int read_sepc(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->sepc;
+ return 0;
+}
+
+static int write_sepc(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->sepc = val;
+ return 0;
+}
+
+static int read_scause(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->scause;
+ return 0;
+}
+
+static int write_scause(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->scause = val;
+ return 0;
+}
+
+static int read_sbadaddr(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = env->sbadaddr;
+ return 0;
+}
+
+static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
+{
+ env->sbadaddr = val;
+ return 0;
+}
+
+static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ return rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
+ write_mask & env->mideleg);
+}
+
+/* Supervisor Protection and Translation */
+static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ *val = 0;
+ } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
+ *val = env->satp;
+ } else {
+ *val = env->sptbr;
+ }
+ return 0;
+}
+
+static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
+{
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ return 0;
+ }
+ if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val ^ env->sptbr)) {
+ tlb_flush(CPU(riscv_env_get_cpu(env)));
+ env->sptbr = val & (((target_ulong)
+ 1 << (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
+ }
+ if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
+ validate_vm(env, get_field(val, SATP_MODE)) &&
+ ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
+ {
+ tlb_flush(CPU(riscv_env_get_cpu(env)));
+ env->satp = val;
+ }
+ return 0;
+}
+
+/* Physical Memory Protection */
+static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
+ return 0;
+}
+
+static int write_pmpcfg(CPURISCVState *env, int csrno, target_ulong val)
+{
+ pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val);
+ return 0;
+}
+
+static int read_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0);
+ return 0;
+}
+
+static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val)
+{
+ pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val);
+ return 0;
+}
+
+#endif
+
+/*
+ * riscv_csrrw - read and/or update control and status register
+ *
+ * csrr <-> riscv_csrrw(env, csrno, ret_value, 0, 0);
+ * csrrw <-> riscv_csrrw(env, csrno, ret_value, value, -1);
+ * csrrs <-> riscv_csrrw(env, csrno, ret_value, -1, value);
+ * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value);
+ */
+
+int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ int ret;
+ target_ulong old_value;
+
+ /* check privileges and return -1 if check fails */
+#if !defined(CONFIG_USER_ONLY)
+ int csr_priv = get_field(csrno, 0x300);
+ int read_only = get_field(csrno, 0xC00) == 3;
+ if ((write_mask && read_only) || (env->priv < csr_priv)) {
+ return -1;
+ }
+#endif
+
+ /* check predicate */
+ if (!csr_ops[csrno].predicate || csr_ops[csrno].predicate(env, csrno) < 0) {
+ return -1;
+ }
+
+ /* execute combined read/write operation if it exists */
+ if (csr_ops[csrno].op) {
+ return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask);
+ }
+
+ /* if no accessor exists then return failure */
+ if (!csr_ops[csrno].read) {
+ return -1;
+ }
+
+ /* read old value */
+ ret = csr_ops[csrno].read(env, csrno, &old_value);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* write value if writable and write mask set, otherwise drop writes */
+ if (write_mask) {
+ new_value = (old_value & ~write_mask) | (new_value & write_mask);
+ if (csr_ops[csrno].write) {
+ ret = csr_ops[csrno].write(env, csrno, new_value);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+
+ /* return old value */
+ if (ret_value) {
+ *ret_value = old_value;
+ }
+
+ return 0;
+}
+
+/* Control and Status Register function table */
+static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
+ /* User Floating-Point CSRs */
+ [CSR_FFLAGS] = { fs, read_fflags, write_fflags },
+ [CSR_FRM] = { fs, read_frm, write_frm },
+ [CSR_FCSR] = { fs, read_fcsr, write_fcsr },
+
+ /* User Timers and Counters */
+ [CSR_CYCLE] = { ctr, read_instret },
+ [CSR_INSTRET] = { ctr, read_instret },
+#if defined(TARGET_RISCV32)
+ [CSR_CYCLEH] = { ctr, read_instreth },
+ [CSR_INSTRETH] = { ctr, read_instreth },
+#endif
+
+ /* User-level time CSRs are only available in linux-user
+ * In privileged mode, the monitor emulates these CSRs */
+#if defined(CONFIG_USER_ONLY)
+ [CSR_TIME] = { ctr, read_time },
+#if defined(TARGET_RISCV32)
+ [CSR_TIMEH] = { ctr, read_timeh },
+#endif
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+ /* Machine Timers and Counters */
+ [CSR_MCYCLE] = { any, read_instret },
+ [CSR_MINSTRET] = { any, read_instret },
+#if defined(TARGET_RISCV32)
+ [CSR_MCYCLEH] = { any, read_instreth },
+ [CSR_MINSTRETH] = { any, read_instreth },
+#endif
+
+ /* Machine Information Registers */
+ [CSR_MVENDORID] = { any, read_zero },
+ [CSR_MARCHID] = { any, read_zero },
+ [CSR_MIMPID] = { any, read_zero },
+ [CSR_MHARTID] = { any, read_mhartid },
+
+ /* Machine Trap Setup */
+ [CSR_MSTATUS] = { any, read_mstatus, write_mstatus },
+ [CSR_MISA] = { any, read_misa },
+ [CSR_MIDELEG] = { any, read_mideleg, write_mideleg },
+ [CSR_MEDELEG] = { any, read_medeleg, write_medeleg },
+ [CSR_MIE] = { any, read_mie, write_mie },
+ [CSR_MTVEC] = { any, read_mtvec, write_mtvec },
+ [CSR_MCOUNTEREN] = { any, read_mcounteren, write_mcounteren },
+
+ /* Legacy Counter Setup (priv v1.9.1) */
+ [CSR_MUCOUNTEREN] = { any, read_mucounteren, write_mucounteren },
+ [CSR_MSCOUNTEREN] = { any, read_mscounteren, write_mscounteren },
+
+ /* Machine Trap Handling */
+ [CSR_MSCRATCH] = { any, read_mscratch, write_mscratch },
+ [CSR_MEPC] = { any, read_mepc, write_mepc },
+ [CSR_MCAUSE] = { any, read_mcause, write_mcause },
+ [CSR_MBADADDR] = { any, read_mbadaddr, write_mbadaddr },
+ [CSR_MIP] = { any, NULL, NULL, rmw_mip },
+
+ /* Supervisor Trap Setup */
+ [CSR_SSTATUS] = { smode, read_sstatus, write_sstatus },
+ [CSR_SIE] = { smode, read_sie, write_sie },
+ [CSR_STVEC] = { smode, read_stvec, write_stvec },
+ [CSR_SCOUNTEREN] = { smode, read_scounteren, write_scounteren },
+
+ /* Supervisor Trap Handling */
+ [CSR_SSCRATCH] = { smode, read_sscratch, write_sscratch },
+ [CSR_SEPC] = { smode, read_sepc, write_sepc },
+ [CSR_SCAUSE] = { smode, read_scause, write_scause },
+ [CSR_SBADADDR] = { smode, read_sbadaddr, write_sbadaddr },
+ [CSR_SIP] = { smode, NULL, NULL, rmw_sip },
+
+ /* Supervisor Protection and Translation */
+ [CSR_SATP] = { smode, read_satp, write_satp },
+
+ /* Physical Memory Protection */
+ [CSR_PMPCFG0 ... CSR_PMPADDR9] = { pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp, read_pmpaddr, write_pmpaddr },
+
+ /* Performance Counters */
+ [CSR_HPMCOUNTER3 ... CSR_HPMCOUNTER31] = { ctr, read_zero },
+ [CSR_MHPMCOUNTER3 ... CSR_MHPMCOUNTER31] = { any, read_zero },
+ [CSR_MHPMEVENT3 ... CSR_MHPMEVENT31] = { any, read_zero },
+#if defined(TARGET_RISCV32)
+ [CSR_HPMCOUNTER3H ... CSR_HPMCOUNTER31H] = { ctr, read_zero },
+ [CSR_MHPMCOUNTER3H ... CSR_MHPMCOUNTER31H] = { any, read_zero },
+#endif
+#endif /* !CONFIG_USER_ONLY */
+};
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index fdb87d8d82..01b45ca0ae 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -17,7 +17,6 @@
*/
#include "qemu/osdep.h"
-#include <stdlib.h>
#include "cpu.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 4f919b6c34..3cabb21cd0 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -33,7 +33,10 @@ int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
} else if (n < 65) {
return gdb_get_reg64(mem_buf, env->fpr[n - 33]);
} else if (n < 4096 + 65) {
- return gdb_get_regl(mem_buf, csr_read_helper(env, n - 65));
+ target_ulong val = 0;
+ if (riscv_csrrw(env, n - 65, &val, 0, 0) == 0) {
+ return gdb_get_regl(mem_buf, val);
+ }
}
return 0;
}
@@ -56,7 +59,10 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
env->fpr[n - 33] = ldq_p(mem_buf); /* always 64-bit */
return sizeof(uint64_t);
} else if (n < 4096 + 65) {
- csr_write_helper(env, ldtul_p(mem_buf), n - 65);
+ target_ulong val = ldtul_p(mem_buf);
+ if (riscv_csrrw(env, n - 65, NULL, val, -1) == 0) {
+ return sizeof(target_ulong);
+ }
}
return 0;
}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 3726299d4a..81bd1a77ea 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -24,39 +24,6 @@
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
-#ifndef CONFIG_USER_ONLY
-
-#if defined(TARGET_RISCV32)
-static const char valid_vm_1_09[16] = {
- [VM_1_09_MBARE] = 1,
- [VM_1_09_SV32] = 1,
-};
-static const char valid_vm_1_10[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV32] = 1
-};
-#elif defined(TARGET_RISCV64)
-static const char valid_vm_1_09[16] = {
- [VM_1_09_MBARE] = 1,
- [VM_1_09_SV39] = 1,
- [VM_1_09_SV48] = 1,
-};
-static const char valid_vm_1_10[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV39] = 1,
- [VM_1_10_SV48] = 1,
- [VM_1_10_SV57] = 1
-};
-#endif
-
-static int validate_vm(CPURISCVState *env, target_ulong vm)
-{
- return (env->priv_ver >= PRIV_VERSION_1_10_0) ?
- valid_vm_1_10[vm & 0xf] : valid_vm_1_09[vm & 0xf];
-}
-
-#endif
-
/* Exceptions processing helpers */
void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
uint32_t exception, uintptr_t pc)
@@ -72,584 +39,34 @@ void helper_raise_exception(CPURISCVState *env, uint32_t exception)
do_raise_exception_err(env, exception, 0);
}
-static void validate_mstatus_fs(CPURISCVState *env, uintptr_t ra)
-{
-#ifndef CONFIG_USER_ONLY
- if (!(env->mstatus & MSTATUS_FS)) {
- do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, ra);
- }
-#endif
-}
-
-/*
- * Handle writes to CSRs and any resulting special behavior
- *
- * Adapted from Spike's processor_t::set_csr
- */
-void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
- target_ulong csrno)
-{
-#ifndef CONFIG_USER_ONLY
- uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP;
- uint64_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
-#endif
-
- switch (csrno) {
- case CSR_FFLAGS:
- validate_mstatus_fs(env, GETPC());
- cpu_riscv_set_fflags(env, val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT));
- break;
- case CSR_FRM:
- validate_mstatus_fs(env, GETPC());
- env->frm = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
- break;
- case CSR_FCSR:
- validate_mstatus_fs(env, GETPC());
- env->frm = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
- cpu_riscv_set_fflags(env, (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT);
- break;
-#ifndef CONFIG_USER_ONLY
- case CSR_MSTATUS: {
- target_ulong mstatus = env->mstatus;
- target_ulong mask = 0;
- target_ulong mpp = get_field(val_to_write, MSTATUS_MPP);
-
- /* flush tlb on mstatus fields that affect VM */
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- if ((val_to_write ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
- MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_VM)) {
- helper_tlb_flush(env);
- }
- mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
- MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
- MSTATUS_MPP | MSTATUS_MXR |
- (validate_vm(env, get_field(val_to_write, MSTATUS_VM)) ?
- MSTATUS_VM : 0);
- }
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- if ((val_to_write ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP |
- MSTATUS_MPRV | MSTATUS_SUM)) {
- helper_tlb_flush(env);
- }
- mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE |
- MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM |
- MSTATUS_MPP | MSTATUS_MXR;
- }
-
- /* silenty discard mstatus.mpp writes for unsupported modes */
- if (mpp == PRV_H ||
- (!riscv_has_ext(env, RVS) && mpp == PRV_S) ||
- (!riscv_has_ext(env, RVU) && mpp == PRV_U)) {
- mask &= ~MSTATUS_MPP;
- }
-
- mstatus = (mstatus & ~mask) | (val_to_write & mask);
-
- /* Note: this is a workaround for an issue where mstatus.FS
- does not report dirty after floating point operations
- that modify floating point state. This workaround is
- technically compliant with the RISC-V Privileged
- specification as it is legal to return only off, or dirty.
- at the expense of extra floating point save/restore. */
-
- /* FP is always dirty or off */
- if (mstatus & MSTATUS_FS) {
- mstatus |= MSTATUS_FS;
- }
-
- int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
- ((mstatus & MSTATUS_XS) == MSTATUS_XS);
- mstatus = set_field(mstatus, MSTATUS_SD, dirty);
- env->mstatus = mstatus;
- break;
- }
- case CSR_MIP: {
- /*
- * Since the writeable bits in MIP are not set asynchrously by the
- * CLINT, no additional locking is needed for read-modifiy-write
- * CSR operations
- */
- qemu_mutex_lock_iothread();
- RISCVCPU *cpu = riscv_env_get_cpu(env);
- riscv_cpu_update_mip(cpu, MIP_SSIP | MIP_STIP,
- (val_to_write & (MIP_SSIP | MIP_STIP)));
- /*
- * csrs, csrc on mip.SEIP is not decomposable into separate read and
- * write steps, so a different implementation is needed
- */
- qemu_mutex_unlock_iothread();
- break;
- }
- case CSR_MIE: {
- env->mie = (env->mie & ~all_ints) |
- (val_to_write & all_ints);
- break;
- }
- case CSR_MIDELEG:
- env->mideleg = (env->mideleg & ~delegable_ints)
- | (val_to_write & delegable_ints);
- break;
- case CSR_MEDELEG: {
- target_ulong mask = 0;
- mask |= 1ULL << (RISCV_EXCP_INST_ADDR_MIS);
- mask |= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT);
- mask |= 1ULL << (RISCV_EXCP_ILLEGAL_INST);
- mask |= 1ULL << (RISCV_EXCP_BREAKPOINT);
- mask |= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS);
- mask |= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT);
- mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS);
- mask |= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
- mask |= 1ULL << (RISCV_EXCP_U_ECALL);
- mask |= 1ULL << (RISCV_EXCP_S_ECALL);
- mask |= 1ULL << (RISCV_EXCP_H_ECALL);
- mask |= 1ULL << (RISCV_EXCP_M_ECALL);
- mask |= 1ULL << (RISCV_EXCP_INST_PAGE_FAULT);
- mask |= 1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT);
- mask |= 1ULL << (RISCV_EXCP_STORE_PAGE_FAULT);
- env->medeleg = (env->medeleg & ~mask)
- | (val_to_write & mask);
- break;
- }
- case CSR_MINSTRET:
- /* minstret is WARL so unsupported writes are ignored */
- break;
- case CSR_MCYCLE:
- /* mcycle is WARL so unsupported writes are ignored */
- break;
-#if defined(TARGET_RISCV32)
- case CSR_MINSTRETH:
- /* minstreth is WARL so unsupported writes are ignored */
- break;
- case CSR_MCYCLEH:
- /* mcycleh is WARL so unsupported writes are ignored */
- break;
-#endif
- case CSR_MUCOUNTEREN:
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- env->scounteren = val_to_write;
- break;
- } else {
- goto do_illegal;
- }
- case CSR_MSCOUNTEREN:
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- env->mcounteren = val_to_write;
- break;
- } else {
- goto do_illegal;
- }
- case CSR_SSTATUS: {
- target_ulong ms = env->mstatus;
- target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
- | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
- | SSTATUS_SUM | SSTATUS_SD;
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- mask |= SSTATUS_MXR;
- }
- ms = (ms & ~mask) | (val_to_write & mask);
- csr_write_helper(env, ms, CSR_MSTATUS);
- break;
- }
- case CSR_SIP: {
- qemu_mutex_lock_iothread();
- target_ulong next_mip = (env->mip & ~env->mideleg)
- | (val_to_write & env->mideleg);
- qemu_mutex_unlock_iothread();
- csr_write_helper(env, next_mip, CSR_MIP);
- break;
- }
- case CSR_SIE: {
- target_ulong next_mie = (env->mie & ~env->mideleg)
- | (val_to_write & env->mideleg);
- csr_write_helper(env, next_mie, CSR_MIE);
- break;
- }
- case CSR_SATP: /* CSR_SPTBR */ {
- if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
- break;
- }
- if (env->priv_ver <= PRIV_VERSION_1_09_1 && (val_to_write ^ env->sptbr))
- {
- helper_tlb_flush(env);
- env->sptbr = val_to_write & (((target_ulong)
- 1 << (TARGET_PHYS_ADDR_SPACE_BITS - PGSHIFT)) - 1);
- }
- if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
- validate_vm(env, get_field(val_to_write, SATP_MODE)) &&
- ((val_to_write ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
- {
- helper_tlb_flush(env);
- env->satp = val_to_write;
- }
- break;
- }
- case CSR_SEPC:
- env->sepc = val_to_write;
- break;
- case CSR_STVEC:
- /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
- if ((val_to_write & 3) == 0) {
- env->stvec = val_to_write >> 2 << 2;
- } else {
- qemu_log_mask(LOG_UNIMP,
- "CSR_STVEC: vectored traps not supported\n");
- }
- break;
- case CSR_SCOUNTEREN:
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- env->scounteren = val_to_write;
- break;
- } else {
- goto do_illegal;
- }
- case CSR_SSCRATCH:
- env->sscratch = val_to_write;
- break;
- case CSR_SCAUSE:
- env->scause = val_to_write;
- break;
- case CSR_SBADADDR:
- env->sbadaddr = val_to_write;
- break;
- case CSR_MEPC:
- env->mepc = val_to_write;
- break;
- case CSR_MTVEC:
- /* bits [1:0] indicate mode; 0 = direct, 1 = vectored, 2 >= reserved */
- if ((val_to_write & 3) == 0) {
- env->mtvec = val_to_write >> 2 << 2;
- } else {
- qemu_log_mask(LOG_UNIMP,
- "CSR_MTVEC: vectored traps not supported\n");
- }
- break;
- case CSR_MCOUNTEREN:
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- env->mcounteren = val_to_write;
- break;
- } else {
- goto do_illegal;
- }
- case CSR_MSCRATCH:
- env->mscratch = val_to_write;
- break;
- case CSR_MCAUSE:
- env->mcause = val_to_write;
- break;
- case CSR_MBADADDR:
- env->mbadaddr = val_to_write;
- break;
- case CSR_MISA:
- /* misa is WARL so unsupported writes are ignored */
- break;
- case CSR_PMPCFG0:
- case CSR_PMPCFG1:
- case CSR_PMPCFG2:
- case CSR_PMPCFG3:
- pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val_to_write);
- break;
- case CSR_PMPADDR0:
- case CSR_PMPADDR1:
- case CSR_PMPADDR2:
- case CSR_PMPADDR3:
- case CSR_PMPADDR4:
- case CSR_PMPADDR5:
- case CSR_PMPADDR6:
- case CSR_PMPADDR7:
- case CSR_PMPADDR8:
- case CSR_PMPADDR9:
- case CSR_PMPADDR10:
- case CSR_PMPADDR11:
- case CSR_PMPADDR12:
- case CSR_PMPADDR13:
- case CSR_PMPADDR14:
- case CSR_PMPADDR15:
- pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val_to_write);
- break;
-#endif
-#if !defined(CONFIG_USER_ONLY)
- do_illegal:
-#endif
- default:
- do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
- }
-}
-
-/*
- * Handle reads to CSRs and any resulting special behavior
- *
- * Adapted from Spike's processor_t::get_csr
- */
-target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
-{
-#ifndef CONFIG_USER_ONLY
- target_ulong ctr_en = env->priv == PRV_U ? env->scounteren :
- env->priv == PRV_S ? env->mcounteren : -1U;
-#else
- target_ulong ctr_en = -1;
-#endif
- target_ulong ctr_ok = (ctr_en >> (csrno & 31)) & 1;
-
- if (csrno >= CSR_HPMCOUNTER3 && csrno <= CSR_HPMCOUNTER31) {
- if (ctr_ok) {
- return 0;
- }
- }
-#if defined(TARGET_RISCV32)
- if (csrno >= CSR_HPMCOUNTER3H && csrno <= CSR_HPMCOUNTER31H) {
- if (ctr_ok) {
- return 0;
- }
- }
-#endif
- if (csrno >= CSR_MHPMCOUNTER3 && csrno <= CSR_MHPMCOUNTER31) {
- return 0;
- }
-#if defined(TARGET_RISCV32)
- if (csrno >= CSR_MHPMCOUNTER3 && csrno <= CSR_MHPMCOUNTER31) {
- return 0;
- }
-#endif
- if (csrno >= CSR_MHPMEVENT3 && csrno <= CSR_MHPMEVENT31) {
- return 0;
- }
-
- switch (csrno) {
- case CSR_FFLAGS:
- validate_mstatus_fs(env, GETPC());
- return cpu_riscv_get_fflags(env);
- case CSR_FRM:
- validate_mstatus_fs(env, GETPC());
- return env->frm;
- case CSR_FCSR:
- validate_mstatus_fs(env, GETPC());
- return (cpu_riscv_get_fflags(env) << FSR_AEXC_SHIFT)
- | (env->frm << FSR_RD_SHIFT);
- /* rdtime/rdtimeh is trapped and emulated by bbl in system mode */
-#ifdef CONFIG_USER_ONLY
- case CSR_TIME:
- return cpu_get_host_ticks();
-#if defined(TARGET_RISCV32)
- case CSR_TIMEH:
- return cpu_get_host_ticks() >> 32;
-#endif
-#endif
- case CSR_INSTRET:
- case CSR_CYCLE:
- if (ctr_ok) {
-#if !defined(CONFIG_USER_ONLY)
- if (use_icount) {
- return cpu_get_icount();
- } else {
- return cpu_get_host_ticks();
- }
-#else
- return cpu_get_host_ticks();
-#endif
- }
- break;
-#if defined(TARGET_RISCV32)
- case CSR_INSTRETH:
- case CSR_CYCLEH:
- if (ctr_ok) {
-#if !defined(CONFIG_USER_ONLY)
- if (use_icount) {
- return cpu_get_icount() >> 32;
- } else {
- return cpu_get_host_ticks() >> 32;
- }
-#else
- return cpu_get_host_ticks() >> 32;
-#endif
- }
- break;
-#endif
-#ifndef CONFIG_USER_ONLY
- case CSR_MINSTRET:
- case CSR_MCYCLE:
- if (use_icount) {
- return cpu_get_icount();
- } else {
- return cpu_get_host_ticks();
- }
- case CSR_MINSTRETH:
- case CSR_MCYCLEH:
-#if defined(TARGET_RISCV32)
- if (use_icount) {
- return cpu_get_icount() >> 32;
- } else {
- return cpu_get_host_ticks() >> 32;
- }
-#endif
- break;
- case CSR_MUCOUNTEREN:
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- return env->scounteren;
- } else {
- break; /* illegal instruction */
- }
- case CSR_MSCOUNTEREN:
- if (env->priv_ver <= PRIV_VERSION_1_09_1) {
- return env->mcounteren;
- } else {
- break; /* illegal instruction */
- }
- case CSR_SSTATUS: {
- target_ulong mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE
- | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS
- | SSTATUS_SUM | SSTATUS_SD;
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- mask |= SSTATUS_MXR;
- }
- return env->mstatus & mask;
- }
- case CSR_SIP: {
- qemu_mutex_lock_iothread();
- target_ulong tmp = env->mip & env->mideleg;
- qemu_mutex_unlock_iothread();
- return tmp;
- }
- case CSR_SIE:
- return env->mie & env->mideleg;
- case CSR_SEPC:
- return env->sepc;
- case CSR_SBADADDR:
- return env->sbadaddr;
- case CSR_STVEC:
- return env->stvec;
- case CSR_SCOUNTEREN:
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- return env->scounteren;
- } else {
- break; /* illegal instruction */
- }
- case CSR_SCAUSE:
- return env->scause;
- case CSR_SATP: /* CSR_SPTBR */
- if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
- return 0;
- }
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- return env->satp;
- } else {
- return env->sptbr;
- }
- case CSR_SSCRATCH:
- return env->sscratch;
- case CSR_MSTATUS:
- return env->mstatus;
- case CSR_MIP: {
- qemu_mutex_lock_iothread();
- target_ulong tmp = env->mip;
- qemu_mutex_unlock_iothread();
- return tmp;
- }
- case CSR_MIE:
- return env->mie;
- case CSR_MEPC:
- return env->mepc;
- case CSR_MSCRATCH:
- return env->mscratch;
- case CSR_MCAUSE:
- return env->mcause;
- case CSR_MBADADDR:
- return env->mbadaddr;
- case CSR_MISA:
- return env->misa;
- case CSR_MARCHID:
- return 0; /* as spike does */
- case CSR_MIMPID:
- return 0; /* as spike does */
- case CSR_MVENDORID:
- return 0; /* as spike does */
- case CSR_MHARTID:
- return env->mhartid;
- case CSR_MTVEC:
- return env->mtvec;
- case CSR_MCOUNTEREN:
- if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- return env->mcounteren;
- } else {
- break; /* illegal instruction */
- }
- case CSR_MEDELEG:
- return env->medeleg;
- case CSR_MIDELEG:
- return env->mideleg;
- case CSR_PMPCFG0:
- case CSR_PMPCFG1:
- case CSR_PMPCFG2:
- case CSR_PMPCFG3:
- return pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
- case CSR_PMPADDR0:
- case CSR_PMPADDR1:
- case CSR_PMPADDR2:
- case CSR_PMPADDR3:
- case CSR_PMPADDR4:
- case CSR_PMPADDR5:
- case CSR_PMPADDR6:
- case CSR_PMPADDR7:
- case CSR_PMPADDR8:
- case CSR_PMPADDR9:
- case CSR_PMPADDR10:
- case CSR_PMPADDR11:
- case CSR_PMPADDR12:
- case CSR_PMPADDR13:
- case CSR_PMPADDR14:
- case CSR_PMPADDR15:
- return pmpaddr_csr_read(env, csrno - CSR_PMPADDR0);
-#endif
- }
- /* used by e.g. MTIME read */
- do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
-}
-
-/*
- * Check that CSR access is allowed.
- *
- * Adapted from Spike's decode.h:validate_csr
- */
-static void validate_csr(CPURISCVState *env, uint64_t which,
- uint64_t write, uintptr_t ra)
-{
-#ifndef CONFIG_USER_ONLY
- unsigned csr_priv = get_field((which), 0x300);
- unsigned csr_read_only = get_field((which), 0xC00) == 3;
- if (((write) && csr_read_only) || (env->priv < csr_priv)) {
- do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, ra);
- }
-#endif
-}
-
target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
target_ulong csr)
{
- validate_csr(env, csr, 1, GETPC());
- uint64_t csr_backup = csr_read_helper(env, csr);
- csr_write_helper(env, src, csr);
- return csr_backup;
+ target_ulong val = 0;
+ if (riscv_csrrw(env, csr, &val, src, -1) < 0) {
+ do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+ }
+ return val;
}
target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
{
- validate_csr(env, csr, rs1_pass != 0, GETPC());
- uint64_t csr_backup = csr_read_helper(env, csr);
- if (rs1_pass != 0) {
- csr_write_helper(env, src | csr_backup, csr);
+ target_ulong val = 0;
+ if (riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0) < 0) {
+ do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
- return csr_backup;
+ return val;
}
target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
{
- validate_csr(env, csr, rs1_pass != 0, GETPC());
- uint64_t csr_backup = csr_read_helper(env, csr);
- if (rs1_pass != 0) {
- csr_write_helper(env, (~src) & csr_backup, csr);
+ target_ulong val = 0;
+ if (riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0) < 0) {
+ do_raise_exception_err(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
- return csr_backup;
+ return val;
}
#ifndef CONFIG_USER_ONLY
@@ -674,7 +91,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
riscv_set_mode(env, prev_priv);
- csr_write_helper(env, mstatus, CSR_MSTATUS);
+ env->mstatus = mstatus;
return retpc;
}
@@ -699,7 +116,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
riscv_set_mode(env, prev_priv);
- csr_write_helper(env, mstatus, CSR_MSTATUS);
+ env->mstatus = mstatus;
return retpc;
}
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 03abd8fe5e..15a5366616 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -138,7 +138,7 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
return;
} else {
target_ulong t1 = ctz64(~a);
- target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 3;
+ target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 2;
target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1;
*sa = base;
*ea = base + range;
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index acb0f3d4af..aafa740f61 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -130,7 +130,7 @@ out:
}
return;
default:
- hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
break;
}
}
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index 0f090ece54..4a4445bdf5 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -111,7 +111,6 @@ cpu_add_feat_as_prop(const char *typename, const char *name, const char *val)
prop->driver = typename;
prop->property = g_strdup(name);
prop->value = g_strdup(val);
- prop->errp = &error_fatal;
qdev_prop_register_global(prop);
}
diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c
index f201150fc7..df1e4d0fef 100644
--- a/target/tilegx/translate.c
+++ b/target/tilegx/translate.c
@@ -297,7 +297,7 @@ static TileExcp gen_st_opcode(DisasContext *dc, unsigned dest, unsigned srca,
}
tcg_gen_qemu_st_tl(load_gr(dc, srcb), load_gr(dc, srca),
- dc->mmuidx, memop);
+ dc->mmuidx, memop);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "%s %s, %s", name,
reg_names[srca], reg_names[srcb]);
diff --git a/target/tricore/fpu_helper.c b/target/tricore/fpu_helper.c
index df162902d6..31df462e4a 100644
--- a/target/tricore/fpu_helper.c
+++ b/target/tricore/fpu_helper.c
@@ -44,11 +44,6 @@ static inline uint8_t f_get_excp_flags(CPUTriCoreState *env)
| float_flag_inexact);
}
-static inline bool f_is_denormal(float32 arg)
-{
- return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
-}
-
static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
float32 arg3, float32 result,
uint32_t muladd_negate_c)
@@ -260,8 +255,8 @@ uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
set_flush_inputs_to_zero(0, &env->fp_status);
result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1);
- result |= f_is_denormal(arg1) << 4;
- result |= f_is_denormal(arg2) << 5;
+ result |= float32_is_denormal(arg1) << 4;
+ result |= float32_is_denormal(arg2) << 5;
flags = f_get_excp_flags(env);
if (flags) {
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index 9aea1d1771..f966a4fcb3 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -137,6 +137,7 @@ typedef enum {
#define TCG_TARGET_HAS_mul_vec 1
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
diff --git a/tcg/aarch64/tcg-target.inc.c b/tcg/aarch64/tcg-target.inc.c
index 083592a4d7..0562e0aa40 100644
--- a/tcg/aarch64/tcg-target.inc.c
+++ b/tcg/aarch64/tcg-target.inc.c
@@ -78,48 +78,40 @@ static const int tcg_target_call_oarg_regs[1] = {
#define TCG_REG_GUEST_BASE TCG_REG_X28
#endif
-static inline void reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
{
ptrdiff_t offset = target - code_ptr;
- tcg_debug_assert(offset == sextract64(offset, 0, 26));
- /* read instruction, mask away previous PC_REL26 parameter contents,
- set the proper offset, then write back the instruction. */
- *code_ptr = deposit32(*code_ptr, 0, 26, offset);
-}
-
-static inline void reloc_pc26_atomic(tcg_insn_unit *code_ptr,
- tcg_insn_unit *target)
-{
- ptrdiff_t offset = target - code_ptr;
- tcg_insn_unit insn;
- tcg_debug_assert(offset == sextract64(offset, 0, 26));
- /* read instruction, mask away previous PC_REL26 parameter contents,
- set the proper offset, then write back the instruction. */
- insn = atomic_read(code_ptr);
- atomic_set(code_ptr, deposit32(insn, 0, 26, offset));
+ if (offset == sextract64(offset, 0, 26)) {
+ /* read instruction, mask away previous PC_REL26 parameter contents,
+ set the proper offset, then write back the instruction. */
+ *code_ptr = deposit32(*code_ptr, 0, 26, offset);
+ return true;
+ }
+ return false;
}
-static inline void reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
{
ptrdiff_t offset = target - code_ptr;
- tcg_debug_assert(offset == sextract64(offset, 0, 19));
- *code_ptr = deposit32(*code_ptr, 5, 19, offset);
+ if (offset == sextract64(offset, 0, 19)) {
+ *code_ptr = deposit32(*code_ptr, 5, 19, offset);
+ return true;
+ }
+ return false;
}
-static inline void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
tcg_debug_assert(addend == 0);
switch (type) {
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
- reloc_pc26(code_ptr, (tcg_insn_unit *)value);
- break;
+ return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
case R_AARCH64_CONDBR19:
- reloc_pc19(code_ptr, (tcg_insn_unit *)value);
- break;
+ return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
default:
- tcg_abort();
+ g_assert_not_reached();
}
}
@@ -1141,23 +1133,6 @@ static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
}
}
-static inline void tcg_out_goto_noaddr(TCGContext *s)
-{
- /* We pay attention here to not modify the branch target by reading from
- the buffer. This ensure that caches and memory are kept coherent during
- retranslation. Mask away possible garbage in the high bits for the
- first translation, while keeping the offset bits for retranslation. */
- uint32_t old = tcg_in32(s);
- tcg_out_insn(s, 3206, B, old);
-}
-
-static inline void tcg_out_goto_cond_noaddr(TCGContext *s, TCGCond c)
-{
- /* See comments in tcg_out_goto_noaddr. */
- uint32_t old = tcg_in32(s) >> 5;
- tcg_out_insn(s, 3202, B_C, c, old);
-}
-
static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
{
tcg_out_insn(s, 3207, BLR, reg);
@@ -1204,7 +1179,7 @@ static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l)
{
if (!l->has_value) {
tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, l, 0);
- tcg_out_goto_noaddr(s);
+ tcg_out_insn(s, 3206, B, 0);
} else {
tcg_out_goto(s, l->u.value_ptr);
}
@@ -1415,7 +1390,8 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOp opc = get_memop(oi);
TCGMemOp size = opc & MO_SIZE;
- reloc_pc19(lb->label_ptr[0], s->code_ptr);
+ bool ok = reloc_pc19(lb->label_ptr[0], s->code_ptr);
+ tcg_debug_assert(ok);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg);
@@ -1437,7 +1413,8 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOp opc = get_memop(oi);
TCGMemOp size = opc & MO_SIZE;
- reloc_pc19(lb->label_ptr[0], s->code_ptr);
+ bool ok = reloc_pc19(lb->label_ptr[0], s->code_ptr);
+ tcg_debug_assert(ok);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg);
@@ -1535,7 +1512,7 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
/* If not equal, we jump to the slow path. */
*label_ptr = s->code_ptr;
- tcg_out_goto_cond_noaddr(s, TCG_COND_NE);
+ tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
}
#endif /* CONFIG_SOFTMMU */
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 94b3578c55..16172f73a3 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -131,6 +131,7 @@ enum {
};
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c
index e1fbf465cb..49f57d655e 100644
--- a/tcg/arm/tcg-target.inc.c
+++ b/tcg/arm/tcg-target.inc.c
@@ -187,27 +187,23 @@ static const uint8_t tcg_cond_to_arm_cond[] = {
[TCG_COND_GTU] = COND_HI,
};
-static inline void reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+static inline bool reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
{
ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
- *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
-}
-
-static inline void reloc_pc24_atomic(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
-{
- ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
- tcg_insn_unit insn = atomic_read(code_ptr);
- tcg_debug_assert(offset == sextract32(offset, 0, 24));
- atomic_set(code_ptr, deposit32(insn, 0, 24, offset));
+ if (offset == sextract32(offset, 0, 24)) {
+ *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
+ return true;
+ }
+ return false;
}
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
tcg_debug_assert(addend == 0);
if (type == R_ARM_PC24) {
- reloc_pc24(code_ptr, (tcg_insn_unit *)value);
+ return reloc_pc24(code_ptr, (tcg_insn_unit *)value);
} else if (type == R_ARM_PC13) {
intptr_t diff = value - (uintptr_t)(code_ptr + 2);
tcg_insn_unit insn = *code_ptr;
@@ -221,7 +217,11 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
} else {
int rd = extract32(insn, 12, 4);
int rt = rd == TCG_REG_PC ? TCG_REG_TMP : rd;
- assert(diff >= 0x1000 && diff < 0x100000);
+
+ if (diff < 0x1000 || diff >= 0x100000) {
+ return false;
+ }
+
/* add rt, pc, #high */
*code_ptr++ = ((insn & 0xf0000000) | (1 << 25) | ARITH_ADD
| (TCG_REG_PC << 16) | (rt << 12)
@@ -237,6 +237,7 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
} else {
g_assert_not_reached();
}
+ return true;
}
#define TCG_CT_CONST_ARM 0x100
@@ -374,22 +375,6 @@ static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
(((offset - 8) >> 2) & 0x00ffffff));
}
-static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
-{
- /* We pay attention here to not modify the branch target by masking
- the corresponding bytes. This ensure that caches and memory are
- kept coherent during retranslation. */
- tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0a));
-}
-
-static inline void tcg_out_bl_noaddr(TCGContext *s, int cond)
-{
- /* We pay attention here to not modify the branch target by masking
- the corresponding bytes. This ensure that caches and memory are
- kept coherent during retranslation. */
- tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0b));
-}
-
static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset)
{
tcg_out32(s, (cond << 28) | 0x0b000000 |
@@ -1090,7 +1075,7 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, TCGLabel *l)
tcg_out_goto(s, cond, l->u.value_ptr);
} else {
tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, l, 0);
- tcg_out_b_noaddr(s, cond);
+ tcg_out_b(s, cond, 0);
}
}
@@ -1395,7 +1380,8 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOp opc = get_memop(oi);
void *func;
- reloc_pc24(lb->label_ptr[0], s->code_ptr);
+ bool ok = reloc_pc24(lb->label_ptr[0], s->code_ptr);
+ tcg_debug_assert(ok);
argreg = tcg_out_arg_reg32(s, TCG_REG_R0, TCG_AREG0);
if (TARGET_LONG_BITS == 64) {
@@ -1455,7 +1441,8 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOpIdx oi = lb->oi;
TCGMemOp opc = get_memop(oi);
- reloc_pc24(lb->label_ptr[0], s->code_ptr);
+ bool ok = reloc_pc24(lb->label_ptr[0], s->code_ptr);
+ tcg_debug_assert(ok);
argreg = TCG_REG_R0;
argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
@@ -1636,7 +1623,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
/* This a conditional BL only to load a pointer within this opcode into LR
for the slow path. We will not be using the value for a tail call. */
label_ptr = s->code_ptr;
- tcg_out_bl_noaddr(s, COND_NE);
+ tcg_out_bl(s, COND_NE, 0);
tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, addend);
@@ -1768,7 +1755,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
/* The conditional call must come last, as we're going to return here. */
label_ptr = s->code_ptr;
- tcg_out_bl_noaddr(s, COND_NE);
+ tcg_out_bl(s, COND_NE, 0);
add_qemu_ldst_label(s, false, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 9fdf37f23c..f378d29568 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -84,10 +84,12 @@ typedef enum {
TCG_REG_RBP = TCG_REG_EBP,
TCG_REG_RSI = TCG_REG_ESI,
TCG_REG_RDI = TCG_REG_EDI,
+
+ TCG_AREG0 = TCG_REG_EBP,
+ TCG_REG_CALL_STACK = TCG_REG_ESP
} TCGReg;
/* used for function call generation */
-#define TCG_REG_CALL_STACK TCG_REG_ESP
#define TCG_TARGET_STACK_ALIGN 16
#if defined(_WIN64)
#define TCG_TARGET_CALL_STACK_OFFSET 32
@@ -133,8 +135,9 @@ extern bool have_avx2;
#define TCG_TARGET_HAS_direct_jump 1
#if TCG_TARGET_REG_BITS == 64
-#define TCG_TARGET_HAS_extrl_i64_i32 0
-#define TCG_TARGET_HAS_extrh_i64_i32 0
+/* Keep target addresses zero-extended in a register. */
+#define TCG_TARGET_HAS_extrl_i64_i32 (TARGET_LONG_BITS == 32)
+#define TCG_TARGET_HAS_extrh_i64_i32 (TARGET_LONG_BITS == 32)
#define TCG_TARGET_HAS_div2_i64 1
#define TCG_TARGET_HAS_rot_i64 1
#define TCG_TARGET_HAS_ext8s_i64 1
@@ -194,12 +197,6 @@ extern bool have_avx2;
#define TCG_TARGET_extract_i64_valid(ofs, len) \
(((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
-#if TCG_TARGET_REG_BITS == 64
-# define TCG_AREG0 TCG_REG_R14
-#else
-# define TCG_AREG0 TCG_REG_EBP
-#endif
-
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
}
@@ -223,6 +220,8 @@ static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
+
#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
#endif
diff --git a/tcg/i386/tcg-target.inc.c b/tcg/i386/tcg-target.inc.c
index 436195894b..1b4e3b80e1 100644
--- a/tcg/i386/tcg-target.inc.c
+++ b/tcg/i386/tcg-target.inc.c
@@ -167,7 +167,7 @@ static bool have_lzcnt;
static tcg_insn_unit *tb_ret_addr;
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
value += addend;
@@ -175,7 +175,7 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
case R_386_PC32:
value -= (uintptr_t)code_ptr;
if (value != (int32_t)value) {
- tcg_abort();
+ return false;
}
/* FALLTHRU */
case R_386_32:
@@ -184,13 +184,14 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
case R_386_PC8:
value -= (uintptr_t)code_ptr;
if (value != (int8_t)value) {
- tcg_abort();
+ return false;
}
tcg_patch8(code_ptr, value);
break;
default:
tcg_abort();
}
+ return true;
}
#if TCG_TARGET_REG_BITS == 64
@@ -308,13 +309,11 @@ static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
#define P_EXT38 0x200 /* 0x0f 0x38 opcode prefix */
#define P_DATA16 0x400 /* 0x66 opcode prefix */
#if TCG_TARGET_REG_BITS == 64
-# define P_ADDR32 0x800 /* 0x67 opcode prefix */
# define P_REXW 0x1000 /* Set REX.W = 1 */
# define P_REXB_R 0x2000 /* REG field as byte register */
# define P_REXB_RM 0x4000 /* R/M field as byte register */
# define P_GS 0x8000 /* gs segment override */
#else
-# define P_ADDR32 0
# define P_REXW 0
# define P_REXB_R 0
# define P_REXB_RM 0
@@ -527,9 +526,6 @@ static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x)
tcg_debug_assert((opc & P_REXW) == 0);
tcg_out8(s, 0x66);
}
- if (opc & P_ADDR32) {
- tcg_out8(s, 0x67);
- }
if (opc & P_SIMDF3) {
tcg_out8(s, 0xf3);
} else if (opc & P_SIMDF2) {
@@ -1658,11 +1654,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
tcg_out_modrm_offset(s, OPC_CMP_GvEv + trexw, r1, r0, 0);
/* Prepare for both the fast path add of the tlb addend, and the slow
- path function argument setup. There are two cases worth note:
- For 32-bit guest and x86_64 host, MOVL zero-extends the guest address
- before the fastpath ADDQ below. For 64-bit guest and x32 host, MOVQ
- copies the entire guest address for the slow path, while truncation
- for the 32-bit host happens with the fastpath ADDL below. */
+ path function argument setup. */
tcg_out_mov(s, ttype, r1, addrlo);
/* jne slow_path */
@@ -1691,7 +1683,8 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
* Record the context of a call to the out of line helper code for the slow path
* for a load or store, so that we can later generate the correct helper code
*/
-static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
+static void add_qemu_ldst_label(TCGContext *s, bool is_ld, bool is_64,
+ TCGMemOpIdx oi,
TCGReg datalo, TCGReg datahi,
TCGReg addrlo, TCGReg addrhi,
tcg_insn_unit *raddr,
@@ -1701,6 +1694,7 @@ static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
label->is_ld = is_ld;
label->oi = oi;
+ label->type = is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
label->datalo_reg = datalo;
label->datahi_reg = datahi;
label->addrlo_reg = addrlo;
@@ -1721,6 +1715,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
TCGMemOp opc = get_memop(oi);
TCGReg data_reg;
tcg_insn_unit **label_ptr = &l->label_ptr[0];
+ int rexw = (l->type == TCG_TYPE_I64 ? P_REXW : 0);
/* resolve label address */
tcg_patch32(label_ptr[0], s->code_ptr - label_ptr[0] - 4);
@@ -1759,10 +1754,10 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
data_reg = l->datalo_reg;
switch (opc & MO_SSIZE) {
case MO_SB:
- tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
+ tcg_out_ext8s(s, data_reg, TCG_REG_EAX, rexw);
break;
case MO_SW:
- tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
+ tcg_out_ext16s(s, data_reg, TCG_REG_EAX, rexw);
break;
#if TCG_TARGET_REG_BITS == 64
case MO_SL:
@@ -1862,30 +1857,49 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
tcg_out_push(s, retaddr);
tcg_out_jmp(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
}
-#elif defined(__x86_64__) && defined(__linux__)
-# include <asm/prctl.h>
-# include <sys/prctl.h>
-
+#elif TCG_TARGET_REG_BITS == 32
+# define x86_guest_base_seg 0
+# define x86_guest_base_index -1
+# define x86_guest_base_offset guest_base
+#else
+static int x86_guest_base_seg;
+static int x86_guest_base_index = -1;
+static int32_t x86_guest_base_offset;
+# if defined(__x86_64__) && defined(__linux__)
+# include <asm/prctl.h>
+# include <sys/prctl.h>
int arch_prctl(int code, unsigned long addr);
-
-static int guest_base_flags;
-static inline void setup_guest_base_seg(void)
+static inline int setup_guest_base_seg(void)
{
if (arch_prctl(ARCH_SET_GS, guest_base) == 0) {
- guest_base_flags = P_GS;
+ return P_GS;
}
+ return 0;
}
-#else
-# define guest_base_flags 0
-static inline void setup_guest_base_seg(void) { }
+# elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+# include <machine/sysarch.h>
+static inline int setup_guest_base_seg(void)
+{
+ if (sysarch(AMD64_SET_GSBASE, &guest_base) == 0) {
+ return P_GS;
+ }
+ return 0;
+}
+# else
+static inline int setup_guest_base_seg(void)
+{
+ return 0;
+}
+# endif
#endif /* SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
TCGReg base, int index, intptr_t ofs,
- int seg, TCGMemOp memop)
+ int seg, bool is64, TCGMemOp memop)
{
const TCGMemOp real_bswap = memop & MO_BSWAP;
TCGMemOp bswap = real_bswap;
+ int rexw = is64 * P_REXW;
int movop = OPC_MOVL_GvEv;
if (have_movbe && real_bswap) {
@@ -1899,7 +1913,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
base, index, 0, ofs);
break;
case MO_SB:
- tcg_out_modrm_sib_offset(s, OPC_MOVSBL + P_REXW + seg, datalo,
+ tcg_out_modrm_sib_offset(s, OPC_MOVSBL + rexw + seg, datalo,
base, index, 0, ofs);
break;
case MO_UW:
@@ -1919,9 +1933,9 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
base, index, 0, ofs);
tcg_out_rolw_8(s, datalo);
}
- tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo);
+ tcg_out_modrm(s, OPC_MOVSWL + rexw, datalo, datalo);
} else {
- tcg_out_modrm_sib_offset(s, OPC_MOVSWL + P_REXW + seg,
+ tcg_out_modrm_sib_offset(s, OPC_MOVSWL + rexw + seg,
datalo, base, index, 0, ofs);
}
break;
@@ -2009,49 +2023,21 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
label_ptr, offsetof(CPUTLBEntry, addr_read));
/* TLB Hit. */
- tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, -1, 0, 0, opc);
+ tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, -1, 0, 0, is64, opc);
/* Record the current context of a load into ldst label */
- add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi,
+ add_qemu_ldst_label(s, true, is64, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else
- {
- int32_t offset = guest_base;
- TCGReg base = addrlo;
- int index = -1;
- int seg = 0;
-
- /* For a 32-bit guest, the high 32 bits may contain garbage.
- We can do this with the ADDR32 prefix if we're not using
- a guest base, or when using segmentation. Otherwise we
- need to zero-extend manually. */
- if (guest_base == 0 || guest_base_flags) {
- seg = guest_base_flags;
- offset = 0;
- if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
- seg |= P_ADDR32;
- }
- } else if (TCG_TARGET_REG_BITS == 64) {
- if (TARGET_LONG_BITS == 32) {
- tcg_out_ext32u(s, TCG_REG_L0, base);
- base = TCG_REG_L0;
- }
- if (offset != guest_base) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, guest_base);
- index = TCG_REG_L1;
- offset = 0;
- }
- }
-
- tcg_out_qemu_ld_direct(s, datalo, datahi,
- base, index, offset, seg, opc);
- }
+ tcg_out_qemu_ld_direct(s, datalo, datahi, addrlo, x86_guest_base_index,
+ x86_guest_base_offset, x86_guest_base_seg,
+ is64, opc);
#endif
}
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
- TCGReg base, intptr_t ofs, int seg,
- TCGMemOp memop)
+ TCGReg base, int index, intptr_t ofs,
+ int seg, TCGMemOp memop)
{
/* ??? Ideally we wouldn't need a scratch register. For user-only,
we could perform the bswap twice to restore the original value
@@ -2075,8 +2061,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
datalo = scratch;
}
- tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R + seg,
- datalo, base, ofs);
+ tcg_out_modrm_sib_offset(s, OPC_MOVB_EvGv + P_REXB_R + seg,
+ datalo, base, index, 0, ofs);
break;
case MO_16:
if (bswap) {
@@ -2084,7 +2070,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
tcg_out_rolw_8(s, scratch);
datalo = scratch;
}
- tcg_out_modrm_offset(s, movop + P_DATA16 + seg, datalo, base, ofs);
+ tcg_out_modrm_sib_offset(s, movop + P_DATA16 + seg, datalo,
+ base, index, 0, ofs);
break;
case MO_32:
if (bswap) {
@@ -2092,7 +2079,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
tcg_out_bswap32(s, scratch);
datalo = scratch;
}
- tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
+ tcg_out_modrm_sib_offset(s, movop + seg, datalo, base, index, 0, ofs);
break;
case MO_64:
if (TCG_TARGET_REG_BITS == 64) {
@@ -2101,22 +2088,27 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
tcg_out_bswap64(s, scratch);
datalo = scratch;
}
- tcg_out_modrm_offset(s, movop + P_REXW + seg, datalo, base, ofs);
+ tcg_out_modrm_sib_offset(s, movop + P_REXW + seg, datalo,
+ base, index, 0, ofs);
} else if (bswap) {
tcg_out_mov(s, TCG_TYPE_I32, scratch, datahi);
tcg_out_bswap32(s, scratch);
- tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, scratch, base, ofs);
+ tcg_out_modrm_sib_offset(s, OPC_MOVL_EvGv + seg, scratch,
+ base, index, 0, ofs);
tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_bswap32(s, scratch);
- tcg_out_modrm_offset(s, OPC_MOVL_EvGv + seg, scratch, base, ofs+4);
+ tcg_out_modrm_sib_offset(s, OPC_MOVL_EvGv + seg, scratch,
+ base, index, 0, ofs + 4);
} else {
if (real_bswap) {
int t = datalo;
datalo = datahi;
datahi = t;
}
- tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
- tcg_out_modrm_offset(s, movop + seg, datahi, base, ofs+4);
+ tcg_out_modrm_sib_offset(s, movop + seg, datalo,
+ base, index, 0, ofs);
+ tcg_out_modrm_sib_offset(s, movop + seg, datahi,
+ base, index, 0, ofs + 4);
}
break;
default:
@@ -2149,44 +2141,14 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
label_ptr, offsetof(CPUTLBEntry, addr_write));
/* TLB Hit. */
- tcg_out_qemu_st_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
+ tcg_out_qemu_st_direct(s, datalo, datahi, TCG_REG_L1, -1, 0, 0, opc);
/* Record the current context of a store into ldst label */
- add_qemu_ldst_label(s, false, oi, datalo, datahi, addrlo, addrhi,
+ add_qemu_ldst_label(s, false, is64, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else
- {
- int32_t offset = guest_base;
- TCGReg base = addrlo;
- int seg = 0;
-
- /* See comment in tcg_out_qemu_ld re zero-extension of addrlo. */
- if (guest_base == 0 || guest_base_flags) {
- seg = guest_base_flags;
- offset = 0;
- if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
- seg |= P_ADDR32;
- }
- } else if (TCG_TARGET_REG_BITS == 64) {
- /* ??? Note that we can't use the same SIB addressing scheme
- as for loads, since we require L0 free for bswap. */
- if (offset != guest_base) {
- if (TARGET_LONG_BITS == 32) {
- tcg_out_ext32u(s, TCG_REG_L0, base);
- base = TCG_REG_L0;
- }
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, guest_base);
- tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base);
- base = TCG_REG_L1;
- offset = 0;
- } else if (TARGET_LONG_BITS == 32) {
- tcg_out_ext32u(s, TCG_REG_L1, base);
- base = TCG_REG_L1;
- }
- }
-
- tcg_out_qemu_st_direct(s, datalo, datahi, base, offset, seg, opc);
- }
+ tcg_out_qemu_st_direct(s, datalo, datahi, addrlo, x86_guest_base_index,
+ x86_guest_base_offset, x86_guest_base_seg, opc);
#endif
}
@@ -2544,12 +2506,16 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_extu_i32_i64:
case INDEX_op_ext32u_i64:
+ case INDEX_op_extrl_i64_i32:
tcg_out_ext32u(s, a0, a1);
break;
case INDEX_op_ext_i32_i64:
case INDEX_op_ext32s_i64:
tcg_out_ext32s(s, a0, a1);
break;
+ case INDEX_op_extrh_i64_i32:
+ tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32);
+ break;
#endif
OP_32_64(deposit):
@@ -2913,6 +2879,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
case INDEX_op_neg_i64:
case INDEX_op_not_i32:
case INDEX_op_not_i64:
+ case INDEX_op_extrh_i64_i32:
return &r_0;
case INDEX_op_ext8s_i32:
@@ -2928,6 +2895,7 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
case INDEX_op_ext32u_i64:
case INDEX_op_ext_i32_i64:
case INDEX_op_extu_i32_i64:
+ case INDEX_op_extrl_i64_i32:
case INDEX_op_extract_i32:
case INDEX_op_extract_i64:
case INDEX_op_sextract_i32:
@@ -3424,9 +3392,24 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
/* jmp *tb. */
tcg_out_modrm_offset(s, OPC_GRP5, EXT5_JMPN_Ev, TCG_REG_ESP,
- (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4
- + stack_addend);
+ (ARRAY_SIZE(tcg_target_callee_save_regs) + 2) * 4
+ + stack_addend);
#else
+# if !defined(CONFIG_SOFTMMU) && TCG_TARGET_REG_BITS == 64
+ if (guest_base) {
+ int seg = setup_guest_base_seg();
+ if (seg != 0) {
+ x86_guest_base_seg = seg;
+ } else if (guest_base == (int32_t)guest_base) {
+ x86_guest_base_offset = guest_base;
+ } else {
+ /* Choose R12 because, as a base, it requires a SIB byte. */
+ x86_guest_base_index = TCG_REG_R12;
+ tcg_out_mov(s, TCG_TYPE_PTR, x86_guest_base_index, guest_base);
+ tcg_regset_set_reg(s->reserved_regs, x86_guest_base_index);
+ }
+ }
+# endif
tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
/* jmp *tb. */
@@ -3452,13 +3435,6 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_pop(s, tcg_target_callee_save_regs[i]);
}
tcg_out_opc(s, OPC_RET, 0, 0, 0);
-
-#if !defined(CONFIG_SOFTMMU)
- /* Try to set up a segment register to point to guest_base. */
- if (guest_base) {
- setup_guest_base_seg();
- }
-#endif
}
static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index a8222476f0..5cb8672470 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -203,6 +203,7 @@ extern bool use_mips32r2_instructions;
#endif
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c
index cff525373b..be0bc92e8e 100644
--- a/tcg/mips/tcg-target.inc.c
+++ b/tcg/mips/tcg-target.inc.c
@@ -168,12 +168,13 @@ static inline void reloc_26(tcg_insn_unit *pc, tcg_insn_unit *target)
*pc = deposit32(*pc, 0, 26, reloc_26_val(pc, target));
}
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
tcg_debug_assert(type == R_MIPS_PC16);
tcg_debug_assert(addend == 0);
reloc_pc16(code_ptr, (tcg_insn_unit *)value);
+ return true;
}
#define TCG_CT_CONST_ZERO 0x100
@@ -483,12 +484,7 @@ static inline void tcg_out_opc_bf64(TCGContext *s, MIPSInsn opc, MIPSInsn opm,
static inline void tcg_out_opc_br(TCGContext *s, MIPSInsn opc,
TCGReg rt, TCGReg rs)
{
- /* We pay attention here to not modify the branch target by reading
- the existing value and using it again. This ensure that caches and
- memory are kept coherent during retranslation. */
- uint16_t offset = (uint16_t)*s->code_ptr;
-
- tcg_out_opc_imm(s, opc, rt, rs, offset);
+ tcg_out_opc_imm(s, opc, rt, rs, 0);
}
/*
@@ -796,7 +792,7 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
} else if (rl == al && rl == bl) {
- tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
+ tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, TCG_TARGET_REG_BITS - 1);
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
} else {
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 5dbe11c3c8..01e80c3e46 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -353,6 +353,15 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
CASE_OP_32_64(ext16u):
return (uint16_t)x;
+ CASE_OP_32_64(bswap16):
+ return bswap16(x);
+
+ CASE_OP_32_64(bswap32):
+ return bswap32(x);
+
+ case INDEX_op_bswap64_i64:
+ return bswap64(x);
+
case INDEX_op_ext_i32_i64:
case INDEX_op_ext32s_i64:
return (int32_t)x;
@@ -1105,6 +1114,9 @@ void tcg_optimize(TCGContext *s)
CASE_OP_32_64(ext16s):
CASE_OP_32_64(ext16u):
CASE_OP_32_64(ctpop):
+ CASE_OP_32_64(bswap16):
+ CASE_OP_32_64(bswap32):
+ case INDEX_op_bswap64_i64:
case INDEX_op_ext32s_i64:
case INDEX_op_ext32u_i64:
case INDEX_op_ext_i32_i64:
@@ -1249,7 +1261,7 @@ void tcg_optimize(TCGContext *s)
uint64_t a = ((uint64_t)ah << 32) | al;
uint64_t b = ((uint64_t)bh << 32) | bl;
TCGArg rl, rh;
- TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32, 2);
+ TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32);
if (opc == INDEX_op_add2_i32) {
a += b;
@@ -1271,7 +1283,7 @@ void tcg_optimize(TCGContext *s)
uint32_t b = arg_info(op->args[3])->val;
uint64_t r = (uint64_t)a * b;
TCGArg rl, rh;
- TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32, 2);
+ TCGOp *op2 = tcg_op_insert_before(s, op, INDEX_op_movi_i32);
rl = op->args[0];
rh = op->args[1];
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index be52ad1d2e..52c1bb04b1 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -128,6 +128,7 @@ void flush_icache_range(uintptr_t start, uintptr_t stop);
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/ppc/tcg-target.inc.c b/tcg/ppc/tcg-target.inc.c
index c2f729ee8f..8c1cfdd7ac 100644
--- a/tcg/ppc/tcg-target.inc.c
+++ b/tcg/ppc/tcg-target.inc.c
@@ -193,9 +193,14 @@ static uint32_t reloc_pc24_val(tcg_insn_unit *pc, tcg_insn_unit *target)
return disp & 0x3fffffc;
}
-static void reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc24(tcg_insn_unit *pc, tcg_insn_unit *target)
{
- *pc = (*pc & ~0x3fffffc) | reloc_pc24_val(pc, target);
+ ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
+ if (in_range_b(disp)) {
+ *pc = (*pc & ~0x3fffffc) | (disp & 0x3fffffc);
+ return true;
+ }
+ return false;
}
static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
@@ -205,21 +210,14 @@ static uint16_t reloc_pc14_val(tcg_insn_unit *pc, tcg_insn_unit *target)
return disp & 0xfffc;
}
-static void reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
+static bool reloc_pc14(tcg_insn_unit *pc, tcg_insn_unit *target)
{
- *pc = (*pc & ~0xfffc) | reloc_pc14_val(pc, target);
-}
-
-static inline void tcg_out_b_noaddr(TCGContext *s, int insn)
-{
- unsigned retrans = *s->code_ptr & 0x3fffffc;
- tcg_out32(s, insn | retrans);
-}
-
-static inline void tcg_out_bc_noaddr(TCGContext *s, int insn)
-{
- unsigned retrans = *s->code_ptr & 0xfffc;
- tcg_out32(s, insn | retrans);
+ ptrdiff_t disp = tcg_ptr_byte_diff(target, pc);
+ if (disp == (int16_t) disp) {
+ *pc = (*pc & ~0xfffc) | (disp & 0xfffc);
+ return true;
+ }
+ return false;
}
/* parse target specific constraints */
@@ -525,7 +523,7 @@ static const uint32_t tcg_to_isel[] = {
[TCG_COND_GTU] = ISEL | BC_(7, CR_GT),
};
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
tcg_insn_unit *target;
@@ -536,11 +534,9 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
switch (type) {
case R_PPC_REL14:
- reloc_pc14(code_ptr, target);
- break;
+ return reloc_pc14(code_ptr, target);
case R_PPC_REL24:
- reloc_pc24(code_ptr, target);
- break;
+ return reloc_pc24(code_ptr, target);
case R_PPC_ADDR16:
/* We are abusing this relocation type. This points to a pair
of insns, addis + load. If the displacement is small, we
@@ -552,7 +548,9 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
} else {
int16_t lo = value;
int hi = value - lo;
- assert(hi + lo == value);
+ if (hi + lo != value) {
+ return false;
+ }
code_ptr[0] = deposit32(code_ptr[0], 0, 16, hi >> 16);
code_ptr[1] = deposit32(code_ptr[1], 0, 16, lo);
}
@@ -560,6 +558,7 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
default:
g_assert_not_reached();
}
+ return true;
}
static void tcg_out_mem_long(TCGContext *s, int opi, int opx, TCGReg rt,
@@ -1179,11 +1178,11 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond,
static void tcg_out_bc(TCGContext *s, int bc, TCGLabel *l)
{
if (l->has_value) {
- tcg_out32(s, bc | reloc_pc14_val(s->code_ptr, l->u.value_ptr));
+ bc |= reloc_pc14_val(s->code_ptr, l->u.value_ptr);
} else {
tcg_out_reloc(s, s->code_ptr, R_PPC_REL14, l, 0);
- tcg_out_bc_noaddr(s, bc);
}
+ tcg_out32(s, bc);
}
static void tcg_out_brcond(TCGContext *s, TCGCond cond,
@@ -1649,7 +1648,7 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOp opc = get_memop(oi);
TCGReg hi, lo, arg = TCG_REG_R3;
- reloc_pc14(lb->label_ptr[0], s->code_ptr);
+ **lb->label_ptr |= reloc_pc14_val(*lb->label_ptr, s->code_ptr);
tcg_out_mov(s, TCG_TYPE_PTR, arg++, TCG_AREG0);
@@ -1694,7 +1693,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOp s_bits = opc & MO_SIZE;
TCGReg hi, lo, arg = TCG_REG_R3;
- reloc_pc14(lb->label_ptr[0], s->code_ptr);
+ **lb->label_ptr |= reloc_pc14_val(*lb->label_ptr, s->code_ptr);
tcg_out_mov(s, TCG_TYPE_PTR, arg++, TCG_AREG0);
@@ -1771,7 +1770,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
/* Load a pointer into the current opcode w/conditional branch-link. */
label_ptr = s->code_ptr;
- tcg_out_bc_noaddr(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
+ tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
@@ -1846,7 +1845,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
/* Load a pointer into the current opcode w/conditional branch-link. */
label_ptr = s->code_ptr;
- tcg_out_bc_noaddr(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
+ tcg_out32(s, BC | BI(7, CR_EQ) | BO_COND_FALSE | LK);
rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
@@ -2044,13 +2043,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_br:
{
TCGLabel *l = arg_label(args[0]);
+ uint32_t insn = B;
if (l->has_value) {
- tcg_out_b(s, 0, l->u.value_ptr);
+ insn |= reloc_pc24_val(s->code_ptr, l->u.value_ptr);
} else {
tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0);
- tcg_out_b_noaddr(s, B);
}
+ tcg_out32(s, insn);
}
break;
case INDEX_op_ld8u_i32:
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
new file mode 100644
index 0000000000..60918cacb4
--- /dev/null
+++ b/tcg/riscv/tcg-target.h
@@ -0,0 +1,177 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2018 SiFive, 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.
+ */
+
+#ifndef RISCV_TCG_TARGET_H
+#define RISCV_TCG_TARGET_H
+
+#if __riscv_xlen == 32
+# define TCG_TARGET_REG_BITS 32
+#elif __riscv_xlen == 64
+# define TCG_TARGET_REG_BITS 64
+#endif
+
+#define TCG_TARGET_INSN_UNIT_SIZE 4
+#define TCG_TARGET_TLB_DISPLACEMENT_BITS 20
+#define TCG_TARGET_NB_REGS 32
+
+typedef enum {
+ TCG_REG_ZERO,
+ TCG_REG_RA,
+ TCG_REG_SP,
+ TCG_REG_GP,
+ TCG_REG_TP,
+ TCG_REG_T0,
+ TCG_REG_T1,
+ TCG_REG_T2,
+ TCG_REG_S0,
+ TCG_REG_S1,
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3,
+ TCG_REG_A4,
+ TCG_REG_A5,
+ TCG_REG_A6,
+ TCG_REG_A7,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_S8,
+ TCG_REG_S9,
+ TCG_REG_S10,
+ TCG_REG_S11,
+ TCG_REG_T3,
+ TCG_REG_T4,
+ TCG_REG_T5,
+ TCG_REG_T6,
+
+ /* aliases */
+ TCG_AREG0 = TCG_REG_S0,
+ TCG_GUEST_BASE_REG = TCG_REG_S1,
+ TCG_REG_TMP0 = TCG_REG_T6,
+ TCG_REG_TMP1 = TCG_REG_T5,
+ TCG_REG_TMP2 = TCG_REG_T4,
+} TCGReg;
+
+/* used for function call generation */
+#define TCG_REG_CALL_STACK TCG_REG_SP
+#define TCG_TARGET_STACK_ALIGN 16
+#define TCG_TARGET_CALL_ALIGN_ARGS 1
+#define TCG_TARGET_CALL_STACK_OFFSET 0
+
+/* optional instructions */
+#define TCG_TARGET_HAS_goto_ptr 1
+#define TCG_TARGET_HAS_movcond_i32 0
+#define TCG_TARGET_HAS_div_i32 1
+#define TCG_TARGET_HAS_rem_i32 1
+#define TCG_TARGET_HAS_div2_i32 0
+#define TCG_TARGET_HAS_rot_i32 0
+#define TCG_TARGET_HAS_deposit_i32 0
+#define TCG_TARGET_HAS_extract_i32 0
+#define TCG_TARGET_HAS_sextract_i32 0
+#define TCG_TARGET_HAS_add2_i32 1
+#define TCG_TARGET_HAS_sub2_i32 1
+#define TCG_TARGET_HAS_mulu2_i32 0
+#define TCG_TARGET_HAS_muls2_i32 0
+#define TCG_TARGET_HAS_muluh_i32 (TCG_TARGET_REG_BITS == 32)
+#define TCG_TARGET_HAS_mulsh_i32 (TCG_TARGET_REG_BITS == 32)
+#define TCG_TARGET_HAS_ext8s_i32 1
+#define TCG_TARGET_HAS_ext16s_i32 1
+#define TCG_TARGET_HAS_ext8u_i32 1
+#define TCG_TARGET_HAS_ext16u_i32 1
+#define TCG_TARGET_HAS_bswap16_i32 0
+#define TCG_TARGET_HAS_bswap32_i32 0
+#define TCG_TARGET_HAS_not_i32 1
+#define TCG_TARGET_HAS_neg_i32 1
+#define TCG_TARGET_HAS_andc_i32 0
+#define TCG_TARGET_HAS_orc_i32 0
+#define TCG_TARGET_HAS_eqv_i32 0
+#define TCG_TARGET_HAS_nand_i32 0
+#define TCG_TARGET_HAS_nor_i32 0
+#define TCG_TARGET_HAS_clz_i32 0
+#define TCG_TARGET_HAS_ctz_i32 0
+#define TCG_TARGET_HAS_ctpop_i32 0
+#define TCG_TARGET_HAS_direct_jump 0
+#define TCG_TARGET_HAS_brcond2 1
+#define TCG_TARGET_HAS_setcond2 1
+
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_movcond_i64 0
+#define TCG_TARGET_HAS_div_i64 1
+#define TCG_TARGET_HAS_rem_i64 1
+#define TCG_TARGET_HAS_div2_i64 0
+#define TCG_TARGET_HAS_rot_i64 0
+#define TCG_TARGET_HAS_deposit_i64 0
+#define TCG_TARGET_HAS_extract_i64 0
+#define TCG_TARGET_HAS_sextract_i64 0
+#define TCG_TARGET_HAS_extrl_i64_i32 1
+#define TCG_TARGET_HAS_extrh_i64_i32 1
+#define TCG_TARGET_HAS_ext8s_i64 1
+#define TCG_TARGET_HAS_ext16s_i64 1
+#define TCG_TARGET_HAS_ext32s_i64 1
+#define TCG_TARGET_HAS_ext8u_i64 1
+#define TCG_TARGET_HAS_ext16u_i64 1
+#define TCG_TARGET_HAS_ext32u_i64 1
+#define TCG_TARGET_HAS_bswap16_i64 0
+#define TCG_TARGET_HAS_bswap32_i64 0
+#define TCG_TARGET_HAS_bswap64_i64 0
+#define TCG_TARGET_HAS_not_i64 1
+#define TCG_TARGET_HAS_neg_i64 1
+#define TCG_TARGET_HAS_andc_i64 0
+#define TCG_TARGET_HAS_orc_i64 0
+#define TCG_TARGET_HAS_eqv_i64 0
+#define TCG_TARGET_HAS_nand_i64 0
+#define TCG_TARGET_HAS_nor_i64 0
+#define TCG_TARGET_HAS_clz_i64 0
+#define TCG_TARGET_HAS_ctz_i64 0
+#define TCG_TARGET_HAS_ctpop_i64 0
+#define TCG_TARGET_HAS_add2_i64 1
+#define TCG_TARGET_HAS_sub2_i64 1
+#define TCG_TARGET_HAS_mulu2_i64 0
+#define TCG_TARGET_HAS_muls2_i64 0
+#define TCG_TARGET_HAS_muluh_i64 1
+#define TCG_TARGET_HAS_mulsh_i64 1
+#endif
+
+static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
+{
+ __builtin___clear_cache((char *)start, (char *)stop);
+}
+
+/* not defined -- call should be eliminated at compile time */
+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t);
+
+#define TCG_TARGET_DEFAULT_MO (0)
+
+#ifdef CONFIG_SOFTMMU
+#define TCG_TARGET_NEED_LDST_LABELS
+#endif
+#define TCG_TARGET_NEED_POOL_LABELS
+
+#define TCG_TARGET_HAS_MEMORY_BSWAP 0
+
+#endif
diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c
new file mode 100644
index 0000000000..6cf8de32b5
--- /dev/null
+++ b/tcg/riscv/tcg-target.inc.c
@@ -0,0 +1,1949 @@
+/*
+ * Tiny Code Generator for QEMU
+ *
+ * Copyright (c) 2018 SiFive, Inc
+ * Copyright (c) 2008-2009 Arnaud Patard <arnaud.patard@rtp-net.org>
+ * Copyright (c) 2009 Aurelien Jarno <aurelien@aurel32.net>
+ * Copyright (c) 2008 Fabrice Bellard
+ *
+ * Based on i386/tcg-target.c and mips/tcg-target.c
+ *
+ * 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 "tcg-pool.inc.c"
+
+#ifdef CONFIG_DEBUG_TCG
+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
+ "zero",
+ "ra",
+ "sp",
+ "gp",
+ "tp",
+ "t0",
+ "t1",
+ "t2",
+ "s0",
+ "s1",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "a4",
+ "a5",
+ "a6",
+ "a7",
+ "s2",
+ "s3",
+ "s4",
+ "s5",
+ "s6",
+ "s7",
+ "s8",
+ "s9",
+ "s10",
+ "s11",
+ "t3",
+ "t4",
+ "t5",
+ "t6"
+};
+#endif
+
+static const int tcg_target_reg_alloc_order[] = {
+ /* Call saved registers */
+ /* TCG_REG_S0 reservered for TCG_AREG0 */
+ TCG_REG_S1,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_S8,
+ TCG_REG_S9,
+ TCG_REG_S10,
+ TCG_REG_S11,
+
+ /* Call clobbered registers */
+ TCG_REG_T0,
+ TCG_REG_T1,
+ TCG_REG_T2,
+ TCG_REG_T3,
+ TCG_REG_T4,
+ TCG_REG_T5,
+ TCG_REG_T6,
+
+ /* Argument registers */
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3,
+ TCG_REG_A4,
+ TCG_REG_A5,
+ TCG_REG_A6,
+ TCG_REG_A7,
+};
+
+static const int tcg_target_call_iarg_regs[] = {
+ TCG_REG_A0,
+ TCG_REG_A1,
+ TCG_REG_A2,
+ TCG_REG_A3,
+ TCG_REG_A4,
+ TCG_REG_A5,
+ TCG_REG_A6,
+ TCG_REG_A7,
+};
+
+static const int tcg_target_call_oarg_regs[] = {
+ TCG_REG_A0,
+ TCG_REG_A1,
+};
+
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_S12 0x200
+#define TCG_CT_CONST_N12 0x400
+#define TCG_CT_CONST_M12 0x800
+
+static inline tcg_target_long sextreg(tcg_target_long val, int pos, int len)
+{
+ if (TCG_TARGET_REG_BITS == 32) {
+ return sextract32(val, pos, len);
+ } else {
+ return sextract64(val, pos, len);
+ }
+}
+
+/* parse target specific constraints */
+static const char *target_parse_constraint(TCGArgConstraint *ct,
+ const char *ct_str, TCGType type)
+{
+ switch (*ct_str++) {
+ case 'r':
+ ct->ct |= TCG_CT_REG;
+ ct->u.regs = 0xffffffff;
+ break;
+ case 'L':
+ /* qemu_ld/qemu_st constraint */
+ ct->ct |= TCG_CT_REG;
+ ct->u.regs = 0xffffffff;
+ /* qemu_ld/qemu_st uses TCG_REG_TMP0 */
+#if defined(CONFIG_SOFTMMU)
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[0]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[1]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[2]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[3]);
+ tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[4]);
+#endif
+ break;
+ case 'I':
+ ct->ct |= TCG_CT_CONST_S12;
+ break;
+ case 'N':
+ ct->ct |= TCG_CT_CONST_N12;
+ break;
+ case 'M':
+ ct->ct |= TCG_CT_CONST_M12;
+ break;
+ case 'Z':
+ /* we can use a zero immediate as a zero register argument. */
+ ct->ct |= TCG_CT_CONST_ZERO;
+ break;
+ default:
+ return NULL;
+ }
+ return ct_str;
+}
+
+/* test if a constant matches the constraint */
+static int tcg_target_const_match(tcg_target_long val, TCGType type,
+ const TCGArgConstraint *arg_ct)
+{
+ int ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_S12) && val == sextreg(val, 0, 12)) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_N12) && -val == sextreg(-val, 0, 12)) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_M12) && val >= -0xfff && val <= 0xfff) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * RISC-V Base ISA opcodes (IM)
+ */
+
+typedef enum {
+ OPC_ADD = 0x33,
+ OPC_ADDI = 0x13,
+ OPC_AND = 0x7033,
+ OPC_ANDI = 0x7013,
+ OPC_AUIPC = 0x17,
+ OPC_BEQ = 0x63,
+ OPC_BGE = 0x5063,
+ OPC_BGEU = 0x7063,
+ OPC_BLT = 0x4063,
+ OPC_BLTU = 0x6063,
+ OPC_BNE = 0x1063,
+ OPC_DIV = 0x2004033,
+ OPC_DIVU = 0x2005033,
+ OPC_JAL = 0x6f,
+ OPC_JALR = 0x67,
+ OPC_LB = 0x3,
+ OPC_LBU = 0x4003,
+ OPC_LD = 0x3003,
+ OPC_LH = 0x1003,
+ OPC_LHU = 0x5003,
+ OPC_LUI = 0x37,
+ OPC_LW = 0x2003,
+ OPC_LWU = 0x6003,
+ OPC_MUL = 0x2000033,
+ OPC_MULH = 0x2001033,
+ OPC_MULHSU = 0x2002033,
+ OPC_MULHU = 0x2003033,
+ OPC_OR = 0x6033,
+ OPC_ORI = 0x6013,
+ OPC_REM = 0x2006033,
+ OPC_REMU = 0x2007033,
+ OPC_SB = 0x23,
+ OPC_SD = 0x3023,
+ OPC_SH = 0x1023,
+ OPC_SLL = 0x1033,
+ OPC_SLLI = 0x1013,
+ OPC_SLT = 0x2033,
+ OPC_SLTI = 0x2013,
+ OPC_SLTIU = 0x3013,
+ OPC_SLTU = 0x3033,
+ OPC_SRA = 0x40005033,
+ OPC_SRAI = 0x40005013,
+ OPC_SRL = 0x5033,
+ OPC_SRLI = 0x5013,
+ OPC_SUB = 0x40000033,
+ OPC_SW = 0x2023,
+ OPC_XOR = 0x4033,
+ OPC_XORI = 0x4013,
+
+#if TCG_TARGET_REG_BITS == 64
+ OPC_ADDIW = 0x1b,
+ OPC_ADDW = 0x3b,
+ OPC_DIVUW = 0x200503b,
+ OPC_DIVW = 0x200403b,
+ OPC_MULW = 0x200003b,
+ OPC_REMUW = 0x200703b,
+ OPC_REMW = 0x200603b,
+ OPC_SLLIW = 0x101b,
+ OPC_SLLW = 0x103b,
+ OPC_SRAIW = 0x4000501b,
+ OPC_SRAW = 0x4000503b,
+ OPC_SRLIW = 0x501b,
+ OPC_SRLW = 0x503b,
+ OPC_SUBW = 0x4000003b,
+#else
+ /* Simplify code throughout by defining aliases for RV32. */
+ OPC_ADDIW = OPC_ADDI,
+ OPC_ADDW = OPC_ADD,
+ OPC_DIVUW = OPC_DIVU,
+ OPC_DIVW = OPC_DIV,
+ OPC_MULW = OPC_MUL,
+ OPC_REMUW = OPC_REMU,
+ OPC_REMW = OPC_REM,
+ OPC_SLLIW = OPC_SLLI,
+ OPC_SLLW = OPC_SLL,
+ OPC_SRAIW = OPC_SRAI,
+ OPC_SRAW = OPC_SRA,
+ OPC_SRLIW = OPC_SRLI,
+ OPC_SRLW = OPC_SRL,
+ OPC_SUBW = OPC_SUB,
+#endif
+
+ OPC_FENCE = 0x0000000f,
+} RISCVInsn;
+
+/*
+ * RISC-V immediate and instruction encoders (excludes 16-bit RVC)
+ */
+
+/* Type-R */
+
+static int32_t encode_r(RISCVInsn opc, TCGReg rd, TCGReg rs1, TCGReg rs2)
+{
+ return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20;
+}
+
+/* Type-I */
+
+static int32_t encode_imm12(uint32_t imm)
+{
+ return (imm & 0xfff) << 20;
+}
+
+static int32_t encode_i(RISCVInsn opc, TCGReg rd, TCGReg rs1, uint32_t imm)
+{
+ return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | encode_imm12(imm);
+}
+
+/* Type-S */
+
+static int32_t encode_simm12(uint32_t imm)
+{
+ int32_t ret = 0;
+
+ ret |= (imm & 0xFE0) << 20;
+ ret |= (imm & 0x1F) << 7;
+
+ return ret;
+}
+
+static int32_t encode_s(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm)
+{
+ return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_simm12(imm);
+}
+
+/* Type-SB */
+
+static int32_t encode_sbimm12(uint32_t imm)
+{
+ int32_t ret = 0;
+
+ ret |= (imm & 0x1000) << 19;
+ ret |= (imm & 0x7e0) << 20;
+ ret |= (imm & 0x1e) << 7;
+ ret |= (imm & 0x800) >> 4;
+
+ return ret;
+}
+
+static int32_t encode_sb(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm)
+{
+ return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_sbimm12(imm);
+}
+
+/* Type-U */
+
+static int32_t encode_uimm20(uint32_t imm)
+{
+ return imm & 0xfffff000;
+}
+
+static int32_t encode_u(RISCVInsn opc, TCGReg rd, uint32_t imm)
+{
+ return opc | (rd & 0x1f) << 7 | encode_uimm20(imm);
+}
+
+/* Type-UJ */
+
+static int32_t encode_ujimm20(uint32_t imm)
+{
+ int32_t ret = 0;
+
+ ret |= (imm & 0x0007fe) << (21 - 1);
+ ret |= (imm & 0x000800) << (20 - 11);
+ ret |= (imm & 0x0ff000) << (12 - 12);
+ ret |= (imm & 0x100000) << (31 - 20);
+
+ return ret;
+}
+
+static int32_t encode_uj(RISCVInsn opc, TCGReg rd, uint32_t imm)
+{
+ return opc | (rd & 0x1f) << 7 | encode_ujimm20(imm);
+}
+
+/*
+ * RISC-V instruction emitters
+ */
+
+static void tcg_out_opc_reg(TCGContext *s, RISCVInsn opc,
+ TCGReg rd, TCGReg rs1, TCGReg rs2)
+{
+ tcg_out32(s, encode_r(opc, rd, rs1, rs2));
+}
+
+static void tcg_out_opc_imm(TCGContext *s, RISCVInsn opc,
+ TCGReg rd, TCGReg rs1, TCGArg imm)
+{
+ tcg_out32(s, encode_i(opc, rd, rs1, imm));
+}
+
+static void tcg_out_opc_store(TCGContext *s, RISCVInsn opc,
+ TCGReg rs1, TCGReg rs2, uint32_t imm)
+{
+ tcg_out32(s, encode_s(opc, rs1, rs2, imm));
+}
+
+static void tcg_out_opc_branch(TCGContext *s, RISCVInsn opc,
+ TCGReg rs1, TCGReg rs2, uint32_t imm)
+{
+ tcg_out32(s, encode_sb(opc, rs1, rs2, imm));
+}
+
+static void tcg_out_opc_upper(TCGContext *s, RISCVInsn opc,
+ TCGReg rd, uint32_t imm)
+{
+ tcg_out32(s, encode_u(opc, rd, imm));
+}
+
+static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc,
+ TCGReg rd, uint32_t imm)
+{
+ tcg_out32(s, encode_uj(opc, rd, imm));
+}
+
+static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
+{
+ int i;
+ for (i = 0; i < count; ++i) {
+ p[i] = encode_i(OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+ }
+}
+
+/*
+ * Relocations
+ */
+
+static bool reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+{
+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
+
+ if (offset == sextreg(offset, 1, 12) << 1) {
+ code_ptr[0] |= encode_sbimm12(offset);
+ return true;
+ }
+
+ return false;
+}
+
+static bool reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+{
+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
+
+ if (offset == sextreg(offset, 1, 20) << 1) {
+ code_ptr[0] |= encode_ujimm20(offset);
+ return true;
+ }
+
+ return false;
+}
+
+static bool reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
+{
+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr;
+ int32_t lo = sextreg(offset, 0, 12);
+ int32_t hi = offset - lo;
+
+ if (offset == hi + lo) {
+ code_ptr[0] |= encode_uimm20(hi);
+ code_ptr[1] |= encode_imm12(lo);
+ return true;
+ }
+
+ return false;
+}
+
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
+ intptr_t value, intptr_t addend)
+{
+ uint32_t insn = *code_ptr;
+ intptr_t diff;
+ bool short_jmp;
+
+ tcg_debug_assert(addend == 0);
+
+ switch (type) {
+ case R_RISCV_BRANCH:
+ diff = value - (uintptr_t)code_ptr;
+ short_jmp = diff == sextreg(diff, 0, 12);
+ if (short_jmp) {
+ return reloc_sbimm12(code_ptr, (tcg_insn_unit *)value);
+ } else {
+ /* Invert the condition */
+ insn = insn ^ (1 << 12);
+ /* Clear the offset */
+ insn &= 0x01fff07f;
+ /* Set the offset to the PC + 8 */
+ insn |= encode_sbimm12(8);
+
+ /* Move forward */
+ code_ptr[0] = insn;
+
+ /* Overwrite the NOP with jal x0,value */
+ diff = value - (uintptr_t)(code_ptr + 1);
+ insn = encode_uj(OPC_JAL, TCG_REG_ZERO, diff);
+ code_ptr[1] = insn;
+
+ return true;
+ }
+ break;
+ case R_RISCV_JAL:
+ return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
+ break;
+ case R_RISCV_CALL:
+ return reloc_call(code_ptr, (tcg_insn_unit *)value);
+ break;
+ default:
+ tcg_abort();
+ }
+}
+
+/*
+ * TCG intrinsics
+ */
+
+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
+{
+ if (ret == arg) {
+ return;
+ }
+ switch (type) {
+ case TCG_TYPE_I32:
+ case TCG_TYPE_I64:
+ tcg_out_opc_imm(s, OPC_ADDI, ret, arg, 0);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
+ tcg_target_long val)
+{
+ tcg_target_long lo, hi, tmp;
+ int shift, ret;
+
+ if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) {
+ val = (int32_t)val;
+ }
+
+ lo = sextreg(val, 0, 12);
+ if (val == lo) {
+ tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, lo);
+ return;
+ }
+
+ hi = val - lo;
+ if (TCG_TARGET_REG_BITS == 32 || val == (int32_t)val) {
+ tcg_out_opc_upper(s, OPC_LUI, rd, hi);
+ if (lo != 0) {
+ tcg_out_opc_imm(s, OPC_ADDIW, rd, rd, lo);
+ }
+ return;
+ }
+
+ /* We can only be here if TCG_TARGET_REG_BITS != 32 */
+ tmp = tcg_pcrel_diff(s, (void *)val);
+ if (tmp == (int32_t)tmp) {
+ tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
+ tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0);
+ ret = reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val);
+ tcg_debug_assert(ret == true);
+ return;
+ }
+
+ /* Look for a single 20-bit section. */
+ shift = ctz64(val);
+ tmp = val >> shift;
+ if (tmp == sextreg(tmp, 0, 20)) {
+ tcg_out_opc_upper(s, OPC_LUI, rd, tmp << 12);
+ if (shift > 12) {
+ tcg_out_opc_imm(s, OPC_SLLI, rd, rd, shift - 12);
+ } else {
+ tcg_out_opc_imm(s, OPC_SRAI, rd, rd, 12 - shift);
+ }
+ return;
+ }
+
+ /* Look for a few high zero bits, with lots of bits set in the middle. */
+ shift = clz64(val);
+ tmp = val << shift;
+ if (tmp == sextreg(tmp, 12, 20) << 12) {
+ tcg_out_opc_upper(s, OPC_LUI, rd, tmp);
+ tcg_out_opc_imm(s, OPC_SRLI, rd, rd, shift);
+ return;
+ } else if (tmp == sextreg(tmp, 0, 12)) {
+ tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, tmp);
+ tcg_out_opc_imm(s, OPC_SRLI, rd, rd, shift);
+ return;
+ }
+
+ /* Drop into the constant pool. */
+ new_pool_label(s, val, R_RISCV_CALL, s->code_ptr, 0);
+ tcg_out_opc_upper(s, OPC_AUIPC, rd, 0);
+ tcg_out_opc_imm(s, OPC_LD, rd, rd, 0);
+}
+
+static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_ANDI, ret, arg, 0xff);
+}
+
+static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
+ tcg_out_opc_imm(s, OPC_SRLIW, ret, ret, 16);
+}
+
+static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_SLLI, ret, arg, 32);
+ tcg_out_opc_imm(s, OPC_SRLI, ret, ret, 32);
+}
+
+static void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 24);
+ tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 24);
+}
+
+static void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_SLLIW, ret, arg, 16);
+ tcg_out_opc_imm(s, OPC_SRAIW, ret, ret, 16);
+}
+
+static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg)
+{
+ tcg_out_opc_imm(s, OPC_ADDIW, ret, arg, 0);
+}
+
+static void tcg_out_ldst(TCGContext *s, RISCVInsn opc, TCGReg data,
+ TCGReg addr, intptr_t offset)
+{
+ intptr_t imm12 = sextreg(offset, 0, 12);
+
+ if (offset != imm12) {
+ intptr_t diff = offset - (uintptr_t)s->code_ptr;
+
+ if (addr == TCG_REG_ZERO && diff == (int32_t)diff) {
+ imm12 = sextreg(diff, 0, 12);
+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP2, diff - imm12);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP2, offset - imm12);
+ if (addr != TCG_REG_ZERO) {
+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, addr);
+ }
+ }
+ addr = TCG_REG_TMP2;
+ }
+
+ switch (opc) {
+ case OPC_SB:
+ case OPC_SH:
+ case OPC_SW:
+ case OPC_SD:
+ tcg_out_opc_store(s, opc, addr, data, imm12);
+ break;
+ case OPC_LB:
+ case OPC_LBU:
+ case OPC_LH:
+ case OPC_LHU:
+ case OPC_LW:
+ case OPC_LWU:
+ case OPC_LD:
+ tcg_out_opc_imm(s, opc, data, addr, imm12);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
+ TCGReg arg1, intptr_t arg2)
+{
+ bool is32bit = (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32);
+ tcg_out_ldst(s, is32bit ? OPC_LW : OPC_LD, arg, arg1, arg2);
+}
+
+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
+ TCGReg arg1, intptr_t arg2)
+{
+ bool is32bit = (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32);
+ tcg_out_ldst(s, is32bit ? OPC_SW : OPC_SD, arg, arg1, arg2);
+}
+
+static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
+ TCGReg base, intptr_t ofs)
+{
+ if (val == 0) {
+ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs);
+ return true;
+ }
+ return false;
+}
+
+static void tcg_out_addsub2(TCGContext *s,
+ TCGReg rl, TCGReg rh,
+ TCGReg al, TCGReg ah,
+ TCGArg bl, TCGArg bh,
+ bool cbl, bool cbh, bool is_sub, bool is32bit)
+{
+ const RISCVInsn opc_add = is32bit ? OPC_ADDW : OPC_ADD;
+ const RISCVInsn opc_addi = is32bit ? OPC_ADDIW : OPC_ADDI;
+ const RISCVInsn opc_sub = is32bit ? OPC_SUBW : OPC_SUB;
+ TCGReg th = TCG_REG_TMP1;
+
+ /* If we have a negative constant such that negating it would
+ make the high part zero, we can (usually) eliminate one insn. */
+ if (cbl && cbh && bh == -1 && bl != 0) {
+ bl = -bl;
+ bh = 0;
+ is_sub = !is_sub;
+ }
+
+ /* By operating on the high part first, we get to use the final
+ carry operation to move back from the temporary. */
+ if (!cbh) {
+ tcg_out_opc_reg(s, (is_sub ? opc_sub : opc_add), th, ah, bh);
+ } else if (bh != 0 || ah == rl) {
+ tcg_out_opc_imm(s, opc_addi, th, ah, (is_sub ? -bh : bh));
+ } else {
+ th = ah;
+ }
+
+ /* Note that tcg optimization should eliminate the bl == 0 case. */
+ if (is_sub) {
+ if (cbl) {
+ tcg_out_opc_imm(s, OPC_SLTIU, TCG_REG_TMP0, al, bl);
+ tcg_out_opc_imm(s, opc_addi, rl, al, -bl);
+ } else {
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_TMP0, al, bl);
+ tcg_out_opc_reg(s, opc_sub, rl, al, bl);
+ }
+ tcg_out_opc_reg(s, opc_sub, rh, th, TCG_REG_TMP0);
+ } else {
+ if (cbl) {
+ tcg_out_opc_imm(s, opc_addi, rl, al, bl);
+ tcg_out_opc_imm(s, OPC_SLTIU, TCG_REG_TMP0, rl, bl);
+ } else if (rl == al && rl == bl) {
+ tcg_out_opc_imm(s, OPC_SLTI, TCG_REG_TMP0, al, 0);
+ tcg_out_opc_reg(s, opc_addi, rl, al, bl);
+ } else {
+ tcg_out_opc_reg(s, opc_add, rl, al, bl);
+ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_TMP0,
+ rl, (rl == bl ? al : bl));
+ }
+ tcg_out_opc_reg(s, opc_add, rh, th, TCG_REG_TMP0);
+ }
+}
+
+static const struct {
+ RISCVInsn op;
+ bool swap;
+} tcg_brcond_to_riscv[] = {
+ [TCG_COND_EQ] = { OPC_BEQ, false },
+ [TCG_COND_NE] = { OPC_BNE, false },
+ [TCG_COND_LT] = { OPC_BLT, false },
+ [TCG_COND_GE] = { OPC_BGE, false },
+ [TCG_COND_LE] = { OPC_BGE, true },
+ [TCG_COND_GT] = { OPC_BLT, true },
+ [TCG_COND_LTU] = { OPC_BLTU, false },
+ [TCG_COND_GEU] = { OPC_BGEU, false },
+ [TCG_COND_LEU] = { OPC_BGEU, true },
+ [TCG_COND_GTU] = { OPC_BLTU, true }
+};
+
+static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1,
+ TCGReg arg2, TCGLabel *l)
+{
+ RISCVInsn op = tcg_brcond_to_riscv[cond].op;
+
+ tcg_debug_assert(op != 0);
+
+ if (tcg_brcond_to_riscv[cond].swap) {
+ TCGReg t = arg1;
+ arg1 = arg2;
+ arg2 = t;
+ }
+
+ if (l->has_value) {
+ intptr_t diff = tcg_pcrel_diff(s, l->u.value_ptr);
+ if (diff == sextreg(diff, 0, 12)) {
+ tcg_out_opc_branch(s, op, arg1, arg2, diff);
+ } else {
+ /* Invert the conditional branch. */
+ tcg_out_opc_branch(s, op ^ (1 << 12), arg1, arg2, 8);
+ tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, diff - 4);
+ }
+ } else {
+ tcg_out_reloc(s, s->code_ptr, R_RISCV_BRANCH, l, 0);
+ tcg_out_opc_branch(s, op, arg1, arg2, 0);
+ /* NOP to allow patching later */
+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+ }
+}
+
+static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg arg1, TCGReg arg2)
+{
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1);
+ break;
+ case TCG_COND_NE:
+ tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2);
+ tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret);
+ break;
+ case TCG_COND_LT:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+ break;
+ case TCG_COND_GE:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_LE:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_GT:
+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1);
+ break;
+ case TCG_COND_LTU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+ break;
+ case TCG_COND_GEU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_LEU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1);
+ break;
+ case TCG_COND_GTU:
+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1);
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah,
+ TCGReg bl, TCGReg bh, TCGLabel *l)
+{
+ /* todo */
+ g_assert_not_reached();
+}
+
+static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret,
+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh)
+{
+ /* todo */
+ g_assert_not_reached();
+}
+
+static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
+{
+ ptrdiff_t offset = tcg_pcrel_diff(s, target);
+ tcg_debug_assert(offset == sextreg(offset, 1, 20) << 1);
+ tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, offset);
+}
+
+static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail)
+{
+ TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
+ ptrdiff_t offset = tcg_pcrel_diff(s, arg);
+ int ret;
+
+ if (offset == sextreg(offset, 1, 20) << 1) {
+ /* short jump: -2097150 to 2097152 */
+ tcg_out_opc_jump(s, OPC_JAL, link, offset);
+ } else if (TCG_TARGET_REG_BITS == 32 ||
+ offset == sextreg(offset, 1, 31) << 1) {
+ /* long jump: -2147483646 to 2147483648 */
+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0);
+ tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0);
+ ret = reloc_call(s->code_ptr - 2, arg);\
+ tcg_debug_assert(ret == true);
+ } else if (TCG_TARGET_REG_BITS == 64) {
+ /* far jump: 64-bit */
+ tcg_target_long imm = sextreg((tcg_target_long)arg, 0, 12);
+ tcg_target_long base = (tcg_target_long)arg - imm;
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, base);
+ tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, imm);
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg)
+{
+ tcg_out_call_int(s, arg, false);
+}
+
+static void tcg_out_mb(TCGContext *s, TCGArg a0)
+{
+ tcg_insn_unit insn = OPC_FENCE;
+
+ if (a0 & TCG_MO_LD_LD) {
+ insn |= 0x02200000;
+ }
+ if (a0 & TCG_MO_ST_LD) {
+ insn |= 0x01200000;
+ }
+ if (a0 & TCG_MO_LD_ST) {
+ insn |= 0x02100000;
+ }
+ if (a0 & TCG_MO_ST_ST) {
+ insn |= 0x02200000;
+ }
+ tcg_out32(s, insn);
+}
+
+/*
+ * Load/store and TLB
+ */
+
+#if defined(CONFIG_SOFTMMU)
+#include "tcg-ldst.inc.c"
+
+/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
+ * TCGMemOpIdx oi, uintptr_t ra)
+ */
+static void * const qemu_ld_helpers[16] = {
+ [MO_UB] = helper_ret_ldub_mmu,
+ [MO_SB] = helper_ret_ldsb_mmu,
+ [MO_LEUW] = helper_le_lduw_mmu,
+ [MO_LESW] = helper_le_ldsw_mmu,
+ [MO_LEUL] = helper_le_ldul_mmu,
+#if TCG_TARGET_REG_BITS == 64
+ [MO_LESL] = helper_le_ldsl_mmu,
+#endif
+ [MO_LEQ] = helper_le_ldq_mmu,
+ [MO_BEUW] = helper_be_lduw_mmu,
+ [MO_BESW] = helper_be_ldsw_mmu,
+ [MO_BEUL] = helper_be_ldul_mmu,
+#if TCG_TARGET_REG_BITS == 64
+ [MO_BESL] = helper_be_ldsl_mmu,
+#endif
+ [MO_BEQ] = helper_be_ldq_mmu,
+};
+
+/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
+ * uintxx_t val, TCGMemOpIdx oi,
+ * uintptr_t ra)
+ */
+static void * const qemu_st_helpers[16] = {
+ [MO_UB] = helper_ret_stb_mmu,
+ [MO_LEUW] = helper_le_stw_mmu,
+ [MO_LEUL] = helper_le_stl_mmu,
+ [MO_LEQ] = helper_le_stq_mmu,
+ [MO_BEUW] = helper_be_stw_mmu,
+ [MO_BEUL] = helper_be_stl_mmu,
+ [MO_BEQ] = helper_be_stq_mmu,
+};
+
+static void tcg_out_tlb_load(TCGContext *s, TCGReg addrl,
+ TCGReg addrh, TCGMemOpIdx oi,
+ tcg_insn_unit **label_ptr, bool is_load)
+{
+ TCGMemOp opc = get_memop(oi);
+ unsigned s_bits = opc & MO_SIZE;
+ unsigned a_bits = get_alignment_bits(opc);
+ target_ulong mask;
+ int mem_index = get_mmuidx(oi);
+ int cmp_off
+ = (is_load
+ ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
+ : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
+ int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
+ RISCVInsn load_cmp_op = (TARGET_LONG_BITS == 64 ? OPC_LD :
+ TCG_TARGET_REG_BITS == 64 ? OPC_LWU : OPC_LW);
+ RISCVInsn load_add_op = TCG_TARGET_REG_BITS == 64 ? OPC_LD : OPC_LW;
+ TCGReg base = TCG_AREG0;
+
+ /* We don't support oversize guests */
+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
+ g_assert_not_reached();
+ }
+
+ /* We don't support unaligned accesses. */
+ if (a_bits < s_bits) {
+ a_bits = s_bits;
+ }
+ mask = (target_ulong)TARGET_PAGE_MASK | ((1 << a_bits) - 1);
+
+
+ /* Compensate for very large offsets. */
+ if (add_off >= 0x1000) {
+ int adj;
+ base = TCG_REG_TMP2;
+ if (cmp_off <= 2 * 0xfff) {
+ adj = 0xfff;
+ tcg_out_opc_imm(s, OPC_ADDI, base, TCG_AREG0, adj);
+ } else {
+ adj = cmp_off - sextreg(cmp_off, 0, 12);
+ tcg_debug_assert(add_off - adj >= -0x1000
+ && add_off - adj < 0x1000);
+
+ tcg_out_opc_upper(s, OPC_LUI, base, adj);
+ tcg_out_opc_reg(s, OPC_ADD, base, base, TCG_AREG0);
+ }
+ add_off -= adj;
+ cmp_off -= adj;
+ }
+
+ /* Extract the page index. */
+ if (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS < 12) {
+ tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP0, addrl,
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP0, TCG_REG_TMP0,
+ MAKE_64BIT_MASK(CPU_TLB_ENTRY_BITS, CPU_TLB_BITS));
+ } else if (TARGET_PAGE_BITS >= 12) {
+ tcg_out_opc_upper(s, OPC_LUI, TCG_REG_TMP0,
+ MAKE_64BIT_MASK(TARGET_PAGE_BITS, CPU_TLB_BITS));
+ tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP0, TCG_REG_TMP0, addrl);
+ tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP0, TCG_REG_TMP0,
+ CPU_TLB_BITS - CPU_TLB_ENTRY_BITS);
+ } else {
+ tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP0, addrl, TARGET_PAGE_BITS);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP0, TCG_REG_TMP0,
+ MAKE_64BIT_MASK(0, CPU_TLB_BITS));
+ tcg_out_opc_imm(s, OPC_SLLI, TCG_REG_TMP0, TCG_REG_TMP0,
+ CPU_TLB_ENTRY_BITS);
+ }
+
+ /* Add that to the base address to index the tlb. */
+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, base, TCG_REG_TMP0);
+ base = TCG_REG_TMP2;
+
+ /* Load the tlb comparator and the addend. */
+ tcg_out_ldst(s, load_cmp_op, TCG_REG_TMP0, base, cmp_off);
+ tcg_out_ldst(s, load_add_op, TCG_REG_TMP2, base, add_off);
+
+ /* Clear the non-page, non-alignment bits from the address. */
+ if (mask == sextreg(mask, 0, 12)) {
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addrl, mask);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_TMP1, mask);
+ tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addrl);
+ }
+
+ /* Compare masked address with the TLB entry. */
+ label_ptr[0] = s->code_ptr;
+ tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP0, TCG_REG_TMP1, 0);
+ /* NOP to allow patching later */
+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_ZERO, TCG_REG_ZERO, 0);
+ /* TODO: Move this out of line
+ * see:
+ * https://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg02234.html
+ */
+
+ /* TLB Hit - translate address using addend. */
+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
+ tcg_out_ext32u(s, TCG_REG_TMP0, addrl);
+ addrl = TCG_REG_TMP0;
+ }
+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP2, addrl);
+}
+
+static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi,
+ TCGType ext,
+ TCGReg datalo, TCGReg datahi,
+ TCGReg addrlo, TCGReg addrhi,
+ void *raddr, tcg_insn_unit **label_ptr)
+{
+ TCGLabelQemuLdst *label = new_ldst_label(s);
+
+ label->is_ld = is_ld;
+ label->oi = oi;
+ label->type = ext;
+ label->datalo_reg = datalo;
+ label->datahi_reg = datahi;
+ label->addrlo_reg = addrlo;
+ label->addrhi_reg = addrhi;
+ label->raddr = raddr;
+ label->label_ptr[0] = label_ptr[0];
+}
+
+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ TCGMemOpIdx oi = l->oi;
+ TCGMemOp opc = get_memop(oi);
+ TCGReg a0 = tcg_target_call_iarg_regs[0];
+ TCGReg a1 = tcg_target_call_iarg_regs[1];
+ TCGReg a2 = tcg_target_call_iarg_regs[2];
+ TCGReg a3 = tcg_target_call_iarg_regs[3];
+
+ /* We don't support oversize guests */
+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
+ g_assert_not_reached();
+ }
+
+ /* resolve label address */
+ patch_reloc(l->label_ptr[0], R_RISCV_BRANCH, (intptr_t) s->code_ptr, 0);
+
+ /* call load helper */
+ tcg_out_mov(s, TCG_TYPE_PTR, a0, TCG_AREG0);
+ tcg_out_mov(s, TCG_TYPE_PTR, a1, l->addrlo_reg);
+ tcg_out_movi(s, TCG_TYPE_PTR, a2, oi);
+ tcg_out_movi(s, TCG_TYPE_PTR, a3, (tcg_target_long)l->raddr);
+
+ tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]);
+ tcg_out_mov(s, (opc & MO_SIZE) == MO_64, l->datalo_reg, a0);
+
+ tcg_out_goto(s, l->raddr);
+}
+
+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ TCGMemOpIdx oi = l->oi;
+ TCGMemOp opc = get_memop(oi);
+ TCGMemOp s_bits = opc & MO_SIZE;
+ TCGReg a0 = tcg_target_call_iarg_regs[0];
+ TCGReg a1 = tcg_target_call_iarg_regs[1];
+ TCGReg a2 = tcg_target_call_iarg_regs[2];
+ TCGReg a3 = tcg_target_call_iarg_regs[3];
+ TCGReg a4 = tcg_target_call_iarg_regs[4];
+
+ /* We don't support oversize guests */
+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
+ g_assert_not_reached();
+ }
+
+ /* resolve label address */
+ patch_reloc(l->label_ptr[0], R_RISCV_BRANCH, (intptr_t) s->code_ptr, 0);
+
+ /* call store helper */
+ tcg_out_mov(s, TCG_TYPE_PTR, a0, TCG_AREG0);
+ tcg_out_mov(s, TCG_TYPE_PTR, a1, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, a2, l->datalo_reg);
+ switch (s_bits) {
+ case MO_8:
+ tcg_out_ext8u(s, a2, a2);
+ break;
+ case MO_16:
+ tcg_out_ext16u(s, a2, a2);
+ break;
+ default:
+ break;
+ }
+ tcg_out_movi(s, TCG_TYPE_PTR, a3, oi);
+ tcg_out_movi(s, TCG_TYPE_PTR, a4, (tcg_target_long)l->raddr);
+
+ tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SSIZE)]);
+
+ tcg_out_goto(s, l->raddr);
+}
+#endif /* CONFIG_SOFTMMU */
+
+static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
+ TCGReg base, TCGMemOp opc, bool is_64)
+{
+ const TCGMemOp bswap = opc & MO_BSWAP;
+
+ /* We don't yet handle byteswapping, assert */
+ g_assert(!bswap);
+
+ switch (opc & (MO_SSIZE)) {
+ case MO_UB:
+ tcg_out_opc_imm(s, OPC_LBU, lo, base, 0);
+ break;
+ case MO_SB:
+ tcg_out_opc_imm(s, OPC_LB, lo, base, 0);
+ break;
+ case MO_UW:
+ tcg_out_opc_imm(s, OPC_LHU, lo, base, 0);
+ break;
+ case MO_SW:
+ tcg_out_opc_imm(s, OPC_LH, lo, base, 0);
+ break;
+ case MO_UL:
+ if (TCG_TARGET_REG_BITS == 64 && is_64) {
+ tcg_out_opc_imm(s, OPC_LWU, lo, base, 0);
+ break;
+ }
+ /* FALLTHRU */
+ case MO_SL:
+ tcg_out_opc_imm(s, OPC_LW, lo, base, 0);
+ break;
+ case MO_Q:
+ /* Prefer to load from offset 0 first, but allow for overlap. */
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_opc_imm(s, OPC_LD, lo, base, 0);
+ } else if (lo != base) {
+ tcg_out_opc_imm(s, OPC_LW, lo, base, 0);
+ tcg_out_opc_imm(s, OPC_LW, hi, base, 4);
+ } else {
+ tcg_out_opc_imm(s, OPC_LW, hi, base, 4);
+ tcg_out_opc_imm(s, OPC_LW, lo, base, 0);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
+{
+ TCGReg addr_regl, addr_regh __attribute__((unused));
+ TCGReg data_regl, data_regh;
+ TCGMemOpIdx oi;
+ TCGMemOp opc;
+#if defined(CONFIG_SOFTMMU)
+ tcg_insn_unit *label_ptr[1];
+#endif
+ TCGReg base = TCG_REG_TMP0;
+
+ data_regl = *args++;
+ data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0);
+ addr_regl = *args++;
+ addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0);
+ oi = *args++;
+ opc = get_memop(oi);
+
+#if defined(CONFIG_SOFTMMU)
+ tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 1);
+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ add_qemu_ldst_label(s, 1, oi,
+ (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+ data_regl, data_regh, addr_regl, addr_regh,
+ s->code_ptr, label_ptr);
+#else
+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
+ tcg_out_ext32u(s, base, addr_regl);
+ addr_regl = base;
+ }
+
+ if (guest_base == 0) {
+ tcg_out_opc_reg(s, OPC_ADD, base, addr_regl, TCG_REG_ZERO);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl);
+ }
+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+#endif
+}
+
+static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi,
+ TCGReg base, TCGMemOp opc)
+{
+ const TCGMemOp bswap = opc & MO_BSWAP;
+
+ /* We don't yet handle byteswapping, assert */
+ g_assert(!bswap);
+
+ switch (opc & (MO_SSIZE)) {
+ case MO_8:
+ tcg_out_opc_store(s, OPC_SB, base, lo, 0);
+ break;
+ case MO_16:
+ tcg_out_opc_store(s, OPC_SH, base, lo, 0);
+ break;
+ case MO_32:
+ tcg_out_opc_store(s, OPC_SW, base, lo, 0);
+ break;
+ case MO_64:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_opc_store(s, OPC_SD, base, lo, 0);
+ } else {
+ tcg_out_opc_store(s, OPC_SW, base, lo, 0);
+ tcg_out_opc_store(s, OPC_SW, base, hi, 4);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
+{
+ TCGReg addr_regl, addr_regh __attribute__((unused));
+ TCGReg data_regl, data_regh;
+ TCGMemOpIdx oi;
+ TCGMemOp opc;
+#if defined(CONFIG_SOFTMMU)
+ tcg_insn_unit *label_ptr[1];
+#endif
+ TCGReg base = TCG_REG_TMP0;
+
+ data_regl = *args++;
+ data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0);
+ addr_regl = *args++;
+ addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0);
+ oi = *args++;
+ opc = get_memop(oi);
+
+#if defined(CONFIG_SOFTMMU)
+ tcg_out_tlb_load(s, addr_regl, addr_regh, oi, label_ptr, 0);
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ add_qemu_ldst_label(s, 0, oi,
+ (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+ data_regl, data_regh, addr_regl, addr_regh,
+ s->code_ptr, label_ptr);
+#else
+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
+ tcg_out_ext32u(s, base, addr_regl);
+ addr_regl = base;
+ }
+
+ if (guest_base == 0) {
+ tcg_out_opc_reg(s, OPC_ADD, base, addr_regl, TCG_REG_ZERO);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl);
+ }
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+#endif
+}
+
+static tcg_insn_unit *tb_ret_addr;
+
+static void tcg_out_op(TCGContext *s, TCGOpcode opc,
+ const TCGArg *args, const int *const_args)
+{
+ TCGArg a0 = args[0];
+ TCGArg a1 = args[1];
+ TCGArg a2 = args[2];
+ int c2 = const_args[2];
+
+ switch (opc) {
+ case INDEX_op_exit_tb:
+ /* Reuse the zeroing that exists for goto_ptr. */
+ if (a0 == 0) {
+ tcg_out_call_int(s, s->code_gen_epilogue, true);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0);
+ tcg_out_call_int(s, tb_ret_addr, true);
+ }
+ break;
+
+ case INDEX_op_goto_tb:
+ assert(s->tb_jmp_insn_offset == 0);
+ /* indirect jump method */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO,
+ (uintptr_t)(s->tb_jmp_target_addr + a0));
+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0);
+ set_jmp_reset_offset(s, a0);
+ break;
+
+ case INDEX_op_goto_ptr:
+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0);
+ break;
+
+ case INDEX_op_br:
+ tcg_out_reloc(s, s->code_ptr, R_RISCV_JAL, arg_label(a0), 0);
+ tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, 0);
+ break;
+
+ case INDEX_op_ld8u_i32:
+ case INDEX_op_ld8u_i64:
+ tcg_out_ldst(s, OPC_LBU, a0, a1, a2);
+ break;
+ case INDEX_op_ld8s_i32:
+ case INDEX_op_ld8s_i64:
+ tcg_out_ldst(s, OPC_LB, a0, a1, a2);
+ break;
+ case INDEX_op_ld16u_i32:
+ case INDEX_op_ld16u_i64:
+ tcg_out_ldst(s, OPC_LHU, a0, a1, a2);
+ break;
+ case INDEX_op_ld16s_i32:
+ case INDEX_op_ld16s_i64:
+ tcg_out_ldst(s, OPC_LH, a0, a1, a2);
+ break;
+ case INDEX_op_ld32u_i64:
+ tcg_out_ldst(s, OPC_LWU, a0, a1, a2);
+ break;
+ case INDEX_op_ld_i32:
+ case INDEX_op_ld32s_i64:
+ tcg_out_ldst(s, OPC_LW, a0, a1, a2);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ldst(s, OPC_LD, a0, a1, a2);
+ break;
+
+ case INDEX_op_st8_i32:
+ case INDEX_op_st8_i64:
+ tcg_out_ldst(s, OPC_SB, a0, a1, a2);
+ break;
+ case INDEX_op_st16_i32:
+ case INDEX_op_st16_i64:
+ tcg_out_ldst(s, OPC_SH, a0, a1, a2);
+ break;
+ case INDEX_op_st_i32:
+ case INDEX_op_st32_i64:
+ tcg_out_ldst(s, OPC_SW, a0, a1, a2);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_ldst(s, OPC_SD, a0, a1, a2);
+ break;
+
+ case INDEX_op_add_i32:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ADDIW, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADDW, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_add_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ADDI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_ADD, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_sub_i32:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ADDIW, a0, a1, -a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SUBW, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_sub_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ADDI, a0, a1, -a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SUB, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_and_i32:
+ case INDEX_op_and_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ANDI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_AND, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_or_i32:
+ case INDEX_op_or_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_ORI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_OR, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_xor_i32:
+ case INDEX_op_xor_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_XORI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_XOR, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_not_i32:
+ case INDEX_op_not_i64:
+ tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1);
+ break;
+
+ case INDEX_op_neg_i32:
+ tcg_out_opc_reg(s, OPC_SUBW, a0, TCG_REG_ZERO, a1);
+ break;
+ case INDEX_op_neg_i64:
+ tcg_out_opc_reg(s, OPC_SUB, a0, TCG_REG_ZERO, a1);
+ break;
+
+ case INDEX_op_mul_i32:
+ tcg_out_opc_reg(s, OPC_MULW, a0, a1, a2);
+ break;
+ case INDEX_op_mul_i64:
+ tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2);
+ break;
+
+ case INDEX_op_div_i32:
+ tcg_out_opc_reg(s, OPC_DIVW, a0, a1, a2);
+ break;
+ case INDEX_op_div_i64:
+ tcg_out_opc_reg(s, OPC_DIV, a0, a1, a2);
+ break;
+
+ case INDEX_op_divu_i32:
+ tcg_out_opc_reg(s, OPC_DIVUW, a0, a1, a2);
+ break;
+ case INDEX_op_divu_i64:
+ tcg_out_opc_reg(s, OPC_DIVU, a0, a1, a2);
+ break;
+
+ case INDEX_op_rem_i32:
+ tcg_out_opc_reg(s, OPC_REMW, a0, a1, a2);
+ break;
+ case INDEX_op_rem_i64:
+ tcg_out_opc_reg(s, OPC_REM, a0, a1, a2);
+ break;
+
+ case INDEX_op_remu_i32:
+ tcg_out_opc_reg(s, OPC_REMUW, a0, a1, a2);
+ break;
+ case INDEX_op_remu_i64:
+ tcg_out_opc_reg(s, OPC_REMU, a0, a1, a2);
+ break;
+
+ case INDEX_op_shl_i32:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SLLIW, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SLLW, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_shl_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SLLI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SLL, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_shr_i32:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SRLIW, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRLW, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_shr_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SRLI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRL, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_sar_i32:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SRAIW, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRAW, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_sar_i64:
+ if (c2) {
+ tcg_out_opc_imm(s, OPC_SRAI, a0, a1, a2);
+ } else {
+ tcg_out_opc_reg(s, OPC_SRA, a0, a1, a2);
+ }
+ break;
+
+ case INDEX_op_add2_i32:
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+ const_args[4], const_args[5], false, true);
+ break;
+ case INDEX_op_add2_i64:
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+ const_args[4], const_args[5], false, false);
+ break;
+ case INDEX_op_sub2_i32:
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+ const_args[4], const_args[5], true, true);
+ break;
+ case INDEX_op_sub2_i64:
+ tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+ const_args[4], const_args[5], true, false);
+ break;
+
+ case INDEX_op_brcond_i32:
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond(s, a2, a0, a1, arg_label(args[3]));
+ break;
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5]));
+ break;
+
+ case INDEX_op_setcond_i32:
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond(s, args[3], a0, a1, a2);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]);
+ break;
+
+ case INDEX_op_qemu_ld_i32:
+ tcg_out_qemu_ld(s, args, false);
+ break;
+ case INDEX_op_qemu_ld_i64:
+ tcg_out_qemu_ld(s, args, true);
+ break;
+ case INDEX_op_qemu_st_i32:
+ tcg_out_qemu_st(s, args, false);
+ break;
+ case INDEX_op_qemu_st_i64:
+ tcg_out_qemu_st(s, args, true);
+ break;
+
+ case INDEX_op_ext8u_i32:
+ case INDEX_op_ext8u_i64:
+ tcg_out_ext8u(s, a0, a1);
+ break;
+
+ case INDEX_op_ext16u_i32:
+ case INDEX_op_ext16u_i64:
+ tcg_out_ext16u(s, a0, a1);
+ break;
+
+ case INDEX_op_ext32u_i64:
+ case INDEX_op_extu_i32_i64:
+ tcg_out_ext32u(s, a0, a1);
+ break;
+
+ case INDEX_op_ext8s_i32:
+ case INDEX_op_ext8s_i64:
+ tcg_out_ext8s(s, a0, a1);
+ break;
+
+ case INDEX_op_ext16s_i32:
+ case INDEX_op_ext16s_i64:
+ tcg_out_ext16s(s, a0, a1);
+ break;
+
+ case INDEX_op_ext32s_i64:
+ case INDEX_op_extrl_i64_i32:
+ case INDEX_op_ext_i32_i64:
+ tcg_out_ext32s(s, a0, a1);
+ break;
+
+ case INDEX_op_extrh_i64_i32:
+ tcg_out_opc_imm(s, OPC_SRAI, a0, a1, 32);
+ break;
+
+ case INDEX_op_mulsh_i32:
+ case INDEX_op_mulsh_i64:
+ tcg_out_opc_reg(s, OPC_MULH, a0, a1, a2);
+ break;
+
+ case INDEX_op_muluh_i32:
+ case INDEX_op_muluh_i64:
+ tcg_out_opc_reg(s, OPC_MULHU, a0, a1, a2);
+ break;
+
+ case INDEX_op_mb:
+ tcg_out_mb(s, a0);
+ break;
+
+ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
+ case INDEX_op_mov_i64:
+ case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */
+ case INDEX_op_movi_i64:
+ case INDEX_op_call: /* Always emitted via tcg_out_call. */
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
+{
+ static const TCGTargetOpDef r
+ = { .args_ct_str = { "r" } };
+ static const TCGTargetOpDef r_r
+ = { .args_ct_str = { "r", "r" } };
+ static const TCGTargetOpDef rZ_r
+ = { .args_ct_str = { "rZ", "r" } };
+ static const TCGTargetOpDef rZ_rZ
+ = { .args_ct_str = { "rZ", "rZ" } };
+ static const TCGTargetOpDef rZ_rZ_rZ_rZ
+ = { .args_ct_str = { "rZ", "rZ", "rZ", "rZ" } };
+ static const TCGTargetOpDef r_r_ri
+ = { .args_ct_str = { "r", "r", "ri" } };
+ static const TCGTargetOpDef r_r_rI
+ = { .args_ct_str = { "r", "r", "rI" } };
+ static const TCGTargetOpDef r_rZ_rN
+ = { .args_ct_str = { "r", "rZ", "rN" } };
+ static const TCGTargetOpDef r_rZ_rZ
+ = { .args_ct_str = { "r", "rZ", "rZ" } };
+ static const TCGTargetOpDef r_rZ_rZ_rZ_rZ
+ = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "rZ" } };
+ static const TCGTargetOpDef r_L
+ = { .args_ct_str = { "r", "L" } };
+ static const TCGTargetOpDef r_r_L
+ = { .args_ct_str = { "r", "r", "L" } };
+ static const TCGTargetOpDef r_L_L
+ = { .args_ct_str = { "r", "L", "L" } };
+ static const TCGTargetOpDef r_r_L_L
+ = { .args_ct_str = { "r", "r", "L", "L" } };
+ static const TCGTargetOpDef LZ_L
+ = { .args_ct_str = { "LZ", "L" } };
+ static const TCGTargetOpDef LZ_L_L
+ = { .args_ct_str = { "LZ", "L", "L" } };
+ static const TCGTargetOpDef LZ_LZ_L
+ = { .args_ct_str = { "LZ", "LZ", "L" } };
+ static const TCGTargetOpDef LZ_LZ_L_L
+ = { .args_ct_str = { "LZ", "LZ", "L", "L" } };
+ static const TCGTargetOpDef r_r_rZ_rZ_rM_rM
+ = { .args_ct_str = { "r", "r", "rZ", "rZ", "rM", "rM" } };
+
+ switch (op) {
+ case INDEX_op_goto_ptr:
+ return &r;
+
+ case INDEX_op_ld8u_i32:
+ case INDEX_op_ld8s_i32:
+ case INDEX_op_ld16u_i32:
+ case INDEX_op_ld16s_i32:
+ case INDEX_op_ld_i32:
+ case INDEX_op_not_i32:
+ case INDEX_op_neg_i32:
+ case INDEX_op_ld8u_i64:
+ case INDEX_op_ld8s_i64:
+ case INDEX_op_ld16u_i64:
+ case INDEX_op_ld16s_i64:
+ case INDEX_op_ld32s_i64:
+ case INDEX_op_ld32u_i64:
+ case INDEX_op_ld_i64:
+ case INDEX_op_not_i64:
+ case INDEX_op_neg_i64:
+ case INDEX_op_ext8u_i32:
+ case INDEX_op_ext8u_i64:
+ case INDEX_op_ext16u_i32:
+ case INDEX_op_ext16u_i64:
+ case INDEX_op_ext32u_i64:
+ case INDEX_op_extu_i32_i64:
+ case INDEX_op_ext8s_i32:
+ case INDEX_op_ext8s_i64:
+ case INDEX_op_ext16s_i32:
+ case INDEX_op_ext16s_i64:
+ case INDEX_op_ext32s_i64:
+ case INDEX_op_extrl_i64_i32:
+ case INDEX_op_extrh_i64_i32:
+ case INDEX_op_ext_i32_i64:
+ return &r_r;
+
+ case INDEX_op_st8_i32:
+ case INDEX_op_st16_i32:
+ case INDEX_op_st_i32:
+ case INDEX_op_st8_i64:
+ case INDEX_op_st16_i64:
+ case INDEX_op_st32_i64:
+ case INDEX_op_st_i64:
+ return &rZ_r;
+
+ case INDEX_op_add_i32:
+ case INDEX_op_and_i32:
+ case INDEX_op_or_i32:
+ case INDEX_op_xor_i32:
+ case INDEX_op_add_i64:
+ case INDEX_op_and_i64:
+ case INDEX_op_or_i64:
+ case INDEX_op_xor_i64:
+ return &r_r_rI;
+
+ case INDEX_op_sub_i32:
+ case INDEX_op_sub_i64:
+ return &r_rZ_rN;
+
+ case INDEX_op_mul_i32:
+ case INDEX_op_mulsh_i32:
+ case INDEX_op_muluh_i32:
+ case INDEX_op_div_i32:
+ case INDEX_op_divu_i32:
+ case INDEX_op_rem_i32:
+ case INDEX_op_remu_i32:
+ case INDEX_op_setcond_i32:
+ case INDEX_op_mul_i64:
+ case INDEX_op_mulsh_i64:
+ case INDEX_op_muluh_i64:
+ case INDEX_op_div_i64:
+ case INDEX_op_divu_i64:
+ case INDEX_op_rem_i64:
+ case INDEX_op_remu_i64:
+ case INDEX_op_setcond_i64:
+ return &r_rZ_rZ;
+
+ case INDEX_op_shl_i32:
+ case INDEX_op_shr_i32:
+ case INDEX_op_sar_i32:
+ case INDEX_op_shl_i64:
+ case INDEX_op_shr_i64:
+ case INDEX_op_sar_i64:
+ return &r_r_ri;
+
+ case INDEX_op_brcond_i32:
+ case INDEX_op_brcond_i64:
+ return &rZ_rZ;
+
+ case INDEX_op_add2_i32:
+ case INDEX_op_add2_i64:
+ case INDEX_op_sub2_i32:
+ case INDEX_op_sub2_i64:
+ return &r_r_rZ_rZ_rM_rM;
+
+ case INDEX_op_brcond2_i32:
+ return &rZ_rZ_rZ_rZ;
+
+ case INDEX_op_setcond2_i32:
+ return &r_rZ_rZ_rZ_rZ;
+
+ case INDEX_op_qemu_ld_i32:
+ return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_L : &r_L_L;
+ case INDEX_op_qemu_st_i32:
+ return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_L : &LZ_L_L;
+ case INDEX_op_qemu_ld_i64:
+ return TCG_TARGET_REG_BITS == 64 ? &r_L
+ : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_r_L
+ : &r_r_L_L;
+ case INDEX_op_qemu_st_i64:
+ return TCG_TARGET_REG_BITS == 64 ? &LZ_L
+ : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_LZ_L
+ : &LZ_LZ_L_L;
+
+ default:
+ return NULL;
+ }
+}
+
+static const int tcg_target_callee_save_regs[] = {
+ TCG_REG_S0, /* used for the global env (TCG_AREG0) */
+ TCG_REG_S1,
+ TCG_REG_S2,
+ TCG_REG_S3,
+ TCG_REG_S4,
+ TCG_REG_S5,
+ TCG_REG_S6,
+ TCG_REG_S7,
+ TCG_REG_S8,
+ TCG_REG_S9,
+ TCG_REG_S10,
+ TCG_REG_S11,
+ TCG_REG_RA, /* should be last for ABI compliance */
+};
+
+/* Stack frame parameters. */
+#define REG_SIZE (TCG_TARGET_REG_BITS / 8)
+#define SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * REG_SIZE)
+#define TEMP_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long))
+#define FRAME_SIZE ((TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE + SAVE_SIZE \
+ + TCG_TARGET_STACK_ALIGN - 1) \
+ & -TCG_TARGET_STACK_ALIGN)
+#define SAVE_OFS (TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE)
+
+/* We're expecting to be able to use an immediate for frame allocation. */
+QEMU_BUILD_BUG_ON(FRAME_SIZE > 0x7ff);
+
+/* Generate global QEMU prologue and epilogue code */
+static void tcg_target_qemu_prologue(TCGContext *s)
+{
+ int i;
+
+ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, TEMP_SIZE);
+
+ /* TB prologue */
+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_SP, TCG_REG_SP, -FRAME_SIZE);
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE);
+ }
+
+#if !defined(CONFIG_SOFTMMU)
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base);
+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
+#endif
+
+ /* Call generated code */
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, tcg_target_call_iarg_regs[1], 0);
+
+ /* Return path for goto_ptr. Set return value to 0 */
+ s->code_gen_epilogue = s->code_ptr;
+ tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_A0, TCG_REG_ZERO);
+
+ /* TB epilogue */
+ tb_ret_addr = s->code_ptr;
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+ tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i],
+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE);
+ }
+
+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE);
+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_RA, 0);
+}
+
+static void tcg_target_init(TCGContext *s)
+{
+ tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff;
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffff;
+ }
+
+ tcg_target_call_clobber_regs = -1u;
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S3);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S4);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S5);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S6);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S7);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S8);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S9);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S10);
+ tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S11);
+
+ s->reserved_regs = 0;
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP0);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP2);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP);
+}
+
+typedef struct {
+ DebugFrameHeader h;
+ uint8_t fde_def_cfa[4];
+ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2];
+} DebugFrame;
+
+#define ELF_HOST_MACHINE EM_RISCV
+
+static const DebugFrame debug_frame = {
+ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */
+ .h.cie.id = -1,
+ .h.cie.version = 1,
+ .h.cie.code_align = 1,
+ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */
+ .h.cie.return_column = TCG_REG_RA,
+
+ /* Total FDE size does not include the "len" member. */
+ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
+
+ .fde_def_cfa = {
+ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */
+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
+ (FRAME_SIZE >> 7)
+ },
+ .fde_reg_ofs = {
+ 0x80 + 9, 12, /* DW_CFA_offset, s1, -96 */
+ 0x80 + 18, 11, /* DW_CFA_offset, s2, -88 */
+ 0x80 + 19, 10, /* DW_CFA_offset, s3, -80 */
+ 0x80 + 20, 9, /* DW_CFA_offset, s4, -72 */
+ 0x80 + 21, 8, /* DW_CFA_offset, s5, -64 */
+ 0x80 + 22, 7, /* DW_CFA_offset, s6, -56 */
+ 0x80 + 23, 6, /* DW_CFA_offset, s7, -48 */
+ 0x80 + 24, 5, /* DW_CFA_offset, s8, -40 */
+ 0x80 + 25, 4, /* DW_CFA_offset, s9, -32 */
+ 0x80 + 26, 3, /* DW_CFA_offset, s10, -24 */
+ 0x80 + 27, 2, /* DW_CFA_offset, s11, -16 */
+ 0x80 + 1 , 1, /* DW_CFA_offset, ra, -8 */
+ }
+};
+
+void tcg_register_jit(void *buf, size_t buf_size)
+{
+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
+}
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 6f2b06a7d1..853ed6e7aa 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -135,6 +135,7 @@ extern uint64_t s390_facilities;
#define TCG_TARGET_CALL_STACK_OFFSET 160
#define TCG_TARGET_EXTEND_ARGS 1
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
#define TCG_TARGET_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
diff --git a/tcg/s390/tcg-target.inc.c b/tcg/s390/tcg-target.inc.c
index 17c435ade5..39ecf609a1 100644
--- a/tcg/s390/tcg-target.inc.c
+++ b/tcg/s390/tcg-target.inc.c
@@ -366,7 +366,7 @@ static void * const qemu_st_helpers[16] = {
static tcg_insn_unit *tb_ret_addr;
uint64_t s390_facilities;
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
intptr_t pcrel2;
@@ -377,22 +377,29 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
switch (type) {
case R_390_PC16DBL:
- assert(pcrel2 == (int16_t)pcrel2);
- tcg_patch16(code_ptr, pcrel2);
+ if (pcrel2 == (int16_t)pcrel2) {
+ tcg_patch16(code_ptr, pcrel2);
+ return true;
+ }
break;
case R_390_PC32DBL:
- assert(pcrel2 == (int32_t)pcrel2);
- tcg_patch32(code_ptr, pcrel2);
+ if (pcrel2 == (int32_t)pcrel2) {
+ tcg_patch32(code_ptr, pcrel2);
+ return true;
+ }
break;
case R_390_20:
- assert(value == sextract64(value, 0, 20));
- old = *(uint32_t *)code_ptr & 0xf00000ff;
- old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
- tcg_patch32(code_ptr, old);
+ if (value == sextract64(value, 0, 20)) {
+ old = *(uint32_t *)code_ptr & 0xf00000ff;
+ old |= ((value & 0xfff) << 16) | ((value & 0xff000) >> 4);
+ tcg_patch32(code_ptr, old);
+ return true;
+ }
break;
default:
g_assert_not_reached();
}
+ return false;
}
/* parse target specific constraints */
@@ -1329,13 +1336,12 @@ static void tgen_branch(TCGContext *s, int cc, TCGLabel *l)
static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
TCGReg r1, TCGReg r2, TCGLabel *l)
{
- intptr_t off;
+ intptr_t off = 0;
if (l->has_value) {
off = l->u.value_ptr - s->code_ptr;
+ tcg_debug_assert(off == (int16_t)off);
} else {
- /* We need to keep the offset unchanged for retranslation. */
- off = s->code_ptr[1];
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
}
@@ -1347,13 +1353,12 @@ static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc,
static void tgen_compare_imm_branch(TCGContext *s, S390Opcode opc, int cc,
TCGReg r1, int i2, TCGLabel *l)
{
- tcg_target_long off;
+ tcg_target_long off = 0;
if (l->has_value) {
off = l->u.value_ptr - s->code_ptr;
+ tcg_debug_assert(off == (int16_t)off);
} else {
- /* We need to keep the offset unchanged for retranslation. */
- off = s->code_ptr[1];
tcg_out_reloc(s, s->code_ptr + 1, R_390_PC16DBL, l, 2);
}
@@ -1618,7 +1623,9 @@ static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOpIdx oi = lb->oi;
TCGMemOp opc = get_memop(oi);
- patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, 2);
+ bool ok = patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+ (intptr_t)s->code_ptr, 2);
+ tcg_debug_assert(ok);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);
if (TARGET_LONG_BITS == 64) {
@@ -1639,7 +1646,9 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
TCGMemOpIdx oi = lb->oi;
TCGMemOp opc = get_memop(oi);
- patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, 2);
+ bool ok = patch_reloc(lb->label_ptr[0], R_390_PC16DBL,
+ (intptr_t)s->code_ptr, 2);
+ tcg_debug_assert(ok);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);
if (TARGET_LONG_BITS == 64) {
@@ -1696,7 +1705,6 @@ static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 1);
- /* We need to keep the offset unchanged for retranslation. */
tcg_out16(s, RI_BRC | (S390_CC_NE << 4));
label_ptr = s->code_ptr;
s->code_ptr += 1;
@@ -1724,7 +1732,6 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg,
base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 0);
- /* We need to keep the offset unchanged for retranslation. */
tcg_out16(s, RI_BRC | (S390_CC_NE << 4));
label_ptr = s->code_ptr;
s->code_ptr += 1;
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index d8339bf010..a0ed2a3342 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -164,6 +164,7 @@ extern bool use_vis3_instructions;
#define TCG_AREG0 TCG_REG_I0
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
{
diff --git a/tcg/sparc/tcg-target.inc.c b/tcg/sparc/tcg-target.inc.c
index 04bdc3df5e..55144c437c 100644
--- a/tcg/sparc/tcg-target.inc.c
+++ b/tcg/sparc/tcg-target.inc.c
@@ -291,7 +291,7 @@ static inline int check_fit_i32(int32_t val, unsigned int bits)
# define check_fit_ptr check_fit_i32
#endif
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
uint32_t insn = *code_ptr;
@@ -311,29 +311,12 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
insn &= ~INSN_OFF19(-1);
insn |= INSN_OFF19(pcrel);
break;
- case R_SPARC_13:
- /* Note that we're abusing this reloc type for our own needs. */
- if (!check_fit_ptr(value, 13)) {
- int adj = (value > 0 ? 0xff8 : -0x1000);
- value -= adj;
- assert(check_fit_ptr(value, 13));
- *code_ptr++ = (ARITH_ADD | INSN_RD(TCG_REG_T2)
- | INSN_RS1(TCG_REG_TB) | INSN_IMM13(adj));
- insn ^= INSN_RS1(TCG_REG_TB) ^ INSN_RS1(TCG_REG_T2);
- }
- insn &= ~INSN_IMM13(-1);
- insn |= INSN_IMM13(value);
- break;
- case R_SPARC_32:
- /* Note that we're abusing this reloc type for our own needs. */
- code_ptr[0] = deposit32(code_ptr[0], 0, 22, value >> 10);
- code_ptr[1] = deposit32(code_ptr[1], 0, 10, value);
- return;
default:
g_assert_not_reached();
}
*code_ptr = insn;
+ return true;
}
/* parse target specific constraints */
@@ -459,6 +442,15 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
return;
}
+ /* A 13-bit constant relative to the TB. */
+ if (!in_prologue && USE_REG_TB) {
+ test = arg - (uintptr_t)s->code_gen_ptr;
+ if (check_fit_ptr(test, 13)) {
+ tcg_out_arithi(s, ret, TCG_REG_TB, test, ARITH_ADD);
+ return;
+ }
+ }
+
/* A 32-bit constant, or 32-bit zero-extended to 64-bits. */
if (type == TCG_TYPE_I32 || arg == (uint32_t)arg) {
tcg_out_sethi(s, ret, arg);
@@ -488,26 +480,6 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
return;
}
- if (!in_prologue) {
- if (USE_REG_TB) {
- intptr_t diff = arg - (uintptr_t)s->code_gen_ptr;
- if (check_fit_ptr(diff, 13)) {
- tcg_out_arithi(s, ret, TCG_REG_TB, diff, ARITH_ADD);
- } else {
- new_pool_label(s, arg, R_SPARC_13, s->code_ptr,
- -(intptr_t)s->code_gen_ptr);
- tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(TCG_REG_TB));
- /* May be used to extend the 13-bit range in patch_reloc. */
- tcg_out32(s, NOP);
- }
- } else {
- new_pool_label(s, arg, R_SPARC_32, s->code_ptr, 0);
- tcg_out_sethi(s, ret, 0);
- tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | INSN_IMM13(0));
- }
- return;
- }
-
/* A 64-bit constant decomposed into 2 32-bit pieces. */
if (check_fit_i32(lo, 13)) {
hi = (arg - lo) >> 32;
@@ -639,13 +611,11 @@ static void tcg_out_bpcc0(TCGContext *s, int scond, int flags, int off19)
static void tcg_out_bpcc(TCGContext *s, int scond, int flags, TCGLabel *l)
{
- int off19;
+ int off19 = 0;
if (l->has_value) {
off19 = INSN_OFF19(tcg_pcrel_diff(s, l->u.value_ptr));
} else {
- /* Make sure to preserve destinations during retranslation. */
- off19 = *s->code_ptr & INSN_OFF19(-1);
tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, l, 0);
}
tcg_out_bpcc0(s, scond, flags, off19);
@@ -685,13 +655,11 @@ static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGReg arg1,
{
/* For 64-bit signed comparisons vs zero, we can avoid the compare. */
if (arg2 == 0 && !is_unsigned_cond(cond)) {
- int off16;
+ int off16 = 0;
if (l->has_value) {
off16 = INSN_OFF16(tcg_pcrel_diff(s, l->u.value_ptr));
} else {
- /* Make sure to preserve destinations during retranslation. */
- off16 = *s->code_ptr & INSN_OFF16(-1);
tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP16, l, 0);
}
tcg_out32(s, INSN_OP(0) | INSN_OP2(3) | BPR_PT | INSN_RS1(arg1)
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 7a8015c5a9..1bd7ef24af 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -240,6 +240,7 @@ void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l)
if (cond == TCG_COND_ALWAYS) {
tcg_gen_br(l);
} else if (cond != TCG_COND_NEVER) {
+ l->refs++;
tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l));
}
}
@@ -1012,24 +1013,24 @@ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg)
if (TCG_TARGET_HAS_bswap32_i32) {
tcg_gen_op2_i32(INDEX_op_bswap32_i32, ret, arg);
} else {
- TCGv_i32 t0, t1;
- t0 = tcg_temp_new_i32();
- t1 = tcg_temp_new_i32();
-
- tcg_gen_shli_i32(t0, arg, 24);
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ TCGv_i32 t1 = tcg_temp_new_i32();
+ TCGv_i32 t2 = tcg_const_i32(0x00ff00ff);
- tcg_gen_andi_i32(t1, arg, 0x0000ff00);
- tcg_gen_shli_i32(t1, t1, 8);
- tcg_gen_or_i32(t0, t0, t1);
+ /* arg = abcd */
+ tcg_gen_shri_i32(t0, arg, 8); /* t0 = .abc */
+ tcg_gen_and_i32(t1, arg, t2); /* t1 = .b.d */
+ tcg_gen_and_i32(t0, t0, t2); /* t0 = .a.c */
+ tcg_gen_shli_i32(t1, t1, 8); /* t1 = b.d. */
+ tcg_gen_or_i32(ret, t0, t1); /* ret = badc */
- tcg_gen_shri_i32(t1, arg, 8);
- tcg_gen_andi_i32(t1, t1, 0x0000ff00);
- tcg_gen_or_i32(t0, t0, t1);
+ tcg_gen_shri_i32(t0, ret, 16); /* t0 = ..ba */
+ tcg_gen_shli_i32(t1, ret, 16); /* t1 = dc.. */
+ tcg_gen_or_i32(ret, t0, t1); /* ret = dcba */
- tcg_gen_shri_i32(t1, arg, 24);
- tcg_gen_or_i32(ret, t0, t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
}
}
@@ -1405,6 +1406,7 @@ void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l)
if (cond == TCG_COND_ALWAYS) {
tcg_gen_br(l);
} else if (cond != TCG_COND_NEVER) {
+ l->refs++;
if (TCG_TARGET_REG_BITS == 32) {
tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1),
TCGV_HIGH(arg1), TCGV_LOW(arg2),
@@ -1638,25 +1640,25 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg)
} else if (TCG_TARGET_HAS_bswap32_i64) {
tcg_gen_op2_i64(INDEX_op_bswap32_i64, ret, arg);
} else {
- TCGv_i64 t0, t1;
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
-
- tcg_gen_shli_i64(t0, arg, 24);
- tcg_gen_ext32u_i64(t0, t0);
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_const_i64(0x00ff00ff);
- tcg_gen_andi_i64(t1, arg, 0x0000ff00);
- tcg_gen_shli_i64(t1, t1, 8);
- tcg_gen_or_i64(t0, t0, t1);
+ /* arg = ....abcd */
+ tcg_gen_shri_i64(t0, arg, 8); /* t0 = .....abc */
+ tcg_gen_and_i64(t1, arg, t2); /* t1 = .....b.d */
+ tcg_gen_and_i64(t0, t0, t2); /* t0 = .....a.c */
+ tcg_gen_shli_i64(t1, t1, 8); /* t1 = ....b.d. */
+ tcg_gen_or_i64(ret, t0, t1); /* ret = ....badc */
- tcg_gen_shri_i64(t1, arg, 8);
- tcg_gen_andi_i64(t1, t1, 0x0000ff00);
- tcg_gen_or_i64(t0, t0, t1);
+ tcg_gen_shli_i64(t1, ret, 48); /* t1 = dc...... */
+ tcg_gen_shri_i64(t0, ret, 16); /* t0 = ......ba */
+ tcg_gen_shri_i64(t1, t1, 32); /* t1 = ....dc.. */
+ tcg_gen_or_i64(ret, t0, t1); /* ret = ....dcba */
- tcg_gen_shri_i64(t1, arg, 24);
- tcg_gen_or_i64(ret, t0, t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
}
}
@@ -1678,37 +1680,30 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg)
} else {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
+ TCGv_i64 t2 = tcg_temp_new_i64();
- tcg_gen_shli_i64(t0, arg, 56);
-
- tcg_gen_andi_i64(t1, arg, 0x0000ff00);
- tcg_gen_shli_i64(t1, t1, 40);
- tcg_gen_or_i64(t0, t0, t1);
-
- tcg_gen_andi_i64(t1, arg, 0x00ff0000);
- tcg_gen_shli_i64(t1, t1, 24);
- tcg_gen_or_i64(t0, t0, t1);
-
- tcg_gen_andi_i64(t1, arg, 0xff000000);
- tcg_gen_shli_i64(t1, t1, 8);
- tcg_gen_or_i64(t0, t0, t1);
-
- tcg_gen_shri_i64(t1, arg, 8);
- tcg_gen_andi_i64(t1, t1, 0xff000000);
- tcg_gen_or_i64(t0, t0, t1);
-
- tcg_gen_shri_i64(t1, arg, 24);
- tcg_gen_andi_i64(t1, t1, 0x00ff0000);
- tcg_gen_or_i64(t0, t0, t1);
-
- tcg_gen_shri_i64(t1, arg, 40);
- tcg_gen_andi_i64(t1, t1, 0x0000ff00);
- tcg_gen_or_i64(t0, t0, t1);
+ /* arg = abcdefgh */
+ tcg_gen_movi_i64(t2, 0x00ff00ff00ff00ffull);
+ tcg_gen_shri_i64(t0, arg, 8); /* t0 = .abcdefg */
+ tcg_gen_and_i64(t1, arg, t2); /* t1 = .b.d.f.h */
+ tcg_gen_and_i64(t0, t0, t2); /* t0 = .a.c.e.g */
+ tcg_gen_shli_i64(t1, t1, 8); /* t1 = b.d.f.h. */
+ tcg_gen_or_i64(ret, t0, t1); /* ret = badcfehg */
+
+ tcg_gen_movi_i64(t2, 0x0000ffff0000ffffull);
+ tcg_gen_shri_i64(t0, ret, 16); /* t0 = ..badcfe */
+ tcg_gen_and_i64(t1, ret, t2); /* t1 = ..dc..hg */
+ tcg_gen_and_i64(t0, t0, t2); /* t0 = ..ba..fe */
+ tcg_gen_shli_i64(t1, t1, 16); /* t1 = dc..hg.. */
+ tcg_gen_or_i64(ret, t0, t1); /* ret = dcbahgfe */
+
+ tcg_gen_shri_i64(t0, ret, 32); /* t0 = ....dcba */
+ tcg_gen_shli_i64(t1, ret, 32); /* t1 = hgfe.... */
+ tcg_gen_or_i64(ret, t0, t1); /* ret = hgfedcba */
- tcg_gen_shri_i64(t1, arg, 56);
- tcg_gen_or_i64(ret, t0, t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
}
}
@@ -2701,25 +2696,78 @@ static void tcg_gen_req_mo(TCGBar type)
void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
{
+ TCGMemOp orig_memop;
+
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
memop = tcg_canonicalize_memop(memop, 0, 0);
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
addr, trace_mem_get_info(memop, 0));
+
+ orig_memop = memop;
+ if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
+ memop &= ~MO_BSWAP;
+ /* The bswap primitive requires zero-extended input. */
+ if ((memop & MO_SSIZE) == MO_SW) {
+ memop &= ~MO_SIGN;
+ }
+ }
+
gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
+
+ if ((orig_memop ^ memop) & MO_BSWAP) {
+ switch (orig_memop & MO_SIZE) {
+ case MO_16:
+ tcg_gen_bswap16_i32(val, val);
+ if (orig_memop & MO_SIGN) {
+ tcg_gen_ext16s_i32(val, val);
+ }
+ break;
+ case MO_32:
+ tcg_gen_bswap32_i32(val, val);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
}
void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
{
+ TCGv_i32 swap = NULL;
+
tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
memop = tcg_canonicalize_memop(memop, 0, 1);
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
addr, trace_mem_get_info(memop, 1));
+
+ if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
+ swap = tcg_temp_new_i32();
+ switch (memop & MO_SIZE) {
+ case MO_16:
+ tcg_gen_ext16u_i32(swap, val);
+ tcg_gen_bswap16_i32(swap, swap);
+ break;
+ case MO_32:
+ tcg_gen_bswap32_i32(swap, val);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ val = swap;
+ memop &= ~MO_BSWAP;
+ }
+
gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
+
+ if (swap) {
+ tcg_temp_free_i32(swap);
+ }
}
void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
{
- tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
+ TCGMemOp orig_memop;
+
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
tcg_gen_qemu_ld_i32(TCGV_LOW(val), addr, idx, memop);
if (memop & MO_SIGN) {
@@ -2730,24 +2778,85 @@ void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
return;
}
+ tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
memop = tcg_canonicalize_memop(memop, 1, 0);
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
addr, trace_mem_get_info(memop, 0));
+
+ orig_memop = memop;
+ if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
+ memop &= ~MO_BSWAP;
+ /* The bswap primitive requires zero-extended input. */
+ if ((memop & MO_SIGN) && (memop & MO_SIZE) < MO_64) {
+ memop &= ~MO_SIGN;
+ }
+ }
+
gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, memop, idx);
+
+ if ((orig_memop ^ memop) & MO_BSWAP) {
+ switch (orig_memop & MO_SIZE) {
+ case MO_16:
+ tcg_gen_bswap16_i64(val, val);
+ if (orig_memop & MO_SIGN) {
+ tcg_gen_ext16s_i64(val, val);
+ }
+ break;
+ case MO_32:
+ tcg_gen_bswap32_i64(val, val);
+ if (orig_memop & MO_SIGN) {
+ tcg_gen_ext32s_i64(val, val);
+ }
+ break;
+ case MO_64:
+ tcg_gen_bswap64_i64(val, val);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
}
void tcg_gen_qemu_st_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
{
- tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
+ TCGv_i64 swap = NULL;
+
if (TCG_TARGET_REG_BITS == 32 && (memop & MO_SIZE) < MO_64) {
tcg_gen_qemu_st_i32(TCGV_LOW(val), addr, idx, memop);
return;
}
+ tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
memop = tcg_canonicalize_memop(memop, 1, 1);
trace_guest_mem_before_tcg(tcg_ctx->cpu, cpu_env,
addr, trace_mem_get_info(memop, 1));
+
+ if (!TCG_TARGET_HAS_MEMORY_BSWAP && (memop & MO_BSWAP)) {
+ swap = tcg_temp_new_i64();
+ switch (memop & MO_SIZE) {
+ case MO_16:
+ tcg_gen_ext16u_i64(swap, val);
+ tcg_gen_bswap16_i64(swap, swap);
+ break;
+ case MO_32:
+ tcg_gen_ext32u_i64(swap, val);
+ tcg_gen_bswap32_i64(swap, swap);
+ break;
+ case MO_64:
+ tcg_gen_bswap64_i64(swap, val);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ val = swap;
+ memop &= ~MO_BSWAP;
+ }
+
gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, memop, idx);
+
+ if (swap) {
+ tcg_temp_free_i64(swap);
+ }
}
static void tcg_gen_ext_i32(TCGv_i32 ret, TCGv_i32 val, TCGMemOp opc)
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index db4e9188f4..7007ec0d4d 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -260,6 +260,7 @@ static inline void gen_set_label(TCGLabel *l)
static inline void tcg_gen_br(TCGLabel *l)
{
+ l->refs++;
tcg_gen_op1(INDEX_op_br, label_arg(l));
}
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index e3a43aabb6..7a8a3edb5b 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -191,9 +191,10 @@ DEF(mulsh_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_mulsh_i64))
/* QEMU specific */
DEF(insn_start, 0, 0, TLADDR_ARGS * TARGET_INSN_START_WORDS,
TCG_OPF_NOT_PRESENT)
-DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END)
-DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END)
-DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_END | IMPL(TCG_TARGET_HAS_goto_ptr))
+DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
+DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END)
+DEF(goto_ptr, 0, 1, 0,
+ TCG_OPF_BB_EXIT | TCG_OPF_BB_END | IMPL(TCG_TARGET_HAS_goto_ptr))
DEF(qemu_ld_i32, 1, TLADDR_ARGS, 1,
TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index e85133ef05..f34f52fbdb 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -66,7 +66,7 @@
static void tcg_target_init(TCGContext *s);
static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode);
static void tcg_target_qemu_prologue(TCGContext *s);
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend);
/* The CIE and FDE header definitions will be common to all hosts. */
@@ -268,7 +268,8 @@ static void tcg_out_reloc(TCGContext *s, tcg_insn_unit *code_ptr, int type,
/* FIXME: This may break relocations on RISC targets that
modify instruction fields in place. The caller may not have
written the initial value. */
- patch_reloc(code_ptr, type, l->u.value, addend);
+ bool ok = patch_reloc(code_ptr, type, l->u.value, addend);
+ tcg_debug_assert(ok);
} else {
/* add a new relocation entry */
r = tcg_malloc(sizeof(TCGRelocation));
@@ -288,7 +289,8 @@ static void tcg_out_label(TCGContext *s, TCGLabel *l, tcg_insn_unit *ptr)
tcg_debug_assert(!l->has_value);
for (r = l->u.first_reloc; r != NULL; r = r->next) {
- patch_reloc(r->ptr, r->type, value, r->addend);
+ bool ok = patch_reloc(r->ptr, r->type, value, r->addend);
+ tcg_debug_assert(ok);
}
l->has_value = 1;
@@ -1885,7 +1887,21 @@ static const char * const alignment_name[(MO_AMASK >> MO_ASHIFT) + 1] = {
[MO_ALIGN_64 >> MO_ASHIFT] = "al64+",
};
-void tcg_dump_ops(TCGContext *s)
+static inline bool tcg_regset_single(TCGRegSet d)
+{
+ return (d & (d - 1)) == 0;
+}
+
+static inline TCGReg tcg_regset_first(TCGRegSet d)
+{
+ if (TCG_TARGET_NB_REGS <= 32) {
+ return ctz32(d);
+ } else {
+ return ctz64(d);
+ }
+}
+
+static void tcg_dump_ops(TCGContext *s, bool have_prefs)
{
char buf[128];
TCGOp *op;
@@ -1900,6 +1916,7 @@ void tcg_dump_ops(TCGContext *s)
def = &tcg_op_defs[c];
if (c == INDEX_op_insn_start) {
+ nb_oargs = 0;
col += qemu_log("\n ----");
for (i = 0; i < TARGET_INSN_START_WORDS; ++i) {
@@ -2019,12 +2036,15 @@ void tcg_dump_ops(TCGContext *s)
col += qemu_log("%s$0x%" TCG_PRIlx, k ? "," : "", op->args[k]);
}
}
- if (op->life) {
- unsigned life = op->life;
- for (; col < 48; ++col) {
+ if (have_prefs || op->life) {
+ for (; col < 40; ++col) {
putc(' ', qemu_logfile);
}
+ }
+
+ if (op->life) {
+ unsigned life = op->life;
if (life & (SYNC_ARG * 3)) {
qemu_log(" sync:");
@@ -2044,6 +2064,33 @@ void tcg_dump_ops(TCGContext *s)
}
}
}
+
+ if (have_prefs) {
+ for (i = 0; i < nb_oargs; ++i) {
+ TCGRegSet set = op->output_pref[i];
+
+ if (i == 0) {
+ qemu_log(" pref=");
+ } else {
+ qemu_log(",");
+ }
+ if (set == 0) {
+ qemu_log("none");
+ } else if (set == MAKE_64BIT_MASK(0, TCG_TARGET_NB_REGS)) {
+ qemu_log("all");
+#ifdef CONFIG_DEBUG_TCG
+ } else if (tcg_regset_single(set)) {
+ TCGReg reg = tcg_regset_first(set);
+ qemu_log("%s", tcg_target_reg_names[reg]);
+#endif
+ } else if (TCG_TARGET_NB_REGS <= 32) {
+ qemu_log("%#x", (uint32_t)set);
+ } else {
+ qemu_log("%#" PRIx64, (uint64_t)set);
+ }
+ }
+ }
+
qemu_log("\n");
}
}
@@ -2169,6 +2216,26 @@ static void process_op_defs(TCGContext *s)
void tcg_op_remove(TCGContext *s, TCGOp *op)
{
+ TCGLabel *label;
+
+ switch (op->opc) {
+ case INDEX_op_br:
+ label = arg_label(op->args[0]);
+ label->refs--;
+ break;
+ case INDEX_op_brcond_i32:
+ case INDEX_op_brcond_i64:
+ label = arg_label(op->args[3]);
+ label->refs--;
+ break;
+ case INDEX_op_brcond2_i32:
+ label = arg_label(op->args[5]);
+ label->refs--;
+ break;
+ default:
+ break;
+ }
+
QTAILQ_REMOVE(&s->ops, op, link);
QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
s->nb_ops--;
@@ -2203,59 +2270,195 @@ TCGOp *tcg_emit_op(TCGOpcode opc)
return op;
}
-TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op,
- TCGOpcode opc, int nargs)
+TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
{
TCGOp *new_op = tcg_op_alloc(opc);
QTAILQ_INSERT_BEFORE(old_op, new_op, link);
return new_op;
}
-TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op,
- TCGOpcode opc, int nargs)
+TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc)
{
TCGOp *new_op = tcg_op_alloc(opc);
QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link);
return new_op;
}
+/* Reachable analysis : remove unreachable code. */
+static void reachable_code_pass(TCGContext *s)
+{
+ TCGOp *op, *op_next;
+ bool dead = false;
+
+ QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) {
+ bool remove = dead;
+ TCGLabel *label;
+ int call_flags;
+
+ switch (op->opc) {
+ case INDEX_op_set_label:
+ label = arg_label(op->args[0]);
+ if (label->refs == 0) {
+ /*
+ * While there is an occasional backward branch, virtually
+ * all branches generated by the translators are forward.
+ * Which means that generally we will have already removed
+ * all references to the label that will be, and there is
+ * little to be gained by iterating.
+ */
+ remove = true;
+ } else {
+ /* Once we see a label, insns become live again. */
+ dead = false;
+ remove = false;
+
+ /*
+ * Optimization can fold conditional branches to unconditional.
+ * If we find a label with one reference which is preceded by
+ * an unconditional branch to it, remove both. This needed to
+ * wait until the dead code in between them was removed.
+ */
+ if (label->refs == 1) {
+ TCGOp *op_prev = QTAILQ_PREV(op, link);
+ if (op_prev->opc == INDEX_op_br &&
+ label == arg_label(op_prev->args[0])) {
+ tcg_op_remove(s, op_prev);
+ remove = true;
+ }
+ }
+ }
+ break;
+
+ case INDEX_op_br:
+ case INDEX_op_exit_tb:
+ case INDEX_op_goto_ptr:
+ /* Unconditional branches; everything following is dead. */
+ dead = true;
+ break;
+
+ case INDEX_op_call:
+ /* Notice noreturn helper calls, raising exceptions. */
+ call_flags = op->args[TCGOP_CALLO(op) + TCGOP_CALLI(op) + 1];
+ if (call_flags & TCG_CALL_NO_RETURN) {
+ dead = true;
+ }
+ break;
+
+ case INDEX_op_insn_start:
+ /* Never remove -- we need to keep these for unwind. */
+ remove = false;
+ break;
+
+ default:
+ break;
+ }
+
+ if (remove) {
+ tcg_op_remove(s, op);
+ }
+ }
+}
+
#define TS_DEAD 1
#define TS_MEM 2
#define IS_DEAD_ARG(n) (arg_life & (DEAD_ARG << (n)))
#define NEED_SYNC_ARG(n) (arg_life & (SYNC_ARG << (n)))
+/* For liveness_pass_1, the register preferences for a given temp. */
+static inline TCGRegSet *la_temp_pref(TCGTemp *ts)
+{
+ return ts->state_ptr;
+}
+
+/* For liveness_pass_1, reset the preferences for a given temp to the
+ * maximal regset for its type.
+ */
+static inline void la_reset_pref(TCGTemp *ts)
+{
+ *la_temp_pref(ts)
+ = (ts->state == TS_DEAD ? 0 : tcg_target_available_regs[ts->type]);
+}
+
/* liveness analysis: end of function: all temps are dead, and globals
should be in memory. */
-static void tcg_la_func_end(TCGContext *s)
+static void la_func_end(TCGContext *s, int ng, int nt)
{
- int ng = s->nb_globals;
- int nt = s->nb_temps;
int i;
for (i = 0; i < ng; ++i) {
s->temps[i].state = TS_DEAD | TS_MEM;
+ la_reset_pref(&s->temps[i]);
}
for (i = ng; i < nt; ++i) {
s->temps[i].state = TS_DEAD;
+ la_reset_pref(&s->temps[i]);
}
}
/* liveness analysis: end of basic block: all temps are dead, globals
and local temps should be in memory. */
-static void tcg_la_bb_end(TCGContext *s)
+static void la_bb_end(TCGContext *s, int ng, int nt)
{
- int ng = s->nb_globals;
- int nt = s->nb_temps;
int i;
for (i = 0; i < ng; ++i) {
s->temps[i].state = TS_DEAD | TS_MEM;
+ la_reset_pref(&s->temps[i]);
}
for (i = ng; i < nt; ++i) {
s->temps[i].state = (s->temps[i].temp_local
? TS_DEAD | TS_MEM
: TS_DEAD);
+ la_reset_pref(&s->temps[i]);
+ }
+}
+
+/* liveness analysis: sync globals back to memory. */
+static void la_global_sync(TCGContext *s, int ng)
+{
+ int i;
+
+ for (i = 0; i < ng; ++i) {
+ int state = s->temps[i].state;
+ s->temps[i].state = state | TS_MEM;
+ if (state == TS_DEAD) {
+ /* If the global was previously dead, reset prefs. */
+ la_reset_pref(&s->temps[i]);
+ }
+ }
+}
+
+/* liveness analysis: sync globals back to memory and kill. */
+static void la_global_kill(TCGContext *s, int ng)
+{
+ int i;
+
+ for (i = 0; i < ng; i++) {
+ s->temps[i].state = TS_DEAD | TS_MEM;
+ la_reset_pref(&s->temps[i]);
+ }
+}
+
+/* liveness analysis: note live globals crossing calls. */
+static void la_cross_call(TCGContext *s, int nt)
+{
+ TCGRegSet mask = ~tcg_target_call_clobber_regs;
+ int i;
+
+ for (i = 0; i < nt; i++) {
+ TCGTemp *ts = &s->temps[i];
+ if (!(ts->state & TS_DEAD)) {
+ TCGRegSet *pset = la_temp_pref(ts);
+ TCGRegSet set = *pset;
+
+ set &= mask;
+ /* If the combination is not possible, restart. */
+ if (set == 0) {
+ set = tcg_target_available_regs[ts->type] & mask;
+ }
+ *pset = set;
+ }
}
}
@@ -2265,16 +2468,25 @@ static void tcg_la_bb_end(TCGContext *s)
static void liveness_pass_1(TCGContext *s)
{
int nb_globals = s->nb_globals;
+ int nb_temps = s->nb_temps;
TCGOp *op, *op_prev;
+ TCGRegSet *prefs;
+ int i;
- tcg_la_func_end(s);
+ prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps);
+ for (i = 0; i < nb_temps; ++i) {
+ s->temps[i].state_ptr = prefs + i;
+ }
+
+ /* ??? Should be redundant with the exit_tb that ends the TB. */
+ la_func_end(s, nb_globals, nb_temps);
- QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, TCGOpHead, link, op_prev) {
- int i, nb_iargs, nb_oargs;
+ QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) {
+ int nb_iargs, nb_oargs;
TCGOpcode opc_new, opc_new2;
bool have_opc_new2;
TCGLifeData arg_life = 0;
- TCGTemp *arg_ts;
+ TCGTemp *ts;
TCGOpcode opc = op->opc;
const TCGOpDef *def = &tcg_op_defs[opc];
@@ -2282,6 +2494,7 @@ static void liveness_pass_1(TCGContext *s)
case INDEX_op_call:
{
int call_flags;
+ int nb_call_regs;
nb_oargs = TCGOP_CALLO(op);
nb_iargs = TCGOP_CALLI(op);
@@ -2290,53 +2503,74 @@ static void liveness_pass_1(TCGContext *s)
/* pure functions can be removed if their result is unused */
if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) {
for (i = 0; i < nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts->state != TS_DEAD) {
+ ts = arg_temp(op->args[i]);
+ if (ts->state != TS_DEAD) {
goto do_not_remove_call;
}
}
goto do_remove;
- } else {
- do_not_remove_call:
+ }
+ do_not_remove_call:
- /* output args are dead */
- for (i = 0; i < nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts->state & TS_DEAD) {
- arg_life |= DEAD_ARG << i;
- }
- if (arg_ts->state & TS_MEM) {
- arg_life |= SYNC_ARG << i;
- }
- arg_ts->state = TS_DEAD;
+ /* Output args are dead. */
+ for (i = 0; i < nb_oargs; i++) {
+ ts = arg_temp(op->args[i]);
+ if (ts->state & TS_DEAD) {
+ arg_life |= DEAD_ARG << i;
+ }
+ if (ts->state & TS_MEM) {
+ arg_life |= SYNC_ARG << i;
}
+ ts->state = TS_DEAD;
+ la_reset_pref(ts);
- if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
- TCG_CALL_NO_READ_GLOBALS))) {
- /* globals should go back to memory */
- for (i = 0; i < nb_globals; i++) {
- s->temps[i].state = TS_DEAD | TS_MEM;
- }
- } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
- /* globals should be synced to memory */
- for (i = 0; i < nb_globals; i++) {
- s->temps[i].state |= TS_MEM;
- }
+ /* Not used -- it will be tcg_target_call_oarg_regs[i]. */
+ op->output_pref[i] = 0;
+ }
+
+ if (!(call_flags & (TCG_CALL_NO_WRITE_GLOBALS |
+ TCG_CALL_NO_READ_GLOBALS))) {
+ la_global_kill(s, nb_globals);
+ } else if (!(call_flags & TCG_CALL_NO_READ_GLOBALS)) {
+ la_global_sync(s, nb_globals);
+ }
+
+ /* Record arguments that die in this helper. */
+ for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
+ ts = arg_temp(op->args[i]);
+ if (ts && ts->state & TS_DEAD) {
+ arg_life |= DEAD_ARG << i;
}
+ }
- /* record arguments that die in this helper */
- for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts && arg_ts->state & TS_DEAD) {
- arg_life |= DEAD_ARG << i;
- }
+ /* For all live registers, remove call-clobbered prefs. */
+ la_cross_call(s, nb_temps);
+
+ nb_call_regs = ARRAY_SIZE(tcg_target_call_iarg_regs);
+
+ /* Input arguments are live for preceding opcodes. */
+ for (i = 0; i < nb_iargs; i++) {
+ ts = arg_temp(op->args[i + nb_oargs]);
+ if (ts && ts->state & TS_DEAD) {
+ /* For those arguments that die, and will be allocated
+ * in registers, clear the register set for that arg,
+ * to be filled in below. For args that will be on
+ * the stack, reset to any available reg.
+ */
+ *la_temp_pref(ts)
+ = (i < nb_call_regs ? 0 :
+ tcg_target_available_regs[ts->type]);
+ ts->state &= ~TS_DEAD;
}
- /* input arguments are live for preceding opcodes */
- for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts) {
- arg_ts->state &= ~TS_DEAD;
- }
+ }
+
+ /* For each input argument, add its input register to prefs.
+ If a temp is used once, this produces a single set bit. */
+ for (i = 0; i < MIN(nb_call_regs, nb_iargs); i++) {
+ ts = arg_temp(op->args[i + nb_oargs]);
+ if (ts) {
+ tcg_regset_set_reg(*la_temp_pref(ts),
+ tcg_target_call_iarg_regs[i]);
}
}
}
@@ -2345,7 +2579,9 @@ static void liveness_pass_1(TCGContext *s)
break;
case INDEX_op_discard:
/* mark the temporary as dead */
- arg_temp(op->args[0])->state = TS_DEAD;
+ ts = arg_temp(op->args[0]);
+ ts->state = TS_DEAD;
+ la_reset_pref(ts);
break;
case INDEX_op_add2_i32:
@@ -2440,43 +2676,96 @@ static void liveness_pass_1(TCGContext *s)
goto do_not_remove;
}
}
- do_remove:
- tcg_op_remove(s, op);
- } else {
- do_not_remove:
- /* output args are dead */
- for (i = 0; i < nb_oargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts->state & TS_DEAD) {
- arg_life |= DEAD_ARG << i;
- }
- if (arg_ts->state & TS_MEM) {
- arg_life |= SYNC_ARG << i;
- }
- arg_ts->state = TS_DEAD;
+ goto do_remove;
+ }
+ goto do_not_remove;
+
+ do_remove:
+ tcg_op_remove(s, op);
+ break;
+
+ do_not_remove:
+ for (i = 0; i < nb_oargs; i++) {
+ ts = arg_temp(op->args[i]);
+
+ /* Remember the preference of the uses that followed. */
+ op->output_pref[i] = *la_temp_pref(ts);
+
+ /* Output args are dead. */
+ if (ts->state & TS_DEAD) {
+ arg_life |= DEAD_ARG << i;
+ }
+ if (ts->state & TS_MEM) {
+ arg_life |= SYNC_ARG << i;
}
+ ts->state = TS_DEAD;
+ la_reset_pref(ts);
+ }
- /* if end of basic block, update */
- if (def->flags & TCG_OPF_BB_END) {
- tcg_la_bb_end(s);
- } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
- /* globals should be synced to memory */
- for (i = 0; i < nb_globals; i++) {
- s->temps[i].state |= TS_MEM;
- }
+ /* If end of basic block, update. */
+ if (def->flags & TCG_OPF_BB_EXIT) {
+ la_func_end(s, nb_globals, nb_temps);
+ } else if (def->flags & TCG_OPF_BB_END) {
+ la_bb_end(s, nb_globals, nb_temps);
+ } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
+ la_global_sync(s, nb_globals);
+ if (def->flags & TCG_OPF_CALL_CLOBBER) {
+ la_cross_call(s, nb_temps);
}
+ }
- /* record arguments that die in this opcode */
- for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
- arg_ts = arg_temp(op->args[i]);
- if (arg_ts->state & TS_DEAD) {
- arg_life |= DEAD_ARG << i;
- }
+ /* Record arguments that die in this opcode. */
+ for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+ ts = arg_temp(op->args[i]);
+ if (ts->state & TS_DEAD) {
+ arg_life |= DEAD_ARG << i;
+ }
+ }
+
+ /* Input arguments are live for preceding opcodes. */
+ for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
+ ts = arg_temp(op->args[i]);
+ if (ts->state & TS_DEAD) {
+ /* For operands that were dead, initially allow
+ all regs for the type. */
+ *la_temp_pref(ts) = tcg_target_available_regs[ts->type];
+ ts->state &= ~TS_DEAD;
+ }
+ }
+
+ /* Incorporate constraints for this operand. */
+ switch (opc) {
+ case INDEX_op_mov_i32:
+ case INDEX_op_mov_i64:
+ /* Note that these are TCG_OPF_NOT_PRESENT and do not
+ have proper constraints. That said, special case
+ moves to propagate preferences backward. */
+ if (IS_DEAD_ARG(1)) {
+ *la_temp_pref(arg_temp(op->args[0]))
+ = *la_temp_pref(arg_temp(op->args[1]));
}
- /* input arguments are live for preceding opcodes */
+ break;
+
+ default:
for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) {
- arg_temp(op->args[i])->state &= ~TS_DEAD;
+ const TCGArgConstraint *ct = &def->args_ct[i];
+ TCGRegSet set, *pset;
+
+ ts = arg_temp(op->args[i]);
+ pset = la_temp_pref(ts);
+ set = *pset;
+
+ set &= ct->u.regs;
+ if (ct->ct & TCG_CT_IALIAS) {
+ set &= op->output_pref[ct->alias_index];
+ }
+ /* If the combination is not possible, restart. */
+ if (set == 0) {
+ set = ct->u.regs;
+ }
+ *pset = set;
}
+ break;
}
break;
}
@@ -2550,7 +2839,7 @@ static bool liveness_pass_2(TCGContext *s)
TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32
? INDEX_op_ld_i32
: INDEX_op_ld_i64);
- TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3);
+ TCGOp *lop = tcg_op_insert_before(s, op, lopc);
lop->args[0] = temp_arg(dir_ts);
lop->args[1] = temp_arg(arg_ts->mem_base);
@@ -2619,7 +2908,7 @@ static bool liveness_pass_2(TCGContext *s)
TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32
? INDEX_op_st_i32
: INDEX_op_st_i64);
- TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3);
+ TCGOp *sop = tcg_op_insert_after(s, op, sopc);
sop->args[0] = temp_arg(dir_ts);
sop->args[1] = temp_arg(arg_ts->mem_base);
@@ -2727,7 +3016,7 @@ static void temp_allocate_frame(TCGContext *s, TCGTemp *ts)
s->current_frame_offset += sizeof(tcg_target_long);
}
-static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet);
+static void temp_load(TCGContext *, TCGTemp *, TCGRegSet, TCGRegSet, TCGRegSet);
/* Mark a temporary as free or dead. If 'free_or_dead' is negative,
mark it free; otherwise mark it dead. */
@@ -2755,8 +3044,8 @@ static inline void temp_dead(TCGContext *s, TCGTemp *ts)
registers needs to be allocated to store a constant. If 'free_or_dead'
is non-zero, subsequently release the temporary; if it is positive, the
temp is dead; if it is negative, the temp is free. */
-static void temp_sync(TCGContext *s, TCGTemp *ts,
- TCGRegSet allocated_regs, int free_or_dead)
+static void temp_sync(TCGContext *s, TCGTemp *ts, TCGRegSet allocated_regs,
+ TCGRegSet preferred_regs, int free_or_dead)
{
if (ts->fixed_reg) {
return;
@@ -2776,7 +3065,7 @@ static void temp_sync(TCGContext *s, TCGTemp *ts,
break;
}
temp_load(s, ts, tcg_target_available_regs[ts->type],
- allocated_regs);
+ allocated_regs, preferred_regs);
/* fallthrough */
case TEMP_VAL_REG:
@@ -2803,35 +3092,76 @@ static void tcg_reg_free(TCGContext *s, TCGReg reg, TCGRegSet allocated_regs)
{
TCGTemp *ts = s->reg_to_temp[reg];
if (ts != NULL) {
- temp_sync(s, ts, allocated_regs, -1);
+ temp_sync(s, ts, allocated_regs, 0, -1);
}
}
-/* Allocate a register belonging to reg1 & ~reg2 */
-static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
- TCGRegSet allocated_regs, bool rev)
+/**
+ * tcg_reg_alloc:
+ * @required_regs: Set of registers in which we must allocate.
+ * @allocated_regs: Set of registers which must be avoided.
+ * @preferred_regs: Set of registers we should prefer.
+ * @rev: True if we search the registers in "indirect" order.
+ *
+ * The allocated register must be in @required_regs & ~@allocated_regs,
+ * but if we can put it in @preferred_regs we may save a move later.
+ */
+static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
+ TCGRegSet allocated_regs,
+ TCGRegSet preferred_regs, bool rev)
{
- int i, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
+ int i, j, f, n = ARRAY_SIZE(tcg_target_reg_alloc_order);
+ TCGRegSet reg_ct[2];
const int *order;
- TCGReg reg;
- TCGRegSet reg_ct;
- reg_ct = desired_regs & ~allocated_regs;
+ reg_ct[1] = required_regs & ~allocated_regs;
+ tcg_debug_assert(reg_ct[1] != 0);
+ reg_ct[0] = reg_ct[1] & preferred_regs;
+
+ /* Skip the preferred_regs option if it cannot be satisfied,
+ or if the preference made no difference. */
+ f = reg_ct[0] == 0 || reg_ct[0] == reg_ct[1];
+
order = rev ? indirect_reg_alloc_order : tcg_target_reg_alloc_order;
- /* first try free registers */
- for(i = 0; i < n; i++) {
- reg = order[i];
- if (tcg_regset_test_reg(reg_ct, reg) && s->reg_to_temp[reg] == NULL)
- return reg;
+ /* Try free registers, preferences first. */
+ for (j = f; j < 2; j++) {
+ TCGRegSet set = reg_ct[j];
+
+ if (tcg_regset_single(set)) {
+ /* One register in the set. */
+ TCGReg reg = tcg_regset_first(set);
+ if (s->reg_to_temp[reg] == NULL) {
+ return reg;
+ }
+ } else {
+ for (i = 0; i < n; i++) {
+ TCGReg reg = order[i];
+ if (s->reg_to_temp[reg] == NULL &&
+ tcg_regset_test_reg(set, reg)) {
+ return reg;
+ }
+ }
+ }
}
- /* XXX: do better spill choice */
- for(i = 0; i < n; i++) {
- reg = order[i];
- if (tcg_regset_test_reg(reg_ct, reg)) {
+ /* We must spill something. */
+ for (j = f; j < 2; j++) {
+ TCGRegSet set = reg_ct[j];
+
+ if (tcg_regset_single(set)) {
+ /* One register in the set. */
+ TCGReg reg = tcg_regset_first(set);
tcg_reg_free(s, reg, allocated_regs);
return reg;
+ } else {
+ for (i = 0; i < n; i++) {
+ TCGReg reg = order[i];
+ if (tcg_regset_test_reg(set, reg)) {
+ tcg_reg_free(s, reg, allocated_regs);
+ return reg;
+ }
+ }
}
}
@@ -2841,7 +3171,7 @@ static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet desired_regs,
/* Make sure the temporary is in a register. If needed, allocate the register
from DESIRED while avoiding ALLOCATED. */
static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
- TCGRegSet allocated_regs)
+ TCGRegSet allocated_regs, TCGRegSet preferred_regs)
{
TCGReg reg;
@@ -2849,12 +3179,14 @@ static void temp_load(TCGContext *s, TCGTemp *ts, TCGRegSet desired_regs,
case TEMP_VAL_REG:
return;
case TEMP_VAL_CONST:
- reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
+ reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
+ preferred_regs, ts->indirect_base);
tcg_out_movi(s, ts->type, reg, ts->val);
ts->mem_coherent = 0;
break;
case TEMP_VAL_MEM:
- reg = tcg_reg_alloc(s, desired_regs, allocated_regs, ts->indirect_base);
+ reg = tcg_reg_alloc(s, desired_regs, allocated_regs,
+ preferred_regs, ts->indirect_base);
tcg_out_ld(s, ts->type, reg, ts->mem_base->reg, ts->mem_offset);
ts->mem_coherent = 1;
break;
@@ -2924,7 +3256,8 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs)
}
static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
- tcg_target_ulong val, TCGLifeData arg_life)
+ tcg_target_ulong val, TCGLifeData arg_life,
+ TCGRegSet preferred_regs)
{
if (ots->fixed_reg) {
/* For fixed registers, we do not do any constant propagation. */
@@ -2940,7 +3273,7 @@ static void tcg_reg_alloc_do_movi(TCGContext *s, TCGTemp *ots,
ots->val = val;
ots->mem_coherent = 0;
if (NEED_SYNC_ARG(0)) {
- temp_sync(s, ots, s->reserved_regs, IS_DEAD_ARG(0));
+ temp_sync(s, ots, s->reserved_regs, preferred_regs, IS_DEAD_ARG(0));
} else if (IS_DEAD_ARG(0)) {
temp_dead(s, ots);
}
@@ -2951,17 +3284,18 @@ static void tcg_reg_alloc_movi(TCGContext *s, const TCGOp *op)
TCGTemp *ots = arg_temp(op->args[0]);
tcg_target_ulong val = op->args[1];
- tcg_reg_alloc_do_movi(s, ots, val, op->life);
+ tcg_reg_alloc_do_movi(s, ots, val, op->life, op->output_pref[0]);
}
static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
{
const TCGLifeData arg_life = op->life;
- TCGRegSet allocated_regs;
+ TCGRegSet allocated_regs, preferred_regs;
TCGTemp *ts, *ots;
TCGType otype, itype;
allocated_regs = s->reserved_regs;
+ preferred_regs = op->output_pref[0];
ots = arg_temp(op->args[0]);
ts = arg_temp(op->args[1]);
@@ -2975,7 +3309,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
if (IS_DEAD_ARG(1)) {
temp_dead(s, ts);
}
- tcg_reg_alloc_do_movi(s, ots, val, arg_life);
+ tcg_reg_alloc_do_movi(s, ots, val, arg_life, preferred_regs);
return;
}
@@ -2984,7 +3318,8 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
the SOURCE value into its own register first, that way we
don't have to reload SOURCE the next time it is used. */
if (ts->val_type == TEMP_VAL_MEM) {
- temp_load(s, ts, tcg_target_available_regs[itype], allocated_regs);
+ temp_load(s, ts, tcg_target_available_regs[itype],
+ allocated_regs, preferred_regs);
}
tcg_debug_assert(ts->val_type == TEMP_VAL_REG);
@@ -3014,7 +3349,8 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
input one. */
tcg_regset_set_reg(allocated_regs, ts->reg);
ots->reg = tcg_reg_alloc(s, tcg_target_available_regs[otype],
- allocated_regs, ots->indirect_base);
+ allocated_regs, preferred_regs,
+ ots->indirect_base);
}
tcg_out_mov(s, otype, ots->reg, ts->reg);
}
@@ -3022,7 +3358,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOp *op)
ots->mem_coherent = 0;
s->reg_to_temp[ots->reg] = ots;
if (NEED_SYNC_ARG(0)) {
- temp_sync(s, ots, allocated_regs, 0);
+ temp_sync(s, ots, allocated_regs, 0, 0);
}
}
}
@@ -3054,6 +3390,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
/* satisfy input constraints */
for (k = 0; k < nb_iargs; k++) {
+ TCGRegSet i_preferred_regs, o_preferred_regs;
+
i = def->sorted_args[nb_oargs + k];
arg = op->args[i];
arg_ct = &def->args_ct[i];
@@ -3064,17 +3402,18 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
/* constant is OK for instruction */
const_args[i] = 1;
new_args[i] = ts->val;
- goto iarg_end;
+ continue;
}
- temp_load(s, ts, arg_ct->u.regs, i_allocated_regs);
-
+ i_preferred_regs = o_preferred_regs = 0;
if (arg_ct->ct & TCG_CT_IALIAS) {
+ o_preferred_regs = op->output_pref[arg_ct->alias_index];
if (ts->fixed_reg) {
/* if fixed register, we must allocate a new register
if the alias is not the same register */
- if (arg != op->args[arg_ct->alias_index])
+ if (arg != op->args[arg_ct->alias_index]) {
goto allocate_in_reg;
+ }
} else {
/* if the input is aliased to an output and if it is
not dead after the instruction, we must allocate
@@ -3082,33 +3421,42 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
if (!IS_DEAD_ARG(i)) {
goto allocate_in_reg;
}
+
/* check if the current register has already been allocated
for another input aliased to an output */
- int k2, i2;
- for (k2 = 0 ; k2 < k ; k2++) {
- i2 = def->sorted_args[nb_oargs + k2];
- if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
- (new_args[i2] == ts->reg)) {
- goto allocate_in_reg;
+ if (ts->val_type == TEMP_VAL_REG) {
+ int k2, i2;
+ reg = ts->reg;
+ for (k2 = 0 ; k2 < k ; k2++) {
+ i2 = def->sorted_args[nb_oargs + k2];
+ if ((def->args_ct[i2].ct & TCG_CT_IALIAS) &&
+ reg == new_args[i2]) {
+ goto allocate_in_reg;
+ }
}
}
+ i_preferred_regs = o_preferred_regs;
}
}
+
+ temp_load(s, ts, arg_ct->u.regs, i_allocated_regs, i_preferred_regs);
reg = ts->reg;
+
if (tcg_regset_test_reg(arg_ct->u.regs, reg)) {
/* nothing to do : the constraint is satisfied */
} else {
allocate_in_reg:
/* allocate a new register matching the constraint
and move the temporary register into it */
+ temp_load(s, ts, tcg_target_available_regs[ts->type],
+ i_allocated_regs, 0);
reg = tcg_reg_alloc(s, arg_ct->u.regs, i_allocated_regs,
- ts->indirect_base);
+ o_preferred_regs, ts->indirect_base);
tcg_out_mov(s, ts->type, reg, ts->reg);
}
new_args[i] = reg;
const_args[i] = 0;
tcg_regset_set_reg(i_allocated_regs, reg);
- iarg_end: ;
}
/* mark dead temporaries and free the associated registers */
@@ -3147,7 +3495,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
} else if (arg_ct->ct & TCG_CT_NEWREG) {
reg = tcg_reg_alloc(s, arg_ct->u.regs,
i_allocated_regs | o_allocated_regs,
- ts->indirect_base);
+ op->output_pref[k], ts->indirect_base);
} else {
/* if fixed register, we try to use it */
reg = ts->reg;
@@ -3156,7 +3504,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
goto oarg_end;
}
reg = tcg_reg_alloc(s, arg_ct->u.regs, o_allocated_regs,
- ts->indirect_base);
+ op->output_pref[k], ts->indirect_base);
}
tcg_regset_set_reg(o_allocated_regs, reg);
/* if a fixed register is used, then a move will be done afterwards */
@@ -3192,7 +3540,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
tcg_out_mov(s, ts->type, ts->reg, reg);
}
if (NEED_SYNC_ARG(i)) {
- temp_sync(s, ts, o_allocated_regs, IS_DEAD_ARG(i));
+ temp_sync(s, ts, o_allocated_regs, 0, IS_DEAD_ARG(i));
} else if (IS_DEAD_ARG(i)) {
temp_dead(s, ts);
}
@@ -3248,7 +3596,7 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
if (arg != TCG_CALL_DUMMY_ARG) {
ts = arg_temp(arg);
temp_load(s, ts, tcg_target_available_regs[ts->type],
- s->reserved_regs);
+ s->reserved_regs, 0);
tcg_out_st(s, ts->type, ts->reg, TCG_REG_CALL_STACK, stack_offset);
}
#ifndef TCG_TARGET_STACK_GROWSUP
@@ -3263,17 +3611,18 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
if (arg != TCG_CALL_DUMMY_ARG) {
ts = arg_temp(arg);
reg = tcg_target_call_iarg_regs[i];
- tcg_reg_free(s, reg, allocated_regs);
if (ts->val_type == TEMP_VAL_REG) {
if (ts->reg != reg) {
+ tcg_reg_free(s, reg, allocated_regs);
tcg_out_mov(s, ts->type, reg, ts->reg);
}
} else {
TCGRegSet arg_set = 0;
+ tcg_reg_free(s, reg, allocated_regs);
tcg_regset_set_reg(arg_set, reg);
- temp_load(s, ts, arg_set, allocated_regs);
+ temp_load(s, ts, arg_set, allocated_regs, 0);
}
tcg_regset_set_reg(allocated_regs, reg);
@@ -3326,7 +3675,7 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
ts->mem_coherent = 0;
s->reg_to_temp[reg] = ts;
if (NEED_SYNC_ARG(i)) {
- temp_sync(s, ts, allocated_regs, IS_DEAD_ARG(i));
+ temp_sync(s, ts, allocated_regs, 0, IS_DEAD_ARG(i));
} else if (IS_DEAD_ARG(i)) {
temp_dead(s, ts);
}
@@ -3476,7 +3825,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
&& qemu_log_in_addr_range(tb->pc))) {
qemu_log_lock();
qemu_log("OP:\n");
- tcg_dump_ops(s);
+ tcg_dump_ops(s, false);
qemu_log("\n");
qemu_log_unlock();
}
@@ -3495,6 +3844,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
atomic_set(&prof->la_time, prof->la_time - profile_getclock());
#endif
+ reachable_code_pass(s);
liveness_pass_1(s);
if (s->nb_indirects > 0) {
@@ -3503,7 +3853,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
&& qemu_log_in_addr_range(tb->pc))) {
qemu_log_lock();
qemu_log("OP before indirect lowering:\n");
- tcg_dump_ops(s);
+ tcg_dump_ops(s, false);
qemu_log("\n");
qemu_log_unlock();
}
@@ -3524,7 +3874,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb)
&& qemu_log_in_addr_range(tb->pc))) {
qemu_log_lock();
qemu_log("OP after optimization and liveness analysis:\n");
- tcg_dump_ops(s);
+ tcg_dump_ops(s, true);
qemu_log("\n");
qemu_log_unlock();
}
diff --git a/tcg/tcg.h b/tcg/tcg.h
index f4efbaa680..f8ec265027 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -230,11 +230,9 @@ typedef uint64_t tcg_insn_unit;
#if defined CONFIG_DEBUG_TCG || defined QEMU_STATIC_ANALYSIS
# define tcg_debug_assert(X) do { assert(X); } while (0)
-#elif QEMU_GNUC_PREREQ(4, 5)
+#else
# define tcg_debug_assert(X) \
do { if (!(X)) { __builtin_unreachable(); } } while (0)
-#else
-# define tcg_debug_assert(X) do { (void)(X); } while (0)
#endif
typedef struct TCGRelocation {
@@ -246,7 +244,8 @@ typedef struct TCGRelocation {
typedef struct TCGLabel {
unsigned has_value : 1;
- unsigned id : 31;
+ unsigned id : 15;
+ unsigned refs : 16;
union {
uintptr_t value;
tcg_insn_unit *value_ptr;
@@ -464,11 +463,13 @@ typedef TCGv_ptr TCGv_env;
/* call flags */
/* Helper does not read globals (either directly or through an exception). It
implies TCG_CALL_NO_WRITE_GLOBALS. */
-#define TCG_CALL_NO_READ_GLOBALS 0x0010
+#define TCG_CALL_NO_READ_GLOBALS 0x0001
/* Helper does not write globals */
-#define TCG_CALL_NO_WRITE_GLOBALS 0x0020
+#define TCG_CALL_NO_WRITE_GLOBALS 0x0002
/* Helper can be safely suppressed if the return value is not used. */
-#define TCG_CALL_NO_SIDE_EFFECTS 0x0040
+#define TCG_CALL_NO_SIDE_EFFECTS 0x0004
+/* Helper is QEMU_NORETURN. */
+#define TCG_CALL_NO_RETURN 0x0008
/* convenience version of most used call flags */
#define TCG_CALL_NO_RWG TCG_CALL_NO_READ_GLOBALS
@@ -618,6 +619,9 @@ typedef struct TCGOp {
/* Arguments for the opcode. */
TCGArg args[MAX_OPC_PARAM];
+
+ /* Register preferences for the output(s). */
+ TCGRegSet output_pref[2];
} TCGOp;
#define TCGOP_CALLI(X) (X)->param1
@@ -704,7 +708,7 @@ struct TCGContext {
/* These structures are private to tcg-target.inc.c. */
#ifdef TCG_TARGET_NEED_LDST_LABELS
- QSIMPLEQ_HEAD(ldst_labels, TCGLabelQemuLdst) ldst_labels;
+ QSIMPLEQ_HEAD(, TCGLabelQemuLdst) ldst_labels;
#endif
#ifdef TCG_TARGET_NEED_POOL_LABELS
struct TCGLabelPoolData *pool_labels;
@@ -715,7 +719,7 @@ struct TCGContext {
TCGTempSet free_temps[TCG_TYPE_COUNT * 2];
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
- QTAILQ_HEAD(TCGOpHead, TCGOp) ops, free_ops;
+ QTAILQ_HEAD(, TCGOp) ops, free_ops;
/* Tells which temporary holds a given register.
It does not take into account fixed registers */
@@ -843,7 +847,7 @@ static inline void tcg_set_insn_start_param(TCGOp *op, int arg, target_ulong v)
/* The last op that was emitted. */
static inline TCGOp *tcg_last_op(void)
{
- return QTAILQ_LAST(&tcg_ctx->ops, TCGOpHead);
+ return QTAILQ_LAST(&tcg_ctx->ops);
}
/* Test for whether to terminate the TB for using too many opcodes. */
@@ -1026,20 +1030,22 @@ typedef struct TCGArgConstraint {
/* Bits for TCGOpDef->flags, 8 bits available. */
enum {
+ /* Instruction exits the translation block. */
+ TCG_OPF_BB_EXIT = 0x01,
/* Instruction defines the end of a basic block. */
- TCG_OPF_BB_END = 0x01,
+ TCG_OPF_BB_END = 0x02,
/* Instruction clobbers call registers and potentially update globals. */
- TCG_OPF_CALL_CLOBBER = 0x02,
+ TCG_OPF_CALL_CLOBBER = 0x04,
/* Instruction has side effects: it cannot be removed if its outputs
are not used, and might trigger exceptions. */
- TCG_OPF_SIDE_EFFECTS = 0x04,
+ TCG_OPF_SIDE_EFFECTS = 0x08,
/* Instruction operands are 64-bits (otherwise 32-bits). */
- TCG_OPF_64BIT = 0x08,
+ TCG_OPF_64BIT = 0x10,
/* Instruction is optional and not implemented by the host, or insn
is generic and should not be implemened by the host. */
- TCG_OPF_NOT_PRESENT = 0x10,
+ TCG_OPF_NOT_PRESENT = 0x20,
/* Instruction operands are vectors. */
- TCG_OPF_VECTOR = 0x20,
+ TCG_OPF_VECTOR = 0x40,
};
typedef struct TCGOpDef {
@@ -1073,14 +1079,11 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args);
TCGOp *tcg_emit_op(TCGOpcode opc);
void tcg_op_remove(TCGContext *s, TCGOp *op);
-TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc, int narg);
-TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc, int narg);
+TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc);
+TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc);
void tcg_optimize(TCGContext *s);
-/* only used for debugging purposes */
-void tcg_dump_ops(TCGContext *s);
-
TCGv_i32 tcg_const_i32(int32_t val);
TCGv_i64 tcg_const_i64(int64_t val);
TCGv_i32 tcg_const_local_i32(int32_t val);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 26140d78cb..086f34e69a 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -198,6 +198,8 @@ static inline void flush_icache_range(uintptr_t start, uintptr_t stop)
We prefer consistency across hosts on this. */
#define TCG_TARGET_DEFAULT_MO (0)
+#define TCG_TARGET_HAS_MEMORY_BSWAP 1
+
static inline void tb_target_set_jmp_target(uintptr_t tc_ptr,
uintptr_t jmp_addr, uintptr_t addr)
{
diff --git a/tcg/tci/tcg-target.inc.c b/tcg/tci/tcg-target.inc.c
index 62ed097254..0015a98485 100644
--- a/tcg/tci/tcg-target.inc.c
+++ b/tcg/tci/tcg-target.inc.c
@@ -369,7 +369,7 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
};
#endif
-static void patch_reloc(tcg_insn_unit *code_ptr, int type,
+static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
intptr_t value, intptr_t addend)
{
/* tcg_out_reloc always uses the same type, addend. */
@@ -381,6 +381,7 @@ static void patch_reloc(tcg_insn_unit *code_ptr, int type,
} else {
tcg_patch64(code_ptr, value);
}
+ return true;
}
/* Parse target specific constraints. */
diff --git a/tests/Makefile.include b/tests/Makefile.include
index fb0b449c02..4eea38ae99 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -3,7 +3,8 @@
check-help:
@echo "Regression testing targets:"
@echo
- @echo " $(MAKE) check Run all tests"
+ @echo " $(MAKE) check Run unit, qapi-schema, qtest and decodetree"
+ @echo
@echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target"
@echo " $(MAKE) check-qtest Run qtest tests"
@echo " $(MAKE) check-unit Run qobject tests"
@@ -12,12 +13,13 @@ check-help:
@echo " $(MAKE) check-block Run block tests"
@echo " $(MAKE) check-tcg Run TCG tests"
@echo " $(MAKE) check-acceptance Run all acceptance (functional) tests"
+ @echo
@echo " $(MAKE) check-report.html Generates an HTML test report"
@echo " $(MAKE) check-venv Creates a Python venv for tests"
- @echo " $(MAKE) check-clean Clean the tests"
+ @echo " $(MAKE) check-clean Clean the tests and related data"
@echo
@echo "Please note that HTML reports do not regenerate if the unit tests"
- @echo "has not changed."
+ @echo "have not changed."
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@echo "Default options are -k and (for $(MAKE) V=1) --verbose; they can be"
@@ -107,7 +109,7 @@ check-unit-y += tests/test-crypto-secret$(EXESUF)
check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF)
check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF)
ifneq (,$(findstring qemu-ga,$(TOOLS)))
-check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF)
+check-unit-$(land,$(CONFIG_LINUX),$(CONFIG_VIRTIO_SERIAL)) += tests/test-qga$(EXESUF)
endif
check-unit-y += tests/test-timed-average$(EXESUF)
check-unit-y += tests/test-util-sockets$(EXESUF)
@@ -143,17 +145,17 @@ check-qtest-generic-y += tests/cdrom-test$(EXESUF)
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
-check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF)
+check-qtest-virtioserial-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-console-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
-check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_NET) += tests/virtio-net-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_BALLOON) += tests/virtio-balloon-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_RNG) += tests/virtio-rng-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_SCSI) += tests/virtio-scsi-test$(EXESUF)
ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
-check-qtest-virtio-y += tests/virtio-9p-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_9P) += tests/virtio-9p-test$(EXESUF)
endif
-check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
+check-qtest-virtio-$(CONFIG_VIRTIO_SERIAL) += tests/virtio-serial-test$(EXESUF)
check-qtest-virtio-y += $(check-qtest-virtioserial-y)
check-qtest-pci-y += tests/e1000-test$(EXESUF)
@@ -165,13 +167,13 @@ check-qtest-pci-$(CONFIG_NE2000_PCI) += tests/ne2000-test$(EXESUF)
check-qtest-pci-$(CONFIG_NVME_PCI) += tests/nvme-test$(EXESUF)
check-qtest-pci-$(CONFIG_AC97) += tests/ac97-test$(EXESUF)
check-qtest-pci-$(CONFIG_ES1370) += tests/es1370-test$(EXESUF)
-check-qtest-pci-y += $(check-qtest-virtio-y)
+check-qtest-pci-$(CONFIG_VIRTIO) += $(check-qtest-virtio-y)
check-qtest-pci-$(CONFIG_IPACK) += tests/tpci200-test$(EXESUF)
check-qtest-pci-$(CONFIG_IPACK) += $(check-qtest-ipack-y)
-check-qtest-pci-y += tests/display-vga-test$(EXESUF)
+check-qtest-pci-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-pci-$(CONFIG_HDA) += tests/intel-hda-test$(EXESUF)
check-qtest-pci-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
-check-qtest-pci-y += tests/megasas-test$(EXESUF)
+check-qtest-pci-$(CONFIG_MEGASAS_SCSI_PCI) += tests/megasas-test$(EXESUF)
check-qtest-i386-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -183,8 +185,9 @@ check-qtest-i386-y += tests/bios-tables-test$(EXESUF)
check-qtest-i386-$(CONFIG_SGA) += tests/boot-serial-test$(EXESUF)
check-qtest-i386-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
check-qtest-i386-y += tests/rtc-test$(EXESUF)
-check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF)
-check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF)
+check-qtest-i386-$(CONFIG_ISA_IPMI_KCS) += tests/ipmi-kcs-test$(EXESUF)
+# Disabled temporarily as it fails intermittently especially under NetBSD VM
+# check-qtest-i386-$(CONFIG_ISA_IPMI_BT) += tests/ipmi-bt-test$(EXESUF)
check-qtest-i386-y += tests/i440fx-test$(EXESUF)
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-i386-y += tests/drive_del-test$(EXESUF)
@@ -222,18 +225,23 @@ check-qtest-x86_64-y += $(check-qtest-i386-y)
check-qtest-x86_64-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
check-qtest-alpha-y += tests/boot-serial-test$(EXESUF)
+check-qtest-alpha-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-hppa-y += tests/boot-serial-test$(EXESUF)
+check-qtest-hppa-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-m68k-y = tests/boot-serial-test$(EXESUF)
check-qtest-microblaze-y += tests/boot-serial-test$(EXESUF)
check-qtest-mips-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
+check-qtest-mips-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-mips64-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
+check-qtest-mips64-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-mips64el-$(CONFIG_ISA_TESTDEV) = tests/endianness-test$(EXESUF)
+check-qtest-mips64el-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-moxie-y += tests/boot-serial-test$(EXESUF)
@@ -242,22 +250,22 @@ check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc-y += tests/prom-env-test$(EXESUF)
check-qtest-ppc-y += tests/drive_del-test$(EXESUF)
check-qtest-ppc-y += tests/boot-serial-test$(EXESUF)
-check-qtest-ppc-y += tests/m48t59-test$(EXESUF)
+check-qtest-ppc-$(CONFIG_M48T59) += tests/m48t59-test$(EXESUF)
check-qtest-ppc64-y += $(check-qtest-ppc-y)
-check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
-check-qtest-ppc64-y += tests/pnv-xscom-test$(EXESUF)
+check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF)
+check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF)
check-qtest-ppc64-y += tests/migration-test$(EXESUF)
-check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
+check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_USB_UHCI) += tests/usb-hcd-uhci-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_USB_XHCI_NEC) += tests/usb-hcd-xhci-test$(EXESUF)
-check-qtest-ppc64-y += $(check-qtest-virtio-y)
+check-qtest-ppc64-$(CONFIG_VIRTIO) += $(check-qtest-virtio-y)
check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF)
check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF)
check-qtest-ppc64-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF)
-check-qtest-ppc64-y += tests/display-vga-test$(EXESUF)
+check-qtest-ppc64-$(CONFIG_VGA) += tests/display-vga-test$(EXESUF)
check-qtest-ppc64-y += tests/numa-test$(EXESUF)
check-qtest-ppc64-$(CONFIG_IVSHMEM_DEVICE) += tests/ivshmem-test$(EXESUF)
check-qtest-ppc64-y += tests/cpu-plug-test$(EXESUF)
@@ -277,8 +285,9 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-y += tests/tmp105-test$(EXESUF)
check-qtest-arm-y += tests/pca9552-test$(EXESUF)
check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/microbit-test$(EXESUF)
check-qtest-arm-y += tests/m25p80-test$(EXESUF)
-check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
+check-qtest-arm-$(CONFIG_VIRTIO_BLK) += tests/virtio-blk-test$(EXESUF)
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-$(CONFIG_SDHCI) += tests/sdhci-test$(EXESUF)
@@ -318,6 +327,7 @@ qapi-schema += alternate-conflict-string.json
qapi-schema += alternate-conflict-bool-string.json
qapi-schema += alternate-conflict-num-string.json
qapi-schema += alternate-empty.json
+qapi-schema += alternate-invalid-dict.json
qapi-schema += alternate-nested.json
qapi-schema += alternate-unknown.json
qapi-schema += args-alternate.json
@@ -379,10 +389,12 @@ qapi-schema += double-data.json
qapi-schema += double-type.json
qapi-schema += duplicate-key.json
qapi-schema += empty.json
+qapi-schema += enum-bad-member.json
qapi-schema += enum-bad-name.json
qapi-schema += enum-bad-prefix.json
qapi-schema += enum-clash-member.json
-qapi-schema += enum-dict-member.json
+qapi-schema += enum-dict-member-unknown.json
+qapi-schema += enum-if-invalid.json
qapi-schema += enum-int-member.json
qapi-schema += enum-member-case.json
qapi-schema += enum-missing-data.json
@@ -392,6 +404,7 @@ qapi-schema += escape-too-big.json
qapi-schema += escape-too-short.json
qapi-schema += event-boxed-empty.json
qapi-schema += event-case.json
+qapi-schema += event-member-invalid-dict.json
qapi-schema += event-nest-struct.json
qapi-schema += flat-union-array-branch.json
qapi-schema += flat-union-bad-base.json
@@ -401,9 +414,11 @@ qapi-schema += flat-union-base-union.json
qapi-schema += flat-union-clash-member.json
qapi-schema += flat-union-empty.json
qapi-schema += flat-union-inline.json
+qapi-schema += flat-union-inline-invalid-dict.json
qapi-schema += flat-union-int-branch.json
qapi-schema += flat-union-invalid-branch-key.json
qapi-schema += flat-union-invalid-discriminator.json
+qapi-schema += flat-union-invalid-if-discriminator.json
qapi-schema += flat-union-no-base.json
qapi-schema += flat-union-optional-discriminator.json
qapi-schema += flat-union-string-discriminator.json
@@ -428,6 +443,7 @@ qapi-schema += missing-comma-list.json
qapi-schema += missing-comma-object.json
qapi-schema += missing-type.json
qapi-schema += nested-struct-data.json
+qapi-schema += nested-struct-data-invalid-dict.json
qapi-schema += non-objects.json
qapi-schema += oob-test.json
qapi-schema += allow-preconfig-test.json
@@ -458,6 +474,7 @@ qapi-schema += returns-whitelist.json
qapi-schema += struct-base-clash-deep.json
qapi-schema += struct-base-clash.json
qapi-schema += struct-data-invalid.json
+qapi-schema += struct-member-invalid-dict.json
qapi-schema += struct-member-invalid.json
qapi-schema += trailing-comma-list.json
qapi-schema += trailing-comma-object.json
@@ -469,6 +486,7 @@ qapi-schema += unicode-str.json
qapi-schema += union-base-empty.json
qapi-schema += union-base-no-discriminator.json
qapi-schema += union-branch-case.json
+qapi-schema += union-branch-invalid-dict.json
qapi-schema += union-clash-branches.json
qapi-schema += union-empty.json
qapi-schema += union-invalid-base.json
@@ -699,6 +717,7 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/microbit-test$(EXESUF): tests/microbit-test.o
tests/m25p80-test$(EXESUF): tests/m25p80-test.o
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
@@ -729,7 +748,6 @@ tests/qom-test$(EXESUF): tests/qom-test.o
tests/test-hmp$(EXESUF): tests/test-hmp.o
tests/machine-none-test$(EXESUF): tests/machine-none-test.o
tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y)
-tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
tests/nvme-test$(EXESUF): tests/nvme-test.o $(libqos-pc-obj-y)
tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
@@ -799,41 +817,68 @@ tests/test-qga$(EXESUF): qemu-ga$(EXESUF)
tests/test-qga$(EXESUF): tests/test-qga.o $(qtest-obj-y)
SPEED = quick
-GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
-GCOV_OPTIONS = -n $(if $(V),-f,)
# gtester tests, possibly with verbose output
+# do_test_tap runs all tests, even if some of them fail, while do_test_human
+# stops at the first failure unless -k is given on the command line
+
+define do_test_human_k
+ $(quiet-@)rc=0; $(foreach COMMAND, $1, \
+ $(call quiet-command-run, \
+ export MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} $2; \
+ $(COMMAND) -m=$(SPEED) -k --tap < /dev/null \
+ | ./scripts/tap-driver.pl --test-name="$(notdir $(COMMAND))" $(if $(V),, --show-failures-only) \
+ || rc=$$?;, "TEST", "$@: $(COMMAND)")) exit $$rc
+endef
+define do_test_human_no_k
+ $(foreach COMMAND, $1, \
+ $(call quiet-command, \
+ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} $2 \
+ $(COMMAND) -m=$(SPEED) -k --tap < /dev/null \
+ | ./scripts/tap-driver.pl --test-name="$(notdir $(COMMAND))" $(if $(V),, --show-failures-only), \
+ "TEST", "$@: $(COMMAND)")
+)
+endef
+do_test_human = \
+ $(if $(findstring k, $(MAKEFLAGS)), $(do_test_human_k), $(do_test_human_no_k))
+
+define do_test_tap
+ $(call quiet-command, \
+ { export MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} $2; \
+ $(foreach COMMAND, $1, \
+ $(COMMAND) -m=$(SPEED) -k --tap < /dev/null \
+ | sed "s/^[a-z][a-z]* [0-9]* /&$(notdir $(COMMAND)) /" || true; ) } \
+ | ./scripts/tap-merge.pl | tee "$@" \
+ | ./scripts/tap-driver.pl $(if $(V),, --show-failures-only), \
+ "TAP","$@")
+endef
.PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: subdir-%-softmmu $(check-qtest-y)
- $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
- QTEST_QEMU_IMG=qemu-img$(EXESUF) \
- MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} \
- gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@")
+ $(call do_test_human,$(check-qtest-$*-y) $(check-qtest-generic-y), \
+ QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+ QTEST_QEMU_IMG=qemu-img$(EXESUF))
-.PHONY: $(patsubst %, check-%, $(check-unit-y) $(check-speed-y))
-$(patsubst %, check-%, $(check-unit-y) $(check-speed-y)): check-%: %
- $(call quiet-command, \
- MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$(( $${RANDOM:-0} % 255 + 1))} \
- gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER","$*")
+check-unit: $(check-unit-y)
+ $(call do_test_human, $^)
-# gtester tests with XML output
+check-speed: $(check-speed-y)
+ $(call do_test_human, $^)
-$(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y)
- $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
- QTEST_QEMU_IMG=qemu-img$(EXESUF) \
- gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER","$@")
+# gtester tests with TAP output
-check-report-unit.xml: $(check-unit-y)
- $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^,"GTESTER","$@")
+$(patsubst %, check-report-qtest-%.tap, $(QTEST_TARGETS)): check-report-qtest-%.tap: $(check-qtest-y)
+ $(call do_test_tap, $(check-qtest-$*-y) $(check-qtest-generic-y), \
+ QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+ QTEST_QEMU_IMG=qemu-img$(EXESUF))
-# Reports and overall runs
+check-report-unit.tap: $(check-unit-y)
+ $(call do_test_tap,$^)
-check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml
- $(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@,"GEN","$@")
+# Reports and overall runs
-check-report.html: check-report.xml
- $(call quiet-command,gtester-report $< > $@,"GEN","$@")
+check-report.tap: $(patsubst %,check-report-qtest-%.tap, $(QTEST_TARGETS)) check-report-unit.tap
+ $(call quiet-command,./scripts/tap-merge.py $^ > $@,"GEN","$@")
# Per guest TCG tests
@@ -915,8 +960,7 @@ TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results
# information please refer to "avocado --help".
AVOCADO_SHOW=none
-PYTHON3 = $(shell $(PYTHON) -c 'import sys; print(1 if sys.version_info >= (3, 0) else 0)')
-ifeq ($(PYTHON3), 1)
+ifneq ($(findstring v2,"v$(PYTHON_VERSION)"),v2)
$(TESTS_VENV_DIR): $(TESTS_VENV_REQ)
$(call quiet-command, \
$(PYTHON) -m venv --system-site-packages $@, \
@@ -948,8 +992,6 @@ check-acceptance: check-venv $(TESTS_RESULTS_DIR)
.PHONY: check-qapi-schema check-qtest check-unit check check-clean
check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y)) check-tests/qapi-schema/doc-good.texi
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
-check-unit: $(patsubst %,check-%, $(check-unit-y))
-check-speed: $(patsubst %,check-%, $(check-speed-y))
check-block: $(patsubst %,check-%, $(check-block-y))
check: check-qapi-schema check-unit check-qtest check-decodetree
check-clean:
diff --git a/tests/acceptance/linux_initrd.py b/tests/acceptance/linux_initrd.py
new file mode 100644
index 0000000000..737355c2ef
--- /dev/null
+++ b/tests/acceptance/linux_initrd.py
@@ -0,0 +1,48 @@
+# Linux initrd acceptance test.
+#
+# Copyright (c) 2018 Red Hat, Inc.
+#
+# Author:
+# Wainer dos Santos Moschetta <wainersm@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.
+
+import tempfile
+from avocado.utils.process import run
+
+from avocado_qemu import Test
+
+
+class LinuxInitrd(Test):
+ """
+ Checks QEMU evaluates correctly the initrd file passed as -initrd option.
+
+ :avocado: enable
+ :avocado: tags=x86_64
+ """
+
+ timeout = 60
+
+ def test_with_2gib_file_should_exit_error_msg(self):
+ """
+ Pretends to boot QEMU with an initrd file with size of 2GiB
+ and expect it exits with error message.
+ """
+ kernel_url = ('https://mirrors.kernel.org/fedora/releases/28/'
+ 'Everything/x86_64/os/images/pxeboot/vmlinuz')
+ kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ max_size = 2 * (1024 ** 3) - 1
+
+ with tempfile.NamedTemporaryFile() as initrd:
+ initrd.seek(max_size)
+ initrd.write(b'\0')
+ initrd.flush()
+ cmd = "%s -kernel %s -initrd %s" % (self.qemu_bin, kernel_path,
+ initrd.name)
+ res = run(cmd, ignore_status=True)
+ self.assertEqual(res.exit_status, 1)
+ expected_msg = r'.*initrd is too large.*max: \d+, need %s.*' % (
+ max_size + 1)
+ self.assertRegex(res.stderr_text, expected_msg)
diff --git a/tests/acceptance/virtio_version.py b/tests/acceptance/virtio_version.py
new file mode 100644
index 0000000000..ce990250d8
--- /dev/null
+++ b/tests/acceptance/virtio_version.py
@@ -0,0 +1,176 @@
+"""
+Check compatibility of virtio device types
+"""
+# Copyright (c) 2018 Red Hat, Inc.
+#
+# Author:
+# Eduardo Habkost <ehabkost@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.
+import sys
+import os
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "scripts"))
+from qemu import QEMUMachine
+from avocado_qemu import Test
+
+# Virtio Device IDs:
+VIRTIO_NET = 1
+VIRTIO_BLOCK = 2
+VIRTIO_CONSOLE = 3
+VIRTIO_RNG = 4
+VIRTIO_BALLOON = 5
+VIRTIO_RPMSG = 7
+VIRTIO_SCSI = 8
+VIRTIO_9P = 9
+VIRTIO_RPROC_SERIAL = 11
+VIRTIO_CAIF = 12
+VIRTIO_GPU = 16
+VIRTIO_INPUT = 18
+VIRTIO_VSOCK = 19
+VIRTIO_CRYPTO = 20
+
+PCI_VENDOR_ID_REDHAT_QUMRANET = 0x1af4
+
+# Device IDs for legacy/transitional devices:
+PCI_LEGACY_DEVICE_IDS = {
+ VIRTIO_NET: 0x1000,
+ VIRTIO_BLOCK: 0x1001,
+ VIRTIO_BALLOON: 0x1002,
+ VIRTIO_CONSOLE: 0x1003,
+ VIRTIO_SCSI: 0x1004,
+ VIRTIO_RNG: 0x1005,
+ VIRTIO_9P: 0x1009,
+ VIRTIO_VSOCK: 0x1012,
+}
+
+def pci_modern_device_id(virtio_devid):
+ return virtio_devid + 0x1040
+
+def devtype_implements(vm, devtype, implements):
+ return devtype in [d['name'] for d in vm.command('qom-list-types', implements=implements)]
+
+def get_pci_interfaces(vm, devtype):
+ interfaces = ('pci-express-device', 'conventional-pci-device')
+ return [i for i in interfaces if devtype_implements(vm, devtype, i)]
+
+class VirtioVersionCheck(Test):
+ """
+ Check if virtio-version-specific device types result in the
+ same device tree created by `disable-modern` and
+ `disable-legacy`.
+
+ :avocado: enable
+ :avocado: tags=x86_64
+ """
+
+ # just in case there are failures, show larger diff:
+ maxDiff = 4096
+
+ def run_device(self, devtype, opts=None, machine='pc'):
+ """
+ Run QEMU with `-device DEVTYPE`, return device info from `query-pci`
+ """
+ with QEMUMachine(self.qemu_bin) as vm:
+ vm.set_machine(machine)
+ if opts:
+ devtype += ',' + opts
+ vm.add_args('-device', '%s,id=devfortest' % (devtype))
+ vm.add_args('-S')
+ vm.launch()
+
+ pcibuses = vm.command('query-pci')
+ alldevs = [dev for bus in pcibuses for dev in bus['devices']]
+ devfortest = [dev for dev in alldevs
+ if dev['qdev_id'] == 'devfortest']
+ return devfortest[0], get_pci_interfaces(vm, devtype)
+
+
+ def assert_devids(self, dev, devid, non_transitional=False):
+ self.assertEqual(dev['id']['vendor'], PCI_VENDOR_ID_REDHAT_QUMRANET)
+ self.assertEqual(dev['id']['device'], devid)
+ if non_transitional:
+ self.assertTrue(0x1040 <= dev['id']['device'] <= 0x107f)
+ self.assertGreaterEqual(dev['id']['subsystem'], 0x40)
+
+ def check_all_variants(self, qemu_devtype, virtio_devid):
+ """Check if a virtio device type and its variants behave as expected"""
+ # Force modern mode:
+ dev_modern, _ = self.run_device(qemu_devtype,
+ 'disable-modern=off,disable-legacy=on')
+ self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid),
+ non_transitional=True)
+
+ # <prefix>-non-transitional device types should be 100% equivalent to
+ # <prefix>,disable-modern=off,disable-legacy=on
+ dev_1_0, nt_ifaces = self.run_device('%s-non-transitional' % (qemu_devtype))
+ self.assertEqual(dev_modern, dev_1_0)
+
+ # Force transitional mode:
+ dev_trans, _ = self.run_device(qemu_devtype,
+ 'disable-modern=off,disable-legacy=off')
+ self.assert_devids(dev_trans, PCI_LEGACY_DEVICE_IDS[virtio_devid])
+
+ # Force legacy mode:
+ dev_legacy, _ = self.run_device(qemu_devtype,
+ 'disable-modern=on,disable-legacy=off')
+ self.assert_devids(dev_legacy, PCI_LEGACY_DEVICE_IDS[virtio_devid])
+
+ # No options: default to transitional on PC machine-type:
+ no_opts_pc, generic_ifaces = self.run_device(qemu_devtype)
+ self.assertEqual(dev_trans, no_opts_pc)
+
+ #TODO: check if plugging on a PCI Express bus will make the
+ # device non-transitional
+ #no_opts_q35 = self.run_device(qemu_devtype, machine='q35')
+ #self.assertEqual(dev_modern, no_opts_q35)
+
+ # <prefix>-transitional device types should be 100% equivalent to
+ # <prefix>,disable-modern=off,disable-legacy=off
+ dev_trans, trans_ifaces = self.run_device('%s-transitional' % (qemu_devtype))
+ self.assertEqual(dev_trans, dev_trans)
+
+ # ensure the interface information is correct:
+ self.assertIn('conventional-pci-device', generic_ifaces)
+ self.assertIn('pci-express-device', generic_ifaces)
+
+ self.assertIn('conventional-pci-device', nt_ifaces)
+ self.assertIn('pci-express-device', nt_ifaces)
+
+ self.assertIn('conventional-pci-device', trans_ifaces)
+ self.assertNotIn('pci-express-device', trans_ifaces)
+
+
+ def test_conventional_devs(self):
+ self.check_all_variants('virtio-net-pci', VIRTIO_NET)
+ # virtio-blk requires 'driver' parameter
+ #self.check_all_variants('virtio-blk-pci', VIRTIO_BLOCK)
+ self.check_all_variants('virtio-serial-pci', VIRTIO_CONSOLE)
+ self.check_all_variants('virtio-rng-pci', VIRTIO_RNG)
+ self.check_all_variants('virtio-balloon-pci', VIRTIO_BALLOON)
+ self.check_all_variants('virtio-scsi-pci', VIRTIO_SCSI)
+ # virtio-9p requires 'fsdev' parameter
+ #self.check_all_variants('virtio-9p-pci', VIRTIO_9P)
+
+ def check_modern_only(self, qemu_devtype, virtio_devid):
+ """Check if a modern-only virtio device type behaves as expected"""
+ # Force modern mode:
+ dev_modern, _ = self.run_device(qemu_devtype,
+ 'disable-modern=off,disable-legacy=on')
+ self.assert_devids(dev_modern, pci_modern_device_id(virtio_devid),
+ non_transitional=True)
+
+ # No options: should be modern anyway
+ dev_no_opts, ifaces = self.run_device(qemu_devtype)
+ self.assertEqual(dev_modern, dev_no_opts)
+
+ self.assertIn('conventional-pci-device', ifaces)
+ self.assertIn('pci-express-device', ifaces)
+
+ def test_modern_only_devs(self):
+ self.check_modern_only('virtio-vga', VIRTIO_GPU)
+ self.check_modern_only('virtio-gpu-pci', VIRTIO_GPU)
+ self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT)
+ self.check_modern_only('virtio-tablet-pci', VIRTIO_INPUT)
+ self.check_modern_only('virtio-keyboard-pci', VIRTIO_INPUT)
diff --git a/tests/acpi-utils.c b/tests/acpi-utils.c
index 41dc1ea9b4..cc33b460ab 100644
--- a/tests/acpi-utils.c
+++ b/tests/acpi-utils.c
@@ -15,7 +15,6 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "qemu-common.h"
-#include "hw/smbios/smbios.h"
#include "qemu/bitmap.h"
#include "acpi-utils.h"
#include "boot-sector.h"
@@ -32,7 +31,7 @@ uint8_t acpi_calc_checksum(const uint8_t *data, int len)
return sum;
}
-uint32_t acpi_find_rsdp_address(void)
+uint32_t acpi_find_rsdp_address(QTestState *qts)
{
uint32_t off;
@@ -42,7 +41,7 @@ uint32_t acpi_find_rsdp_address(void)
int i;
for (i = 0; i < sizeof sig - 1; ++i) {
- sig[i] = readb(off + i);
+ sig[i] = qtest_readb(qts, off + i);
}
if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
@@ -52,14 +51,63 @@ uint32_t acpi_find_rsdp_address(void)
return off;
}
-void acpi_parse_rsdp_table(uint32_t addr, AcpiRsdpDescriptor *rsdp_table)
+uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table)
{
- ACPI_READ_FIELD(rsdp_table->signature, addr);
- ACPI_ASSERT_CMP64(rsdp_table->signature, "RSD PTR ");
-
- ACPI_READ_FIELD(rsdp_table->checksum, addr);
- ACPI_READ_ARRAY(rsdp_table->oem_id, addr);
- ACPI_READ_FIELD(rsdp_table->revision, addr);
- ACPI_READ_FIELD(rsdp_table->rsdt_physical_address, addr);
- ACPI_READ_FIELD(rsdp_table->length, addr);
+ uint64_t xsdt_physical_address;
+ uint8_t revision = rsdp_table[15 /* Revision offset */];
+
+ /* We must have revision 2 if we're looking for an XSDT pointer */
+ g_assert(revision == 2);
+
+ memcpy(&xsdt_physical_address, &rsdp_table[24 /* XsdtAddress offset */], 8);
+ return le64_to_cpu(xsdt_physical_address);
+}
+
+void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
+{
+ uint8_t revision;
+
+ /* Read mandatory revision 0 table data (20 bytes) first */
+ qtest_memread(qts, addr, rsdp_table, 20);
+ revision = rsdp_table[15 /* Revision offset */];
+
+ switch (revision) {
+ case 0: /* ACPI 1.0 RSDP */
+ break;
+ case 2: /* ACPI 2.0+ RSDP */
+ /* Read the rest of the RSDP table */
+ qtest_memread(qts, addr + 20, rsdp_table + 20, 16);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ ACPI_ASSERT_CMP64(*((uint64_t *)(rsdp_table)), "RSD PTR ");
+}
+
+/** acpi_fetch_table
+ * load ACPI table at @addr_ptr offset pointer into buffer and return it in
+ * @aml, its length in @aml_len and check that signature/checksum matches
+ * actual one.
+ */
+void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
+ const uint8_t *addr_ptr, const char *sig,
+ bool verify_checksum)
+{
+ uint32_t addr, len;
+
+ memcpy(&addr, addr_ptr , sizeof(addr));
+ addr = le32_to_cpu(addr);
+ qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
+ *aml_len = le32_to_cpu(len);
+ *aml = g_malloc0(*aml_len);
+ /* get whole table */
+ qtest_memread(qts, addr, *aml, *aml_len);
+
+ if (sig) {
+ ACPI_ASSERT_CMP(**aml, sig);
+ }
+ if (verify_checksum) {
+ g_assert(!acpi_calc_checksum(*aml, *aml_len));
+ }
}
diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
index ac52abd0dd..ef388bbf12 100644
--- a/tests/acpi-utils.h
+++ b/tests/acpi-utils.h
@@ -13,14 +13,12 @@
#ifndef TEST_ACPI_UTILS_H
#define TEST_ACPI_UTILS_H
-#include "hw/acpi/acpi-defs.h"
#include "libqtest.h"
/* DSDT and SSDTs format */
typedef struct {
- AcpiTableHeader header;
- gchar *aml; /* aml bytecode from guest */
- gsize aml_len;
+ uint8_t *aml; /* aml bytecode from guest */
+ uint32_t aml_len;
gchar *aml_file;
gchar *asl; /* asl code generated from aml */
gsize asl_len;
@@ -28,36 +26,6 @@ typedef struct {
bool tmp_files_retain; /* do not delete the temp asl/aml */
} AcpiSdtTable;
-#define ACPI_READ_FIELD(field, addr) \
- do { \
- memread(addr, &field, sizeof(field)); \
- addr += sizeof(field); \
- } while (0)
-
-#define ACPI_READ_ARRAY_PTR(arr, length, addr) \
- do { \
- int idx; \
- for (idx = 0; idx < length; ++idx) { \
- ACPI_READ_FIELD(arr[idx], addr); \
- } \
- } while (0)
-
-#define ACPI_READ_ARRAY(arr, addr) \
- ACPI_READ_ARRAY_PTR(arr, sizeof(arr) / sizeof(arr[0]), addr)
-
-#define ACPI_READ_TABLE_HEADER(table, addr) \
- do { \
- ACPI_READ_FIELD((table)->signature, addr); \
- ACPI_READ_FIELD((table)->length, addr); \
- ACPI_READ_FIELD((table)->revision, addr); \
- ACPI_READ_FIELD((table)->checksum, addr); \
- ACPI_READ_ARRAY((table)->oem_id, addr); \
- ACPI_READ_ARRAY((table)->oem_table_id, addr); \
- ACPI_READ_FIELD((table)->oem_revision, addr); \
- ACPI_READ_ARRAY((table)->asl_compiler_id, addr); \
- ACPI_READ_FIELD((table)->asl_compiler_revision, addr); \
- } while (0)
-
#define ACPI_ASSERT_CMP(actual, expected) do { \
char ACPI_ASSERT_CMP_str[5] = {}; \
memcpy(ACPI_ASSERT_CMP_str, &actual, 4); \
@@ -70,18 +38,18 @@ typedef struct {
g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
} while (0)
-#define ACPI_READ_GENERIC_ADDRESS(field, addr) \
- do { \
- ACPI_READ_FIELD((field).space_id, addr); \
- ACPI_READ_FIELD((field).bit_width, addr); \
- ACPI_READ_FIELD((field).bit_offset, addr); \
- ACPI_READ_FIELD((field).access_width, addr); \
- ACPI_READ_FIELD((field).address, addr); \
- } while (0)
+#define ACPI_FOREACH_RSDT_ENTRY(table, table_len, entry_ptr, entry_size) \
+ for (entry_ptr = table + 36 /* 1st Entry */; \
+ entry_ptr < table + table_len; \
+ entry_ptr += entry_size)
uint8_t acpi_calc_checksum(const uint8_t *data, int len);
-uint32_t acpi_find_rsdp_address(void);
-void acpi_parse_rsdp_table(uint32_t addr, AcpiRsdpDescriptor *rsdp_table);
+uint32_t acpi_find_rsdp_address(QTestState *qts);
+uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table);
+void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table);
+void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
+ const uint8_t *addr_ptr, const char *sig,
+ bool verify_checksum);
#endif /* TEST_ACPI_UTILS_H */
diff --git a/tests/atomic64-bench.c b/tests/atomic64-bench.c
index 71692560ed..121a8c14f4 100644
--- a/tests/atomic64-bench.c
+++ b/tests/atomic64-bench.c
@@ -74,16 +74,14 @@ static void *thread_func(void *arg)
static void run_test(void)
{
- unsigned int remaining;
unsigned int i;
while (atomic_read(&n_ready_threads) != n_threads) {
cpu_relax();
}
+
atomic_set(&test_start, true);
- do {
- remaining = sleep(duration);
- } while (remaining);
+ g_usleep(duration * G_USEC_PER_SEC);
atomic_set(&test_stop, true);
for (i = 0; i < n_threads; i++) {
diff --git a/tests/atomic_add-bench.c b/tests/atomic_add-bench.c
index 2f6c72f63a..5666f6bbff 100644
--- a/tests/atomic_add-bench.c
+++ b/tests/atomic_add-bench.c
@@ -76,16 +76,14 @@ static void *thread_func(void *arg)
static void run_test(void)
{
- unsigned int remaining;
unsigned int i;
while (atomic_read(&n_ready_threads) != n_threads) {
cpu_relax();
}
+
atomic_set(&test_start, true);
- do {
- remaining = sleep(duration);
- } while (remaining);
+ g_usleep(duration * G_USEC_PER_SEC);
atomic_set(&test_stop, true);
for (i = 0; i < n_threads; i++) {
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index d661d9be62..a506dcbb29 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -13,7 +13,7 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "qemu-common.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "qemu/bitmap.h"
#include "acpi-utils.h"
#include "boot-sector.h"
@@ -27,18 +27,13 @@ typedef struct {
const char *machine;
const char *variant;
uint32_t rsdp_addr;
- AcpiRsdpDescriptor rsdp_table;
- AcpiRsdtDescriptorRev1 rsdt_table;
- uint32_t dsdt_addr;
- uint32_t facs_addr;
- AcpiFacsDescriptorRev1 facs_table;
- uint32_t *rsdt_tables_addr;
- int rsdt_tables_nr;
+ uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
GArray *tables;
uint32_t smbios_ep_addr;
struct smbios_21_entry_point smbios_ep_table;
uint8_t *required_struct_types;
int required_struct_types_len;
+ QTestState *qts;
} test_data;
static char disk[] = "tests/acpi-test-disk-XXXXXX";
@@ -49,28 +44,34 @@ static const char *iasl = stringify(CONFIG_IASL);
static const char *iasl;
#endif
+static bool compare_signature(const AcpiSdtTable *sdt, const char *signature)
+{
+ return !memcmp(sdt->aml, signature, 4);
+}
+
+static void cleanup_table_descriptor(AcpiSdtTable *table)
+{
+ g_free(table->aml);
+ if (table->aml_file &&
+ !table->tmp_files_retain &&
+ g_strstr_len(table->aml_file, -1, "aml-")) {
+ unlink(table->aml_file);
+ }
+ g_free(table->aml_file);
+ g_free(table->asl);
+ if (table->asl_file &&
+ !table->tmp_files_retain) {
+ unlink(table->asl_file);
+ }
+ g_free(table->asl_file);
+}
+
static void free_test_data(test_data *data)
{
- AcpiSdtTable *temp;
int i;
- g_free(data->rsdt_tables_addr);
-
for (i = 0; i < data->tables->len; ++i) {
- temp = &g_array_index(data->tables, AcpiSdtTable, i);
- g_free(temp->aml);
- if (temp->aml_file &&
- !temp->tmp_files_retain &&
- g_strstr_len(temp->aml_file, -1, "aml-")) {
- unlink(temp->aml_file);
- }
- g_free(temp->aml_file);
- g_free(temp->asl);
- if (temp->asl_file &&
- !temp->tmp_files_retain) {
- unlink(temp->asl_file);
- }
- g_free(temp->asl_file);
+ cleanup_table_descriptor(&g_array_index(data->tables, AcpiSdtTable, i));
}
g_array_free(data->tables, true);
@@ -78,172 +79,83 @@ static void free_test_data(test_data *data)
static void test_acpi_rsdp_address(test_data *data)
{
- uint32_t off = acpi_find_rsdp_address();
+ uint32_t off = acpi_find_rsdp_address(data->qts);
g_assert_cmphex(off, <, 0x100000);
data->rsdp_addr = off;
}
static void test_acpi_rsdp_table(test_data *data)
{
- AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table;
+ uint8_t *rsdp_table = data->rsdp_table, revision;
uint32_t addr = data->rsdp_addr;
- acpi_parse_rsdp_table(addr, rsdp_table);
-
- /* rsdp checksum is not for the whole table, but for the first 20 bytes */
- g_assert(!acpi_calc_checksum((uint8_t *)rsdp_table, 20));
-}
-
-static void test_acpi_rsdt_table(test_data *data)
-{
- AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table;
- uint32_t addr = le32_to_cpu(data->rsdp_table.rsdt_physical_address);
- uint32_t *tables;
- int tables_nr;
- uint8_t checksum;
- uint32_t rsdt_table_length;
-
- /* read the header */
- ACPI_READ_TABLE_HEADER(rsdt_table, addr);
- ACPI_ASSERT_CMP(rsdt_table->signature, "RSDT");
-
- rsdt_table_length = le32_to_cpu(rsdt_table->length);
-
- /* compute the table entries in rsdt */
- tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) /
- sizeof(uint32_t);
- g_assert(tables_nr > 0);
-
- /* get the addresses of the tables pointed by rsdt */
- tables = g_new0(uint32_t, tables_nr);
- ACPI_READ_ARRAY_PTR(tables, tables_nr, addr);
-
- checksum = acpi_calc_checksum((uint8_t *)rsdt_table, rsdt_table_length) +
- acpi_calc_checksum((uint8_t *)tables,
- tables_nr * sizeof(uint32_t));
- g_assert(!checksum);
-
- /* SSDT tables after FADT */
- data->rsdt_tables_addr = tables;
- data->rsdt_tables_nr = tables_nr;
-}
-
-static void fadt_fetch_facs_and_dsdt_ptrs(test_data *data)
-{
- uint32_t addr;
- AcpiTableHeader hdr;
-
- /* FADT table comes first */
- addr = le32_to_cpu(data->rsdt_tables_addr[0]);
- ACPI_READ_TABLE_HEADER(&hdr, addr);
- ACPI_ASSERT_CMP(hdr.signature, "FACP");
-
- ACPI_READ_FIELD(data->facs_addr, addr);
- ACPI_READ_FIELD(data->dsdt_addr, addr);
-}
-
-static void sanitize_fadt_ptrs(test_data *data)
-{
- /* fixup pointers in FADT */
- int i;
-
- for (i = 0; i < data->tables->len; i++) {
- AcpiSdtTable *sdt = &g_array_index(data->tables, AcpiSdtTable, i);
-
- if (memcmp(&sdt->header.signature, "FACP", 4)) {
- continue;
- }
-
- /* check original FADT checksum before sanitizing table */
- g_assert(!(uint8_t)(
- acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) +
- acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len)
- ));
-
- /* sdt->aml field offset := spec offset - header size */
- memset(sdt->aml + 0, 0, 4); /* sanitize FIRMWARE_CTRL(36) ptr */
- memset(sdt->aml + 4, 0, 4); /* sanitize DSDT(40) ptr */
- if (sdt->header.revision >= 3) {
- memset(sdt->aml + 96, 0, 8); /* sanitize X_FIRMWARE_CTRL(132) ptr */
- memset(sdt->aml + 104, 0, 8); /* sanitize X_DSDT(140) ptr */
- }
+ acpi_parse_rsdp_table(data->qts, addr, rsdp_table);
+ revision = rsdp_table[15 /* Revision offset */];
- /* update checksum */
- sdt->header.checksum = 0;
- sdt->header.checksum -=
- acpi_calc_checksum((uint8_t *)sdt, sizeof(AcpiTableHeader)) +
- acpi_calc_checksum((uint8_t *)sdt->aml, sdt->aml_len);
+ switch (revision) {
+ case 0: /* ACPI 1.0 RSDP */
+ /* With rev 1, checksum is only for the first 20 bytes */
+ g_assert(!acpi_calc_checksum(rsdp_table, 20));
break;
+ case 2: /* ACPI 2.0+ RSDP */
+ /* With revision 2, we have 2 checksums */
+ g_assert(!acpi_calc_checksum(rsdp_table, 20));
+ g_assert(!acpi_calc_checksum(rsdp_table, 36));
+ break;
+ default:
+ g_assert_not_reached();
}
}
-static void test_acpi_facs_table(test_data *data)
-{
- AcpiFacsDescriptorRev1 *facs_table = &data->facs_table;
- uint32_t addr = le32_to_cpu(data->facs_addr);
-
- ACPI_READ_FIELD(facs_table->signature, addr);
- ACPI_READ_FIELD(facs_table->length, addr);
- ACPI_READ_FIELD(facs_table->hardware_signature, addr);
- ACPI_READ_FIELD(facs_table->firmware_waking_vector, addr);
- ACPI_READ_FIELD(facs_table->global_lock, addr);
- ACPI_READ_FIELD(facs_table->flags, addr);
- ACPI_READ_ARRAY(facs_table->resverved3, addr);
-
- ACPI_ASSERT_CMP(facs_table->signature, "FACS");
-}
-
-/** fetch_table
- * load ACPI table at @addr into table descriptor @sdt_table
- * and check that header checksum matches actual one.
- */
-static void fetch_table(AcpiSdtTable *sdt_table, uint32_t addr)
+static void test_acpi_rsdt_table(test_data *data)
{
- uint8_t checksum;
+ AcpiSdtTable rsdt = {};
+ uint8_t *ent;
- memset(sdt_table, 0, sizeof(*sdt_table));
- ACPI_READ_TABLE_HEADER(&sdt_table->header, addr);
+ /* read RSDT table */
+ acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
+ &data->rsdp_table[16 /* RsdtAddress */], "RSDT", true);
- sdt_table->aml_len = le32_to_cpu(sdt_table->header.length)
- - sizeof(AcpiTableHeader);
- sdt_table->aml = g_malloc0(sdt_table->aml_len);
- ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr);
+ /* Load all tables and add to test list directly RSDT referenced tables */
+ ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, 4 /* Entry size */) {
+ AcpiSdtTable ssdt_table = {};
- checksum = acpi_calc_checksum((uint8_t *)sdt_table,
- sizeof(AcpiTableHeader)) +
- acpi_calc_checksum((uint8_t *)sdt_table->aml,
- sdt_table->aml_len);
- g_assert(!checksum);
+ acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
+ NULL, true);
+ /* Add table to ASL test tables list */
+ g_array_append_val(data->tables, ssdt_table);
+ }
+ cleanup_table_descriptor(&rsdt);
}
-static void test_acpi_dsdt_table(test_data *data)
+static void test_acpi_fadt_table(test_data *data)
{
- AcpiSdtTable dsdt_table;
- uint32_t addr = le32_to_cpu(data->dsdt_addr);
-
- fetch_table(&dsdt_table, addr);
- ACPI_ASSERT_CMP(dsdt_table.header.signature, "DSDT");
-
- /* Since DSDT isn't in RSDT, add DSDT to ASL test tables list manually */
- g_array_append_val(data->tables, dsdt_table);
-}
+ /* FADT table is 1st */
+ AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
+ uint8_t *fadt_aml = table.aml;
+ uint32_t fadt_len = table.aml_len;
-/* Load all tables and add to test list directly RSDT referenced tables */
-static void fetch_rsdt_referenced_tables(test_data *data)
-{
- int tables_nr = data->rsdt_tables_nr;
- int i;
+ g_assert(compare_signature(&table, "FACP"));
- for (i = 0; i < tables_nr; i++) {
- AcpiSdtTable ssdt_table;
- uint32_t addr;
+ /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
+ acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
+ fadt_aml + 36 /* FIRMWARE_CTRL */, "FACS", false);
+ g_array_append_val(data->tables, table);
- addr = le32_to_cpu(data->rsdt_tables_addr[i]);
- fetch_table(&ssdt_table, addr);
+ acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
+ fadt_aml + 40 /* DSDT */, "DSDT", true);
+ g_array_append_val(data->tables, table);
- /* Add table to ASL test tables list */
- g_array_append_val(data->tables, ssdt_table);
+ memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
+ memset(fadt_aml + 40, 0, 4); /* sanitize DSDT ptr */
+ if (fadt_aml[8 /* FADT Major Version */] >= 3) {
+ memset(fadt_aml + 132, 0, 8); /* sanitize X_FIRMWARE_CTRL ptr */
+ memset(fadt_aml + 140, 0, 8); /* sanitize X_DSDT ptr */
}
+
+ /* update checksum */
+ fadt_aml[9 /* Checksum */] = 0;
+ fadt_aml[9 /* Checksum */] -= acpi_calc_checksum(fadt_aml, fadt_len);
}
static void dump_aml_files(test_data *data, bool rebuild)
@@ -262,7 +174,7 @@ static void dump_aml_files(test_data *data, bool rebuild)
if (rebuild) {
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
- (gchar *)&sdt->header.signature, ext);
+ sdt->aml, ext);
fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
} else {
@@ -271,8 +183,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
}
g_assert(fd >= 0);
- ret = qemu_write_full(fd, sdt, sizeof(AcpiTableHeader));
- g_assert(ret == sizeof(AcpiTableHeader));
ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
g_assert(ret == sdt->aml_len);
@@ -282,11 +192,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
}
}
-static bool compare_signature(AcpiSdtTable *sdt, const char *signature)
-{
- return !memcmp(&sdt->header.signature, signature, 4);
-}
-
static bool load_asl(GArray *sdts, AcpiSdtTable *sdt)
{
AcpiSdtTable *temp;
@@ -369,8 +274,12 @@ static GArray *load_expected_aml(test_data *data)
AcpiSdtTable *sdt;
GError *error = NULL;
gboolean ret;
+ gsize aml_len;
GArray *exp_tables = g_array_new(false, true, sizeof(AcpiSdtTable));
+ if (getenv("V")) {
+ fputc('\n', stderr);
+ }
for (i = 0; i < data->tables->len; ++i) {
AcpiSdtTable exp_sdt;
gchar *aml_file = NULL;
@@ -379,13 +288,12 @@ static GArray *load_expected_aml(test_data *data)
sdt = &g_array_index(data->tables, AcpiSdtTable, i);
memset(&exp_sdt, 0, sizeof(exp_sdt));
- exp_sdt.header.signature = sdt->header.signature;
try_again:
aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
- (gchar *)&sdt->header.signature, ext);
+ sdt->aml, ext);
if (getenv("V")) {
- fprintf(stderr, "\nLooking for expected file '%s'\n", aml_file);
+ fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
}
if (g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
exp_sdt.aml_file = aml_file;
@@ -397,10 +305,11 @@ try_again:
}
g_assert(exp_sdt.aml_file);
if (getenv("V")) {
- fprintf(stderr, "\nUsing expected file '%s'\n", aml_file);
+ fprintf(stderr, "Using expected file '%s'\n", aml_file);
}
- ret = g_file_get_contents(aml_file, &exp_sdt.aml,
- &exp_sdt.aml_len, &error);
+ ret = g_file_get_contents(aml_file, (gchar **)&exp_sdt.aml,
+ &aml_len, &error);
+ exp_sdt.aml_len = aml_len;
g_assert(ret);
g_assert_no_error(error);
g_assert(exp_sdt.aml);
@@ -443,14 +352,12 @@ static void test_acpi_asl(test_data *data)
fprintf(stderr,
"Warning! iasl couldn't parse the expected aml\n");
} else {
- uint32_t signature = cpu_to_le32(exp_sdt->header.signature);
sdt->tmp_files_retain = true;
exp_sdt->tmp_files_retain = true;
fprintf(stderr,
"acpi-test: Warning! %.4s mismatch. "
"Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n",
- (gchar *)&signature,
- sdt->asl_file, sdt->aml_file,
+ exp_sdt->aml, sdt->asl_file, sdt->aml_file,
exp_sdt->asl_file, exp_sdt->aml_file);
if (getenv("V")) {
const char *diff_cmd = getenv("DIFF");
@@ -482,32 +389,19 @@ static bool smbios_ep_table_ok(test_data *data)
struct smbios_21_entry_point *ep_table = &data->smbios_ep_table;
uint32_t addr = data->smbios_ep_addr;
- ACPI_READ_ARRAY(ep_table->anchor_string, addr);
+ qtest_memread(data->qts, addr, ep_table, sizeof(*ep_table));
if (memcmp(ep_table->anchor_string, "_SM_", 4)) {
return false;
}
- ACPI_READ_FIELD(ep_table->checksum, addr);
- ACPI_READ_FIELD(ep_table->length, addr);
- ACPI_READ_FIELD(ep_table->smbios_major_version, addr);
- ACPI_READ_FIELD(ep_table->smbios_minor_version, addr);
- ACPI_READ_FIELD(ep_table->max_structure_size, addr);
- ACPI_READ_FIELD(ep_table->entry_point_revision, addr);
- ACPI_READ_ARRAY(ep_table->formatted_area, addr);
- ACPI_READ_ARRAY(ep_table->intermediate_anchor_string, addr);
if (memcmp(ep_table->intermediate_anchor_string, "_DMI_", 5)) {
return false;
}
- ACPI_READ_FIELD(ep_table->intermediate_checksum, addr);
- ACPI_READ_FIELD(ep_table->structure_table_length, addr);
if (ep_table->structure_table_length == 0) {
return false;
}
- ACPI_READ_FIELD(ep_table->structure_table_address, addr);
- ACPI_READ_FIELD(ep_table->number_of_structures, addr);
if (ep_table->number_of_structures == 0) {
return false;
}
- ACPI_READ_FIELD(ep_table->smbios_bcd_revision, addr);
if (acpi_calc_checksum((uint8_t *)ep_table, sizeof *ep_table) ||
acpi_calc_checksum((uint8_t *)ep_table + 0x10,
sizeof *ep_table - 0x10)) {
@@ -526,7 +420,7 @@ static void test_smbios_entry_point(test_data *data)
int i;
for (i = 0; i < sizeof sig - 1; ++i) {
- sig[i] = readb(off + i);
+ sig[i] = qtest_readb(data->qts, off + i);
}
if (!memcmp(sig, "_SM_", sizeof sig)) {
@@ -569,9 +463,9 @@ static void test_smbios_structs(test_data *data)
for (i = 0; i < le16_to_cpu(ep_table->number_of_structures); i++) {
/* grab type and formatted area length from struct header */
- type = readb(addr);
+ type = qtest_readb(data->qts, addr);
g_assert_cmpuint(type, <=, SMBIOS_MAX_TYPE);
- len = readb(addr + 1);
+ len = qtest_readb(data->qts, addr + 1);
/* single-instance structs must not have been encountered before */
if (smbios_single_instance(type)) {
@@ -583,7 +477,7 @@ static void test_smbios_structs(test_data *data)
prv = crt = 1;
while (prv || crt) {
prv = crt;
- crt = readb(addr + len);
+ crt = qtest_readb(data->qts, addr + len);
len++;
}
@@ -620,20 +514,15 @@ static void test_acpi_one(const char *params, test_data *data)
data->machine, "kvm:tcg",
params ? params : "", disk);
- qtest_start(args);
+ data->qts = qtest_init(args);
- boot_sector_test(global_qtest);
+ boot_sector_test(data->qts);
data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
test_acpi_rsdp_address(data);
test_acpi_rsdp_table(data);
test_acpi_rsdt_table(data);
- fadt_fetch_facs_and_dsdt_ptrs(data);
- test_acpi_facs_table(data);
- test_acpi_dsdt_table(data);
- fetch_rsdt_referenced_tables(data);
-
- sanitize_fadt_ptrs(data);
+ test_acpi_fadt_table(data);
if (iasl) {
if (getenv(ACPI_REBUILD_EXPECTED_AML)) {
@@ -646,7 +535,8 @@ static void test_acpi_one(const char *params, test_data *data)
test_smbios_entry_point(data);
test_smbios_structs(data);
- qtest_quit(global_qtest);
+ assert(!global_qtest);
+ qtest_quit(data->qts);
g_free(args);
}
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
index c60ebcf9d9..a725bce729 100644
--- a/tests/boot-order-test.c
+++ b/tests/boot-order-test.c
@@ -17,7 +17,7 @@
#include "standard-headers/linux/qemu_fw_cfg.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
typedef struct {
const char *args;
@@ -27,31 +27,30 @@ typedef struct {
static void test_a_boot_order(const char *machine,
const char *test_args,
- uint64_t (*read_boot_order)(void),
+ uint64_t (*read_boot_order)(QTestState *),
uint64_t expected_boot,
uint64_t expected_reboot)
{
uint64_t actual;
+ QTestState *qts;
- global_qtest = qtest_initf("-nodefaults%s%s %s",
- machine ? " -M " : "",
- machine ?: "",
- test_args);
- actual = read_boot_order();
+ qts = qtest_initf("-nodefaults%s%s %s", machine ? " -M " : "",
+ machine ?: "", test_args);
+ actual = read_boot_order(qts);
g_assert_cmphex(actual, ==, expected_boot);
- qmp_discard_response("{ 'execute': 'system_reset' }");
+ qmp_discard_response(qts, "{ 'execute': 'system_reset' }");
/*
* system_reset only requests reset. We get a RESET event after
* the actual reset completes. Need to wait for that.
*/
- qmp_eventwait("RESET");
- actual = read_boot_order();
+ qtest_qmp_eventwait(qts, "RESET");
+ actual = read_boot_order(qts);
g_assert_cmphex(actual, ==, expected_reboot);
- qtest_quit(global_qtest);
+ qtest_quit(qts);
}
static void test_boot_orders(const char *machine,
- uint64_t (*read_boot_order)(void),
+ uint64_t (*read_boot_order)(QTestState *),
const boot_order_test *tests)
{
int i;
@@ -64,16 +63,16 @@ static void test_boot_orders(const char *machine,
}
}
-static uint8_t read_mc146818(uint16_t port, uint8_t reg)
+static uint8_t read_mc146818(QTestState *qts, uint16_t port, uint8_t reg)
{
- outb(port, reg);
- return inb(port + 1);
+ qtest_outb(qts, port, reg);
+ return qtest_inb(qts, port + 1);
}
-static uint64_t read_boot_order_pc(void)
+static uint64_t read_boot_order_pc(QTestState *qts)
{
- uint8_t b1 = read_mc146818(0x70, 0x38);
- uint8_t b2 = read_mc146818(0x70, 0x3d);
+ uint8_t b1 = read_mc146818(qts, 0x70, 0x38);
+ uint8_t b2 = read_mc146818(qts, 0x70, 0x3d);
return b1 | (b2 << 8);
}
@@ -109,16 +108,16 @@ static void test_pc_boot_order(void)
test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
}
-static uint8_t read_m48t59(uint64_t addr, uint16_t reg)
+static uint8_t read_m48t59(QTestState *qts, uint64_t addr, uint16_t reg)
{
- writeb(addr, reg & 0xff);
- writeb(addr + 1, reg >> 8);
- return readb(addr + 3);
+ qtest_writeb(qts, addr, reg & 0xff);
+ qtest_writeb(qts, addr + 1, reg >> 8);
+ return qtest_readb(qts, addr + 3);
}
-static uint64_t read_boot_order_prep(void)
+static uint64_t read_boot_order_prep(QTestState *qts)
{
- return read_m48t59(0x80000000 + 0x74, 0x34);
+ return read_m48t59(qts, 0x80000000 + 0x74, 0x34);
}
static const boot_order_test test_cases_prep[] = {
@@ -133,9 +132,9 @@ static void test_prep_boot_order(void)
test_boot_orders("prep", read_boot_order_prep, test_cases_prep);
}
-static uint64_t read_boot_order_pmac(void)
+static uint64_t read_boot_order_pmac(QTestState *qts)
{
- QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xf0000510);
+ QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xf0000510);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
@@ -158,9 +157,9 @@ static void test_pmac_newworld_boot_order(void)
test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg);
}
-static uint64_t read_boot_order_sun4m(void)
+static uint64_t read_boot_order_sun4m(QTestState *qts)
{
- QFWCFG *fw_cfg = mm_fw_cfg_init(global_qtest, 0xd00000510ULL);
+ QFWCFG *fw_cfg = mm_fw_cfg_init(qts, 0xd00000510ULL);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
@@ -170,9 +169,9 @@ static void test_sun4m_boot_order(void)
test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg);
}
-static uint64_t read_boot_order_sun4u(void)
+static uint64_t read_boot_order_sun4u(QTestState *qts)
{
- QFWCFG *fw_cfg = io_fw_cfg_init(global_qtest, 0x510);
+ QFWCFG *fw_cfg = io_fw_cfg_init(qts, 0x510);
return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
}
diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c
index 8ec6aed35d..58a48f39bf 100644
--- a/tests/boot-serial-test.c
+++ b/tests/boot-serial-test.c
@@ -128,13 +128,14 @@ static testdef_t tests[] = {
{ NULL }
};
-static bool check_guest_output(const testdef_t *test, int fd)
+static bool check_guest_output(QTestState *qts, const testdef_t *test, int fd)
{
- int i, nbr = 0, pos = 0, ccnt;
+ int nbr = 0, pos = 0, ccnt;
+ time_t now, start = time(NULL);
char ch;
- /* Poll serial output... Wait at most 360 seconds */
- for (i = 0; i < 36000; ++i) {
+ /* Poll serial output... */
+ while (1) {
ccnt = 0;
while (ccnt++ < 512 && (nbr = read(fd, &ch, 1)) == 1) {
if (ch == test->expect[pos]) {
@@ -148,6 +149,15 @@ static bool check_guest_output(const testdef_t *test, int fd)
}
}
g_assert(nbr >= 0);
+ /* Wait only if the child is still alive. */
+ if (!qtest_probe_child(qts)) {
+ break;
+ }
+ /* Wait at most 360 seconds. */
+ now = time(NULL);
+ if (now - start >= 360) {
+ break;
+ }
g_usleep(10000);
}
@@ -161,6 +171,7 @@ static void test_machine(const void *data)
char codetmp[] = "/tmp/qtest-boot-serial-cXXXXXX";
const char *codeparam = "";
const uint8_t *code = NULL;
+ QTestState *qts;
int ser_fd;
ser_fd = mkstemp(serialtmp);
@@ -189,22 +200,22 @@ static void test_machine(const void *data)
* Make sure that this test uses tcg if available: It is used as a
* fast-enough smoketest for that.
*/
- global_qtest = qtest_initf("%s %s -M %s,accel=tcg:kvm "
- "-chardev file,id=serial0,path=%s "
- "-no-shutdown -serial chardev:serial0 %s",
- codeparam, code ? codetmp : "",
- test->machine, serialtmp, test->extra);
+ qts = qtest_initf("%s %s -M %s,accel=tcg:kvm -no-shutdown "
+ "-chardev file,id=serial0,path=%s "
+ "-serial chardev:serial0 %s",
+ codeparam, code ? codetmp : "", test->machine,
+ serialtmp, test->extra);
if (code) {
unlink(codetmp);
}
- if (!check_guest_output(test, ser_fd)) {
+ if (!check_guest_output(qts, test, ser_fd)) {
g_error("Failed to find expected string. Please check '%s'",
serialtmp);
}
unlink(serialtmp);
- qtest_quit(global_qtest);
+ qtest_quit(qts);
close(ser_fd);
}
diff --git a/tests/cdrom-test.c b/tests/cdrom-test.c
index 9b43dc9ab4..14bd981336 100644
--- a/tests/cdrom-test.c
+++ b/tests/cdrom-test.c
@@ -169,7 +169,7 @@ int main(int argc, char **argv)
if (exec_genisoimg(genisocheck)) {
/* genisoimage not available - so can't run tests */
- return 0;
+ return g_test_run();
}
ret = prepare_image(arch, isoimage);
diff --git a/tests/check-qom-interface.c b/tests/check-qom-interface.c
index f87c9aaa8a..2177f0dce5 100644
--- a/tests/check-qom-interface.c
+++ b/tests/check-qom-interface.c
@@ -23,9 +23,7 @@
#define TEST_IF(obj) \
INTERFACE_CHECK(TestIf, (obj), TYPE_TEST_IF)
-typedef struct TestIf {
- Object parent_obj;
-} TestIf;
+typedef struct TestIf TestIf;
typedef struct TestIfClass {
InterfaceClass parent_class;
diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c
index f4a677d238..668f00144e 100644
--- a/tests/cpu-plug-test.c
+++ b/tests/cpu-plug-test.c
@@ -157,9 +157,7 @@ static void add_pc_test_case(const char *mname)
(strcmp(mname, "pc-0.15") == 0) ||
(strcmp(mname, "pc-0.14") == 0) ||
(strcmp(mname, "pc-0.13") == 0) ||
- (strcmp(mname, "pc-0.12") == 0) ||
- (strcmp(mname, "pc-0.11") == 0) ||
- (strcmp(mname, "pc-0.10") == 0)) {
+ (strcmp(mname, "pc-0.12") == 0)) {
path = g_strdup_printf("cpu-plug/%s/init/%ux%ux%u&maxcpus=%u",
mname, data->sockets, data->cores,
data->threads, data->maxcpus);
diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm
index f6ec911b11..ad2800de67 100644
--- a/tests/data/acpi/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp
index e31ef50296..9e75ac96e1 100644
--- a/tests/data/acpi/pc/DSDT.memhp
+++ b/tests/data/acpi/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm
index 3837792dec..7177116a21 100644
--- a/tests/data/acpi/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp
index 8fba0baf79..0235461391 100644
--- a/tests/data/acpi/q35/DSDT.memhp
+++ b/tests/data/acpi/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64
index a058ff2ee3..f60ee77fb4 100644
--- a/tests/data/acpi/q35/DSDT.mmio64
+++ b/tests/data/acpi/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
index 2d7d24eee0..bd176dcf3a 100644
--- a/tests/display-vga-test.c
+++ b/tests/display-vga-test.c
@@ -40,13 +40,11 @@ static void pci_virtio_gpu(void)
qtest_end();
}
-#ifdef CONFIG_VIRTIO_VGA
static void pci_virtio_vga(void)
{
qtest_start("-vga none -device virtio-vga");
qtest_end();
}
-#endif
int main(int argc, char **argv)
{
@@ -62,8 +60,10 @@ int main(int argc, char **argv)
qtest_add_func("/display/pci/secondary", pci_secondary);
qtest_add_func("/display/pci/multihead", pci_multihead);
qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu);
-#ifdef CONFIG_VIRTIO_VGA
- qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga);
-#endif
+ if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64") ||
+ g_str_equal(arch, "hppa") || g_str_equal(arch, "ppc64")) {
+ qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga);
+ }
+
return g_test_run();
}
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 9467e9d088..7032c68895 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -98,19 +98,6 @@ docker-image-debian-s390x-cross: docker-image-debian9
docker-image-debian-win32-cross: docker-image-debian8-mxe
docker-image-debian-win64-cross: docker-image-debian8-mxe
-# Debian SID images - we are tracking a rolling distro so we want to
-# force a re-build of the base image if we ever need to build one of
-# its children.
-ifndef SKIP_DOCKER_BUILD
-ifeq ($(HAVE_USER_DOCKER),y)
-SID_AGE=$(shell $(DOCKER_SCRIPT) check --checktype=age --olderthan=180 --quiet qemu:debian-sid)
-ifeq ($(SID_AGE),)
-else
-docker-image-debian-sid: NOCACHE=1
-endif
-endif
-endif
-
docker-image-debian-alpha-cross: docker-image-debian-sid
docker-image-debian-hppa-cross: docker-image-debian-sid
docker-image-debian-m68k-cross: docker-image-debian-sid
diff --git a/tests/docker/dockerfiles/centos7.docker b/tests/docker/dockerfiles/centos7.docker
index 0a04bfbed8..e0f18f5a41 100644
--- a/tests/docker/dockerfiles/centos7.docker
+++ b/tests/docker/dockerfiles/centos7.docker
@@ -22,6 +22,7 @@ ENV PACKAGES \
mesa-libEGL-devel \
mesa-libgbm-devel \
nettle-devel \
+ perl-Test-Harness \
pixman-devel \
SDL-devel \
spice-glib-devel \
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
index 24b113b76f..954fcf9606 100644
--- a/tests/docker/dockerfiles/debian-amd64.docker
+++ b/tests/docker/dockerfiles/debian-amd64.docker
@@ -24,7 +24,8 @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
libegl1-mesa-dev \
libepoxy-dev \
libgbm-dev
-RUN git clone https://anongit.freedesktop.org/git/virglrenderer.git /usr/src/virglrenderer
+RUN git clone https://anongit.freedesktop.org/git/virglrenderer.git /usr/src/virglrenderer && \
+ cd /usr/src/virglrenderer && git checkout virglrenderer-0.7.0
RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --with-glx --disable-tests && make install
# netmap
@@ -35,5 +36,7 @@ RUN git clone https://github.com/luigirizzo/netmap.git /usr/src/netmap
RUN cd /usr/src/netmap/LINUX && ./configure --no-drivers --no-apps --kernel-dir=$(ls -d /usr/src/linux-headers-*-amd64) && make install
ENV QEMU_CONFIGURE_OPTS --enable-netmap
+RUN ldconfig
+
# gcrypt
ENV QEMU_CONFIGURE_OPTS $QEMU_CONFIGURE_OPTS --enable-gcrypt
diff --git a/tests/docker/dockerfiles/debian-sid.docker b/tests/docker/dockerfiles/debian-sid.docker
index 9a3d168705..676941cb32 100644
--- a/tests/docker/dockerfiles/debian-sid.docker
+++ b/tests/docker/dockerfiles/debian-sid.docker
@@ -11,7 +11,16 @@
# updated and trigger a re-build.
#
-FROM debian:sid-slim
+# This must be earlier than the snapshot date we are aiming for
+FROM debian:sid-20181011-slim
+
+# Use a snapshot known to work (see http://snapshot.debian.org/#Usage)
+ENV DEBIAN_SNAPSHOT_DATE "20181030"
+RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list
+
+# Use a snapshot known to work (see http://snapshot.debian.org/#Usage)
+ENV DEBIAN_SNAPSHOT_DATE "20181030"
+RUN sed -i "s%^deb \(https\?://\)deb.debian.org/debian/\? \(.*\)%deb [check-valid-until=no] \1snapshot.debian.org/archive/debian/${DEBIAN_SNAPSHOT_DATE} \2%" /etc/apt/sources.list
# Duplicate deb line as deb-src
RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list
diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker
deleted file mode 100644
index fd32e71b79..0000000000
--- a/tests/docker/dockerfiles/debian.docker
+++ /dev/null
@@ -1,13 +0,0 @@
-# This template is deprecated and was previously based on Jessie on QEMU 2.9.
-# Now than Stretch is out, please use qemu:debian8 as base for Jessie,
-# and qemu:debian9 for Stretch.
-#
-FROM qemu:debian9
-
-MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
-
-RUN for n in $(seq 8); do echo; done && \
- echo "\n\t\tThis image is deprecated." && echo && \
- echo "\tUse 'FROM qemu:debian9' to use the stable Debian Stretch image" && \
- echo "\tor 'FROM qemu:debian8' to use old Debian Jessie." && \
- for n in $(seq 8); do echo; done
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index a4fd895b07..eb8108d118 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,4 +1,4 @@
-FROM fedora:latest
+FROM fedora:29
ENV PACKAGES \
gcc \
glib2-devel.i686 \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 0c4eb9e49c..69d4a7f5d7 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -1,4 +1,4 @@
-FROM fedora:28
+FROM fedora:29
ENV PACKAGES \
bc \
bison \
@@ -70,6 +70,7 @@ ENV PACKAGES \
nss-devel \
numactl-devel \
perl \
+ perl-Test-Harness \
pixman-devel \
python3 \
PyYAML \
@@ -81,7 +82,7 @@ ENV PACKAGES \
tar \
usbredir-devel \
virglrenderer-devel \
- vte3-devel \
+ vte291-devel \
which \
xen-devel \
zlib-devel
diff --git a/tests/docker/dockerfiles/travis.docker b/tests/docker/dockerfiles/travis.docker
index 03ebfb0ef2..e72dc85ca7 100644
--- a/tests/docker/dockerfiles/travis.docker
+++ b/tests/docker/dockerfiles/travis.docker
@@ -1,8 +1,8 @@
-FROM travisci/ci-garnet:packer-1512502276-986baf0
+FROM travisci/ci-sardonyx:packer-1546978056-2c98a19
ENV DEBIAN_FRONTEND noninteractive
ENV LANG en_US.UTF-8
ENV LC_ALL en_US.UTF-8
-RUN cat /etc/apt/sources.list | sed "s/# deb-src/deb-src/" >> /etc/apt/sources.list
+RUN sed -i "s/# deb-src/deb-src/" /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y build-dep qemu
RUN apt-get -y install device-tree-compiler python2.7 python-yaml dh-autoreconf gdb strace lsof net-tools gcovr
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
index 48680cd131..58527952a5 100644
--- a/tests/endianness-test.c
+++ b/tests/endianness-test.c
@@ -48,65 +48,68 @@ static const TestCase test_cases[] = {
{}
};
-static uint8_t isa_inb(const TestCase *test, uint16_t addr)
+static uint8_t isa_inb(QTestState *qts, const TestCase *test, uint16_t addr)
{
uint8_t value;
if (test->isa_base == -1) {
- value = inb(addr);
+ value = qtest_inb(qts, addr);
} else {
- value = readb(test->isa_base + addr);
+ value = qtest_readb(qts, test->isa_base + addr);
}
return value;
}
-static uint16_t isa_inw(const TestCase *test, uint16_t addr)
+static uint16_t isa_inw(QTestState *qts, const TestCase *test, uint16_t addr)
{
uint16_t value;
if (test->isa_base == -1) {
- value = inw(addr);
+ value = qtest_inw(qts, addr);
} else {
- value = readw(test->isa_base + addr);
+ value = qtest_readw(qts, test->isa_base + addr);
}
return test->bswap ? bswap16(value) : value;
}
-static uint32_t isa_inl(const TestCase *test, uint16_t addr)
+static uint32_t isa_inl(QTestState *qts, const TestCase *test, uint16_t addr)
{
uint32_t value;
if (test->isa_base == -1) {
- value = inl(addr);
+ value = qtest_inl(qts, addr);
} else {
- value = readl(test->isa_base + addr);
+ value = qtest_readl(qts, test->isa_base + addr);
}
return test->bswap ? bswap32(value) : value;
}
-static void isa_outb(const TestCase *test, uint16_t addr, uint8_t value)
+static void isa_outb(QTestState *qts, const TestCase *test, uint16_t addr,
+ uint8_t value)
{
if (test->isa_base == -1) {
- outb(addr, value);
+ qtest_outb(qts, addr, value);
} else {
- writeb(test->isa_base + addr, value);
+ qtest_writeb(qts, test->isa_base + addr, value);
}
}
-static void isa_outw(const TestCase *test, uint16_t addr, uint16_t value)
+static void isa_outw(QTestState *qts, const TestCase *test, uint16_t addr,
+ uint16_t value)
{
value = test->bswap ? bswap16(value) : value;
if (test->isa_base == -1) {
- outw(addr, value);
+ qtest_outw(qts, addr, value);
} else {
- writew(test->isa_base + addr, value);
+ qtest_writew(qts, test->isa_base + addr, value);
}
}
-static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value)
+static void isa_outl(QTestState *qts, const TestCase *test, uint16_t addr,
+ uint32_t value)
{
value = test->bswap ? bswap32(value) : value;
if (test->isa_base == -1) {
- outl(addr, value);
+ qtest_outl(qts, addr, value);
} else {
- writel(test->isa_base + addr, value);
+ qtest_writel(qts, test->isa_base + addr, value);
}
}
@@ -114,161 +117,161 @@ static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value)
static void test_endianness(gconstpointer data)
{
const TestCase *test = data;
-
- global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
- test->machine,
- test->superio ? " -device " : "",
- test->superio ?: "");
- isa_outl(test, 0xe0, 0x87654321);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
-
- isa_outw(test, 0xe2, 0x8866);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
-
- isa_outw(test, 0xe0, 0x4422);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
-
- isa_outb(test, 0xe3, 0x87);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
-
- isa_outb(test, 0xe2, 0x65);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
-
- isa_outb(test, 0xe1, 0x43);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
-
- isa_outb(test, 0xe0, 0x21);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
- g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
- g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
- g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
- g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
- qtest_quit(global_qtest);
+ QTestState *qts;
+
+ qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ isa_outl(qts, test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+
+ isa_outw(qts, test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+
+ isa_outw(qts, test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+ isa_outb(qts, test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+ isa_outb(qts, test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+ isa_outb(qts, test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x22);
+
+ isa_outb(qts, test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(qts, test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(qts, test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(qts, test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(qts, test, 0xe0), ==, 0x21);
+ qtest_quit(qts);
}
static void test_endianness_split(gconstpointer data)
{
const TestCase *test = data;
-
- global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
- test->machine,
- test->superio ? " -device " : "",
- test->superio ?: "");
- isa_outl(test, 0xe8, 0x87654321);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
-
- isa_outw(test, 0xea, 0x8866);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
-
- isa_outw(test, 0xe8, 0x4422);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
-
- isa_outb(test, 0xeb, 0x87);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
-
- isa_outb(test, 0xea, 0x65);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
-
- isa_outb(test, 0xe9, 0x43);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
-
- isa_outb(test, 0xe8, 0x21);
- g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
- qtest_quit(global_qtest);
+ QTestState *qts;
+
+ qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ isa_outl(qts, test, 0xe8, 0x87654321);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+
+ isa_outw(qts, test, 0xea, 0x8866);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+
+ isa_outw(qts, test, 0xe8, 0x4422);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+
+ isa_outb(qts, test, 0xeb, 0x87);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8766);
+
+ isa_outb(qts, test, 0xea, 0x65);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4422);
+
+ isa_outb(qts, test, 0xe9, 0x43);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4322);
+
+ isa_outb(qts, test, 0xe8, 0x21);
+ g_assert_cmphex(isa_inl(qts, test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe0), ==, 0x4321);
+ qtest_quit(qts);
}
static void test_endianness_combine(gconstpointer data)
{
const TestCase *test = data;
-
- global_qtest = qtest_initf("-M %s%s%s -device pc-testdev",
- test->machine,
- test->superio ? " -device " : "",
- test->superio ?: "");
- isa_outl(test, 0xe0, 0x87654321);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
-
- isa_outw(test, 0xe2, 0x8866);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664321);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
-
- isa_outw(test, 0xe0, 0x4422);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664422);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
-
- isa_outb(test, 0xe3, 0x87);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87664422);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8766);
-
- isa_outb(test, 0xe2, 0x65);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654422);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
-
- isa_outb(test, 0xe1, 0x43);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654322);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4322);
-
- isa_outb(test, 0xe0, 0x21);
- g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
- g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
- g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
- qtest_quit(global_qtest);
+ QTestState *qts;
+
+ qts = qtest_initf("-M %s%s%s -device pc-testdev", test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ isa_outl(qts, test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+
+ isa_outw(qts, test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+
+ isa_outw(qts, test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
+
+ isa_outb(qts, test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8766);
+
+ isa_outb(qts, test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4422);
+
+ isa_outb(qts, test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4322);
+
+ isa_outb(qts, test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(qts, test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(qts, test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(qts, test, 0xe8), ==, 0x4321);
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/tests/fp/.gitignore b/tests/fp/.gitignore
index 8d45d18ac4..704fd42992 100644
--- a/tests/fp/.gitignore
+++ b/tests/fp/.gitignore
@@ -1 +1,2 @@
fp-test
+fp-bench
diff --git a/tests/fp/Makefile b/tests/fp/Makefile
index d649a5a1db..5019dcdca0 100644
--- a/tests/fp/Makefile
+++ b/tests/fp/Makefile
@@ -29,6 +29,9 @@ QEMU_INCLUDES += -I$(TF_SOURCE_DIR)
# work around TARGET_* poisoning
QEMU_CFLAGS += -DHW_POISON_H
+# define a target to match testfloat's implementation-defined choices, such as
+# whether to raise the invalid flag when dealing with NaNs in muladd.
+QEMU_CFLAGS += -DTARGET_ARM
# capstone has a platform.h file that clashes with softfloat's
QEMU_CFLAGS := $(filter-out %capstone, $(QEMU_CFLAGS))
@@ -550,7 +553,7 @@ TF_OBJS_LIB += $(TF_OBJS_WRITECASE)
TF_OBJS_LIB += testLoops_common.o
TF_OBJS_LIB += $(TF_OBJS_TEST)
-BINARIES := fp-test$(EXESUF)
+BINARIES := fp-test$(EXESUF) fp-bench$(EXESUF)
# everything depends on config-host.h because platform.h includes it
all: $(BUILD_DIR)/config-host.h
@@ -587,10 +590,13 @@ $(TF_OBJS_LIB) slowfloat.o: %.o: $(TF_SOURCE_DIR)/%.c
libtestfloat.a: $(TF_OBJS_LIB)
+fp-bench$(EXESUF): fp-bench.o $(QEMU_SOFTFLOAT_OBJ) $(LIBQEMUUTIL)
+
clean:
rm -f *.o *.d $(BINARIES)
rm -f *.gcno *.gcda *.gcov
rm -f fp-test$(EXESUF)
+ rm -f fp-bench$(EXESUF)
rm -f libsoftfloat.a
rm -f libtestfloat.a
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
new file mode 100644
index 0000000000..f5bc5edebf
--- /dev/null
+++ b/tests/fp/fp-bench.c
@@ -0,0 +1,630 @@
+/*
+ * fp-bench.c - A collection of simple floating point microbenchmarks.
+ *
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef HW_POISON_H
+#error Must define HW_POISON_H to work around TARGET_* poisoning
+#endif
+
+#include "qemu/osdep.h"
+#include <math.h>
+#include <fenv.h>
+#include "qemu/timer.h"
+#include "fpu/softfloat.h"
+
+/* amortize the computation of random inputs */
+#define OPS_PER_ITER 50000
+
+#define MAX_OPERANDS 3
+
+#define SEED_A 0xdeadfacedeadface
+#define SEED_B 0xbadc0feebadc0fee
+#define SEED_C 0xbeefdeadbeefdead
+
+enum op {
+ OP_ADD,
+ OP_SUB,
+ OP_MUL,
+ OP_DIV,
+ OP_FMA,
+ OP_SQRT,
+ OP_CMP,
+ OP_MAX_NR,
+};
+
+static const char * const op_names[] = {
+ [OP_ADD] = "add",
+ [OP_SUB] = "sub",
+ [OP_MUL] = "mul",
+ [OP_DIV] = "div",
+ [OP_FMA] = "mulAdd",
+ [OP_SQRT] = "sqrt",
+ [OP_CMP] = "cmp",
+ [OP_MAX_NR] = NULL,
+};
+
+enum precision {
+ PREC_SINGLE,
+ PREC_DOUBLE,
+ PREC_FLOAT32,
+ PREC_FLOAT64,
+ PREC_MAX_NR,
+};
+
+enum rounding {
+ ROUND_EVEN,
+ ROUND_ZERO,
+ ROUND_DOWN,
+ ROUND_UP,
+ ROUND_TIEAWAY,
+ N_ROUND_MODES,
+};
+
+static const char * const round_names[] = {
+ [ROUND_EVEN] = "even",
+ [ROUND_ZERO] = "zero",
+ [ROUND_DOWN] = "down",
+ [ROUND_UP] = "up",
+ [ROUND_TIEAWAY] = "tieaway",
+};
+
+enum tester {
+ TESTER_SOFT,
+ TESTER_HOST,
+ TESTER_MAX_NR,
+};
+
+static const char * const tester_names[] = {
+ [TESTER_SOFT] = "soft",
+ [TESTER_HOST] = "host",
+ [TESTER_MAX_NR] = NULL,
+};
+
+union fp {
+ float f;
+ double d;
+ float32 f32;
+ float64 f64;
+ uint64_t u64;
+};
+
+struct op_state;
+
+typedef float (*float_func_t)(const struct op_state *s);
+typedef double (*double_func_t)(const struct op_state *s);
+
+union fp_func {
+ float_func_t float_func;
+ double_func_t double_func;
+};
+
+typedef void (*bench_func_t)(void);
+
+struct op_desc {
+ const char * const name;
+};
+
+#define DEFAULT_DURATION_SECS 1
+
+static uint64_t random_ops[MAX_OPERANDS] = {
+ SEED_A, SEED_B, SEED_C,
+};
+static float_status soft_status;
+static enum precision precision;
+static enum op operation;
+static enum tester tester;
+static uint64_t n_completed_ops;
+static unsigned int duration = DEFAULT_DURATION_SECS;
+static int64_t ns_elapsed;
+/* disable optimizations with volatile */
+static volatile union fp res;
+
+/*
+ * From: https://en.wikipedia.org/wiki/Xorshift
+ * This is faster than rand_r(), and gives us a wider range (RAND_MAX is only
+ * guaranteed to be >= INT_MAX).
+ */
+static uint64_t xorshift64star(uint64_t x)
+{
+ x ^= x >> 12; /* a */
+ x ^= x << 25; /* b */
+ x ^= x >> 27; /* c */
+ return x * UINT64_C(2685821657736338717);
+}
+
+static void update_random_ops(int n_ops, enum precision prec)
+{
+ int i;
+
+ for (i = 0; i < n_ops; i++) {
+ uint64_t r = random_ops[i];
+
+ if (prec == PREC_SINGLE || PREC_FLOAT32) {
+ do {
+ r = xorshift64star(r);
+ } while (!float32_is_normal(r));
+ } else if (prec == PREC_DOUBLE || PREC_FLOAT64) {
+ do {
+ r = xorshift64star(r);
+ } while (!float64_is_normal(r));
+ } else {
+ g_assert_not_reached();
+ }
+ random_ops[i] = r;
+ }
+}
+
+static void fill_random(union fp *ops, int n_ops, enum precision prec,
+ bool no_neg)
+{
+ int i;
+
+ for (i = 0; i < n_ops; i++) {
+ switch (prec) {
+ case PREC_SINGLE:
+ case PREC_FLOAT32:
+ ops[i].f32 = make_float32(random_ops[i]);
+ if (no_neg && float32_is_neg(ops[i].f32)) {
+ ops[i].f32 = float32_chs(ops[i].f32);
+ }
+ /* raise the exponent to limit the frequency of denormal results */
+ ops[i].f32 |= 0x40000000;
+ break;
+ case PREC_DOUBLE:
+ case PREC_FLOAT64:
+ ops[i].f64 = make_float64(random_ops[i]);
+ if (no_neg && float64_is_neg(ops[i].f64)) {
+ ops[i].f64 = float64_chs(ops[i].f64);
+ }
+ /* raise the exponent to limit the frequency of denormal results */
+ ops[i].f64 |= LIT64(0x4000000000000000);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+}
+
+/*
+ * The main benchmark function. Instead of (ab)using macros, we rely
+ * on the compiler to unfold this at compile-time.
+ */
+static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
+{
+ int64_t tf = get_clock() + duration * 1000000000LL;
+
+ while (get_clock() < tf) {
+ union fp ops[MAX_OPERANDS];
+ int64_t t0;
+ int i;
+
+ update_random_ops(n_ops, prec);
+ switch (prec) {
+ case PREC_SINGLE:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ float a = ops[0].f;
+ float b = ops[1].f;
+ float c = ops[2].f;
+
+ switch (op) {
+ case OP_ADD:
+ res.f = a + b;
+ break;
+ case OP_SUB:
+ res.f = a - b;
+ break;
+ case OP_MUL:
+ res.f = a * b;
+ break;
+ case OP_DIV:
+ res.f = a / b;
+ break;
+ case OP_FMA:
+ res.f = fmaf(a, b, c);
+ break;
+ case OP_SQRT:
+ res.f = sqrtf(a);
+ break;
+ case OP_CMP:
+ res.u64 = isgreater(a, b);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
+ case PREC_DOUBLE:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ double a = ops[0].d;
+ double b = ops[1].d;
+ double c = ops[2].d;
+
+ switch (op) {
+ case OP_ADD:
+ res.d = a + b;
+ break;
+ case OP_SUB:
+ res.d = a - b;
+ break;
+ case OP_MUL:
+ res.d = a * b;
+ break;
+ case OP_DIV:
+ res.d = a / b;
+ break;
+ case OP_FMA:
+ res.d = fma(a, b, c);
+ break;
+ case OP_SQRT:
+ res.d = sqrt(a);
+ break;
+ case OP_CMP:
+ res.u64 = isgreater(a, b);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
+ case PREC_FLOAT32:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ float32 a = ops[0].f32;
+ float32 b = ops[1].f32;
+ float32 c = ops[2].f32;
+
+ switch (op) {
+ case OP_ADD:
+ res.f32 = float32_add(a, b, &soft_status);
+ break;
+ case OP_SUB:
+ res.f32 = float32_sub(a, b, &soft_status);
+ break;
+ case OP_MUL:
+ res.f = float32_mul(a, b, &soft_status);
+ break;
+ case OP_DIV:
+ res.f32 = float32_div(a, b, &soft_status);
+ break;
+ case OP_FMA:
+ res.f32 = float32_muladd(a, b, c, 0, &soft_status);
+ break;
+ case OP_SQRT:
+ res.f32 = float32_sqrt(a, &soft_status);
+ break;
+ case OP_CMP:
+ res.u64 = float32_compare_quiet(a, b, &soft_status);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
+ case PREC_FLOAT64:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ float64 a = ops[0].f64;
+ float64 b = ops[1].f64;
+ float64 c = ops[2].f64;
+
+ switch (op) {
+ case OP_ADD:
+ res.f64 = float64_add(a, b, &soft_status);
+ break;
+ case OP_SUB:
+ res.f64 = float64_sub(a, b, &soft_status);
+ break;
+ case OP_MUL:
+ res.f = float64_mul(a, b, &soft_status);
+ break;
+ case OP_DIV:
+ res.f64 = float64_div(a, b, &soft_status);
+ break;
+ case OP_FMA:
+ res.f64 = float64_muladd(a, b, c, 0, &soft_status);
+ break;
+ case OP_SQRT:
+ res.f64 = float64_sqrt(a, &soft_status);
+ break;
+ case OP_CMP:
+ res.u64 = float64_compare_quiet(a, b, &soft_status);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ ns_elapsed += get_clock() - t0;
+ n_completed_ops += OPS_PER_ITER;
+ }
+}
+
+#define GEN_BENCH(name, type, prec, op, n_ops) \
+ static void __attribute__((flatten)) name(void) \
+ { \
+ bench(prec, op, n_ops, false); \
+ }
+
+#define GEN_BENCH_NO_NEG(name, type, prec, op, n_ops) \
+ static void __attribute__((flatten)) name(void) \
+ { \
+ bench(prec, op, n_ops, true); \
+ }
+
+#define GEN_BENCH_ALL_TYPES(opname, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _float, float, PREC_SINGLE, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _double, double, PREC_DOUBLE, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _float32, float32, PREC_FLOAT32, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops)
+
+GEN_BENCH_ALL_TYPES(add, OP_ADD, 2)
+GEN_BENCH_ALL_TYPES(sub, OP_SUB, 2)
+GEN_BENCH_ALL_TYPES(mul, OP_MUL, 2)
+GEN_BENCH_ALL_TYPES(div, OP_DIV, 2)
+GEN_BENCH_ALL_TYPES(fma, OP_FMA, 3)
+GEN_BENCH_ALL_TYPES(cmp, OP_CMP, 2)
+#undef GEN_BENCH_ALL_TYPES
+
+#define GEN_BENCH_ALL_TYPES_NO_NEG(name, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float, float, PREC_SINGLE, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _double, double, PREC_DOUBLE, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float32, float32, PREC_FLOAT32, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n)
+
+GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
+#undef GEN_BENCH_ALL_TYPES_NO_NEG
+
+#undef GEN_BENCH_NO_NEG
+#undef GEN_BENCH
+
+#define GEN_BENCH_FUNCS(opname, op) \
+ [op] = { \
+ [PREC_SINGLE] = bench_ ## opname ## _float, \
+ [PREC_DOUBLE] = bench_ ## opname ## _double, \
+ [PREC_FLOAT32] = bench_ ## opname ## _float32, \
+ [PREC_FLOAT64] = bench_ ## opname ## _float64, \
+ }
+
+static const bench_func_t bench_funcs[OP_MAX_NR][PREC_MAX_NR] = {
+ GEN_BENCH_FUNCS(add, OP_ADD),
+ GEN_BENCH_FUNCS(sub, OP_SUB),
+ GEN_BENCH_FUNCS(mul, OP_MUL),
+ GEN_BENCH_FUNCS(div, OP_DIV),
+ GEN_BENCH_FUNCS(fma, OP_FMA),
+ GEN_BENCH_FUNCS(sqrt, OP_SQRT),
+ GEN_BENCH_FUNCS(cmp, OP_CMP),
+};
+
+#undef GEN_BENCH_FUNCS
+
+static void run_bench(void)
+{
+ bench_func_t f;
+
+ f = bench_funcs[operation][precision];
+ g_assert(f);
+ f();
+}
+
+/* @arr must be NULL-terminated */
+static int find_name(const char * const *arr, const char *name)
+{
+ int i;
+
+ for (i = 0; arr[i] != NULL; i++) {
+ if (strcmp(name, arr[i]) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void usage_complete(int argc, char *argv[])
+{
+ gchar *op_list = g_strjoinv(", ", (gchar **)op_names);
+ gchar *tester_list = g_strjoinv(", ", (gchar **)tester_names);
+
+ fprintf(stderr, "Usage: %s [options]\n", argv[0]);
+ fprintf(stderr, "options:\n");
+ fprintf(stderr, " -d = duration, in seconds. Default: %d\n",
+ DEFAULT_DURATION_SECS);
+ fprintf(stderr, " -h = show this help message.\n");
+ fprintf(stderr, " -o = floating point operation (%s). Default: %s\n",
+ op_list, op_names[0]);
+ fprintf(stderr, " -p = floating point precision (single, double). "
+ "Default: single\n");
+ fprintf(stderr, " -r = rounding mode (even, zero, down, up, tieaway). "
+ "Default: even\n");
+ fprintf(stderr, " -t = tester (%s). Default: %s\n",
+ tester_list, tester_names[0]);
+ fprintf(stderr, " -z = flush inputs to zero (soft tester only). "
+ "Default: disabled\n");
+ fprintf(stderr, " -Z = flush output to zero (soft tester only). "
+ "Default: disabled\n");
+
+ g_free(tester_list);
+ g_free(op_list);
+}
+
+static int round_name_to_mode(const char *name)
+{
+ int i;
+
+ for (i = 0; i < N_ROUND_MODES; i++) {
+ if (!strcmp(round_names[i], name)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void QEMU_NORETURN die_host_rounding(enum rounding rounding)
+{
+ fprintf(stderr, "fatal: '%s' rounding not supported on this host\n",
+ round_names[rounding]);
+ exit(EXIT_FAILURE);
+}
+
+static void set_host_precision(enum rounding rounding)
+{
+ int rhost;
+
+ switch (rounding) {
+ case ROUND_EVEN:
+ rhost = FE_TONEAREST;
+ break;
+ case ROUND_ZERO:
+ rhost = FE_TOWARDZERO;
+ break;
+ case ROUND_DOWN:
+ rhost = FE_DOWNWARD;
+ break;
+ case ROUND_UP:
+ rhost = FE_UPWARD;
+ break;
+ case ROUND_TIEAWAY:
+ die_host_rounding(rounding);
+ return;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (fesetround(rhost)) {
+ die_host_rounding(rounding);
+ }
+}
+
+static void set_soft_precision(enum rounding rounding)
+{
+ signed char mode;
+
+ switch (rounding) {
+ case ROUND_EVEN:
+ mode = float_round_nearest_even;
+ break;
+ case ROUND_ZERO:
+ mode = float_round_to_zero;
+ break;
+ case ROUND_DOWN:
+ mode = float_round_down;
+ break;
+ case ROUND_UP:
+ mode = float_round_up;
+ break;
+ case ROUND_TIEAWAY:
+ mode = float_round_ties_away;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ soft_status.float_rounding_mode = mode;
+}
+
+static void parse_args(int argc, char *argv[])
+{
+ int c;
+ int val;
+ int rounding = ROUND_EVEN;
+
+ for (;;) {
+ c = getopt(argc, argv, "d:ho:p:r:t:zZ");
+ if (c < 0) {
+ break;
+ }
+ switch (c) {
+ case 'd':
+ duration = atoi(optarg);
+ break;
+ case 'h':
+ usage_complete(argc, argv);
+ exit(EXIT_SUCCESS);
+ case 'o':
+ val = find_name(op_names, optarg);
+ if (val < 0) {
+ fprintf(stderr, "Unsupported op '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ operation = val;
+ break;
+ case 'p':
+ if (!strcmp(optarg, "single")) {
+ precision = PREC_SINGLE;
+ } else if (!strcmp(optarg, "double")) {
+ precision = PREC_DOUBLE;
+ } else {
+ fprintf(stderr, "Unsupported precision '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'r':
+ rounding = round_name_to_mode(optarg);
+ if (rounding < 0) {
+ fprintf(stderr, "fatal: invalid rounding mode '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 't':
+ val = find_name(tester_names, optarg);
+ if (val < 0) {
+ fprintf(stderr, "Unsupported tester '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ tester = val;
+ break;
+ case 'z':
+ soft_status.flush_inputs_to_zero = 1;
+ break;
+ case 'Z':
+ soft_status.flush_to_zero = 1;
+ break;
+ }
+ }
+
+ /* set precision and rounding mode based on the tester */
+ switch (tester) {
+ case TESTER_HOST:
+ set_host_precision(rounding);
+ break;
+ case TESTER_SOFT:
+ set_soft_precision(rounding);
+ switch (precision) {
+ case PREC_SINGLE:
+ precision = PREC_FLOAT32;
+ break;
+ case PREC_DOUBLE:
+ precision = PREC_FLOAT64;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void pr_stats(void)
+{
+ printf("%.2f MFlops\n", (double)n_completed_ops / ns_elapsed * 1e3);
+}
+
+int main(int argc, char *argv[])
+{
+ parse_args(argc, argv);
+ run_bench();
+ pr_stats();
+ return 0;
+}
diff --git a/tests/fp/platform.h b/tests/fp/platform.h
index c20ba70baa..f8c423dde3 100644
--- a/tests/fp/platform.h
+++ b/tests/fp/platform.h
@@ -29,7 +29,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config-host.h"
#ifndef HOST_WORDS_BIGENDIAN
#define LITTLEENDIAN 1
diff --git a/tests/hexloader-test.c b/tests/hexloader-test.c
index 834ed52c22..8b7aa2d72d 100644
--- a/tests/hexloader-test.c
+++ b/tests/hexloader-test.c
@@ -23,7 +23,7 @@ static void hex_loader_test(void)
const unsigned int base_addr = 0x00010000;
QTestState *s = qtest_initf(
- "-M vexpress-a9 -nographic -device loader,file=tests/data/hex-loader/test.hex");
+ "-M vexpress-a9 -device loader,file=tests/data/hex-loader/test.hex");
for (i = 0; i < 256; ++i) {
uint8_t val = qtest_readb(s, base_addr + i);
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index c37b196b32..4911b69317 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -71,13 +71,10 @@ static const char* reg2str(enum Reg reg) {
static inline unsigned in_reg(IVState *s, enum Reg reg)
{
const char *name = reg2str(reg);
- QTestState *qtest = global_qtest;
unsigned res;
- global_qtest = s->qs->qts;
res = qpci_io_readl(s->dev, s->reg_bar, reg);
g_test_message("*%s -> %x\n", name, res);
- global_qtest = qtest;
return res;
}
@@ -85,35 +82,25 @@ static inline unsigned in_reg(IVState *s, enum Reg reg)
static inline void out_reg(IVState *s, enum Reg reg, unsigned v)
{
const char *name = reg2str(reg);
- QTestState *qtest = global_qtest;
- global_qtest = s->qs->qts;
g_test_message("%x -> *%s\n", v, name);
qpci_io_writel(s->dev, s->reg_bar, reg, v);
- global_qtest = qtest;
}
static inline void read_mem(IVState *s, uint64_t off, void *buf, size_t len)
{
- QTestState *qtest = global_qtest;
-
- global_qtest = s->qs->qts;
qpci_memread(s->dev, s->mem_bar, off, buf, len);
- global_qtest = qtest;
}
static inline void write_mem(IVState *s, uint64_t off,
const void *buf, size_t len)
{
- QTestState *qtest = global_qtest;
-
- global_qtest = s->qs->qts;
qpci_memwrite(s->dev, s->mem_bar, off, buf, len);
- global_qtest = qtest;
}
static void cleanup_vm(IVState *s)
{
+ assert(!global_qtest);
g_free(s->dev);
qtest_shutdown(s->qs);
}
@@ -131,7 +118,6 @@ static void setup_vm_cmd(IVState *s, const char *cmd, bool msix)
g_printerr("ivshmem-test tests are only available on x86 or ppc64\n");
exit(EXIT_FAILURE);
}
- global_qtest = s->qs->qts;
s->dev = get_device(s->qs->pcibus);
s->reg_bar = qpci_iomap(s->dev, 0, &barsize);
@@ -305,20 +291,20 @@ static void *server_thread(void *data)
return NULL;
}
-static void setup_vm_with_server(IVState *s, int nvectors, bool msi)
+static void setup_vm_with_server(IVState *s, int nvectors)
{
- char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
- "-device ivshmem%s,chardev=chr0,vectors=%d",
- tmpserver,
- msi ? "-doorbell" : ",size=1M,msi=off",
- nvectors);
+ char *cmd;
+
+ cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait "
+ "-device ivshmem-doorbell,chardev=chr0,vectors=%d",
+ tmpserver, nvectors);
- setup_vm_cmd(s, cmd, msi);
+ setup_vm_cmd(s, cmd, true);
g_free(cmd);
}
-static void test_ivshmem_server(bool msi)
+static void test_ivshmem_server(void)
{
IVState state1, state2, *s1, *s2;
ServerThread thread;
@@ -341,9 +327,9 @@ static void test_ivshmem_server(bool msi)
thread.thread = g_thread_new("ivshmem-server", server_thread, &thread);
g_assert(thread.thread != NULL);
- setup_vm_with_server(&state1, nvectors, msi);
+ setup_vm_with_server(&state1, nvectors);
s1 = &state1;
- setup_vm_with_server(&state2, nvectors, msi);
+ setup_vm_with_server(&state2, nvectors);
s2 = &state2;
/* check got different VM ids */
@@ -354,40 +340,28 @@ static void test_ivshmem_server(bool msi)
g_assert_cmpint(vm1, !=, vm2);
/* check number of MSI-X vectors */
- global_qtest = s1->qs->qts;
- if (msi) {
- ret = qpci_msix_table_size(s1->dev);
- g_assert_cmpuint(ret, ==, nvectors);
- }
+ ret = qpci_msix_table_size(s1->dev);
+ g_assert_cmpuint(ret, ==, nvectors);
/* TODO test behavior before MSI-X is enabled */
/* ping vm2 -> vm1 on vector 0 */
- if (msi) {
- ret = qpci_msix_pending(s1->dev, 0);
- g_assert_cmpuint(ret, ==, 0);
- } else {
- g_assert_cmpuint(in_reg(s1, INTRSTATUS), ==, 0);
- }
+ ret = qpci_msix_pending(s1->dev, 0);
+ g_assert_cmpuint(ret, ==, 0);
out_reg(s2, DOORBELL, vm1 << 16);
do {
g_usleep(10000);
- ret = msi ? qpci_msix_pending(s1->dev, 0) : in_reg(s1, INTRSTATUS);
+ ret = qpci_msix_pending(s1->dev, 0);
} while (ret == 0 && g_get_monotonic_time() < end_time);
g_assert_cmpuint(ret, !=, 0);
/* ping vm1 -> vm2 on vector 1 */
- global_qtest = s2->qs->qts;
- if (msi) {
- ret = qpci_msix_pending(s2->dev, 1);
- g_assert_cmpuint(ret, ==, 0);
- } else {
- g_assert_cmpuint(in_reg(s2, INTRSTATUS), ==, 0);
- }
+ ret = qpci_msix_pending(s2->dev, 1);
+ g_assert_cmpuint(ret, ==, 0);
out_reg(s1, DOORBELL, vm2 << 16 | 1);
do {
g_usleep(10000);
- ret = msi ? qpci_msix_pending(s2->dev, 1) : in_reg(s2, INTRSTATUS);
+ ret = qpci_msix_pending(s2->dev, 1);
} while (ret == 0 && g_get_monotonic_time() < end_time);
g_assert_cmpuint(ret, !=, 0);
@@ -405,27 +379,17 @@ static void test_ivshmem_server(bool msi)
close(thread.pipe[0]);
}
-static void test_ivshmem_server_msi(void)
-{
- test_ivshmem_server(true);
-}
-
-static void test_ivshmem_server_irq(void)
-{
- test_ivshmem_server(false);
-}
-
#define PCI_SLOT_HP 0x06
static void test_ivshmem_hotplug(void)
{
const char *arch = qtest_get_arch();
- qtest_start("");
+ qtest_start("-object memory-backend-ram,size=1M,id=mb1");
- qtest_qmp_device_add("ivshmem",
- "iv1", "{'addr': %s, 'shm': %s, 'size': '1M'}",
- stringify(PCI_SLOT_HP), tmpshm);
+ qtest_qmp_device_add("ivshmem-plain", "iv1",
+ "{'addr': %s, 'memdev': 'mb1'}",
+ stringify(PCI_SLOT_HP));
if (strcmp(arch, "ppc64") != 0) {
qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP);
}
@@ -508,7 +472,7 @@ int main(int argc, char **argv)
/* shm */
tmpshm = mktempshm(TMPSHMSIZE, &fd);
if (!tmpshm) {
- return 0;
+ goto out;
}
tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
g_assert(tmpshmem != MAP_FAILED);
@@ -525,14 +489,12 @@ int main(int argc, char **argv)
if (g_test_slow()) {
qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
if (strcmp(arch, "ppc64") != 0) {
- qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi);
- qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq);
+ qtest_add_func("/ivshmem/server", test_ivshmem_server);
}
}
+out:
ret = g_test_run();
-
cleanup();
-
return ret;
}
diff --git a/tests/libqos/malloc.c b/tests/libqos/malloc.c
index ac05874b0a..f7bae47a08 100644
--- a/tests/libqos/malloc.c
+++ b/tests/libqos/malloc.c
@@ -104,7 +104,7 @@ static void mlist_coalesce(MemList *head, MemBlock *node)
do {
merge = 0;
- left = QTAILQ_PREV(node, MemList, MLIST_ENTNAME);
+ left = QTAILQ_PREV(node, MLIST_ENTNAME);
right = QTAILQ_NEXT(node, MLIST_ENTNAME);
/* clowns to the left of me */
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 585f5289ec..a4fc02b5d8 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -29,90 +29,91 @@ typedef struct QPCIBusPC
static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr)
{
- return inb(addr);
+ return qtest_inb(bus->qts, addr);
}
static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
{
- outb(addr, val);
+ qtest_outb(bus->qts, addr, val);
}
static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr)
{
- return inw(addr);
+ return qtest_inw(bus->qts, addr);
}
static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
{
- outw(addr, val);
+ qtest_outw(bus->qts, addr, val);
}
static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr)
{
- return inl(addr);
+ return qtest_inl(bus->qts, addr);
}
static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
{
- outl(addr, val);
+ qtest_outl(bus->qts, addr, val);
}
static uint64_t qpci_pc_pio_readq(QPCIBus *bus, uint32_t addr)
{
- return (uint64_t)inl(addr) + ((uint64_t)inl(addr + 4) << 32);
+ return (uint64_t)qtest_inl(bus->qts, addr) +
+ ((uint64_t)qtest_inl(bus->qts, addr + 4) << 32);
}
static void qpci_pc_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val)
{
- outl(addr, val & 0xffffffff);
- outl(addr + 4, val >> 32);
+ qtest_outl(bus->qts, addr, val & 0xffffffff);
+ qtest_outl(bus->qts, addr + 4, val >> 32);
}
static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len)
{
- memread(addr, buf, len);
+ qtest_memread(bus->qts, addr, buf, len);
}
static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr,
const void *buf, size_t len)
{
- memwrite(addr, buf, len);
+ qtest_memwrite(bus->qts, addr, buf, len);
}
static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- return inb(0xcfc);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ return qtest_inb(bus->qts, 0xcfc);
}
static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- return inw(0xcfc);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ return qtest_inw(bus->qts, 0xcfc);
}
static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- return inl(0xcfc);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ return qtest_inl(bus->qts, 0xcfc);
}
static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- outb(0xcfc, value);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ qtest_outb(bus->qts, 0xcfc, value);
}
static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- outw(0xcfc, value);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ qtest_outw(bus->qts, 0xcfc, value);
}
static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
{
- outl(0xcf8, (1U << 31) | (devfn << 8) | offset);
- outl(0xcfc, value);
+ qtest_outl(bus->qts, 0xcf8, (1U << 31) | (devfn << 8) | offset);
+ qtest_outl(bus->qts, 0xcfc, value);
}
QPCIBus *qpci_init_pc(QTestState *qts, QGuestAllocator *alloc)
diff --git a/tests/libqos/pci-spapr.c b/tests/libqos/pci-spapr.c
index c0f7e6db9b..4c29889b0b 100644
--- a/tests/libqos/pci-spapr.c
+++ b/tests/libqos/pci-spapr.c
@@ -45,63 +45,63 @@ typedef struct QPCIBusSPAPR {
static uint8_t qpci_spapr_pio_readb(QPCIBus *bus, uint32_t addr)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- return readb(s->pio_cpu_base + addr);
+ return qtest_readb(bus->qts, s->pio_cpu_base + addr);
}
static void qpci_spapr_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- writeb(s->pio_cpu_base + addr, val);
+ qtest_writeb(bus->qts, s->pio_cpu_base + addr, val);
}
static uint16_t qpci_spapr_pio_readw(QPCIBus *bus, uint32_t addr)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- return bswap16(readw(s->pio_cpu_base + addr));
+ return bswap16(qtest_readw(bus->qts, s->pio_cpu_base + addr));
}
static void qpci_spapr_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- writew(s->pio_cpu_base + addr, bswap16(val));
+ qtest_writew(bus->qts, s->pio_cpu_base + addr, bswap16(val));
}
static uint32_t qpci_spapr_pio_readl(QPCIBus *bus, uint32_t addr)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- return bswap32(readl(s->pio_cpu_base + addr));
+ return bswap32(qtest_readl(bus->qts, s->pio_cpu_base + addr));
}
static void qpci_spapr_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- writel(s->pio_cpu_base + addr, bswap32(val));
+ qtest_writel(bus->qts, s->pio_cpu_base + addr, bswap32(val));
}
static uint64_t qpci_spapr_pio_readq(QPCIBus *bus, uint32_t addr)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- return bswap64(readq(s->pio_cpu_base + addr));
+ return bswap64(qtest_readq(bus->qts, s->pio_cpu_base + addr));
}
static void qpci_spapr_pio_writeq(QPCIBus *bus, uint32_t addr, uint64_t val)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- writeq(s->pio_cpu_base + addr, bswap64(val));
+ qtest_writeq(bus->qts, s->pio_cpu_base + addr, bswap64(val));
}
static void qpci_spapr_memread(QPCIBus *bus, uint32_t addr,
void *buf, size_t len)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- memread(s->mmio32_cpu_base + addr, buf, len);
+ qtest_memread(bus->qts, s->mmio32_cpu_base + addr, buf, len);
}
static void qpci_spapr_memwrite(QPCIBus *bus, uint32_t addr,
const void *buf, size_t len)
{
QPCIBusSPAPR *s = container_of(bus, QPCIBusSPAPR, bus);
- memwrite(s->mmio32_cpu_base + addr, buf, len);
+ qtest_memwrite(bus->qts, s->mmio32_cpu_base + addr, buf, len);
}
static uint8_t qpci_spapr_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 75e07e16e7..55750dd68d 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -39,10 +39,11 @@ struct QTestState
{
int fd;
int qmp_fd;
- bool irq_level[MAX_IRQ];
- GString *rx;
pid_t qemu_pid; /* our child QEMU process */
+ int wstatus;
bool big_endian;
+ bool irq_level[MAX_IRQ];
+ GString *rx;
};
static GHookList abrt_hooks;
@@ -96,36 +97,52 @@ static int socket_accept(int sock)
return ret;
}
-static void kill_qemu(QTestState *s)
+bool qtest_probe_child(QTestState *s)
{
- if (s->qemu_pid != -1) {
- int wstatus = 0;
- pid_t pid;
+ pid_t pid = s->qemu_pid;
+
+ if (pid != -1) {
+ pid = waitpid(pid, &s->wstatus, WNOHANG);
+ if (pid == 0) {
+ return true;
+ }
+ s->qemu_pid = -1;
+ }
+ return false;
+}
- kill(s->qemu_pid, SIGTERM);
- TFR(pid = waitpid(s->qemu_pid, &wstatus, 0));
+static void kill_qemu(QTestState *s)
+{
+ pid_t pid = s->qemu_pid;
+ int wstatus;
+ /* Skip wait if qtest_probe_child already reaped. */
+ if (pid != -1) {
+ kill(pid, SIGTERM);
+ TFR(pid = waitpid(s->qemu_pid, &s->wstatus, 0));
assert(pid == s->qemu_pid);
- /*
- * We expect qemu to exit with status 0; anything else is
- * fishy and should be logged with as much detail as possible.
- */
- if (wstatus) {
- if (WIFEXITED(wstatus)) {
- fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
- "process but encountered exit status %d\n",
- __FILE__, __LINE__, WEXITSTATUS(wstatus));
- } else if (WIFSIGNALED(wstatus)) {
- int sig = WTERMSIG(wstatus);
- const char *signame = strsignal(sig) ?: "unknown ???";
- const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
-
- fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
- "from signal %d (%s)%s\n",
- __FILE__, __LINE__, sig, signame, dump);
- }
- abort();
+ }
+
+ /*
+ * We expect qemu to exit with status 0; anything else is
+ * fishy and should be logged with as much detail as possible.
+ */
+ wstatus = s->wstatus;
+ if (wstatus) {
+ if (WIFEXITED(wstatus)) {
+ fprintf(stderr, "%s:%d: kill_qemu() tried to terminate QEMU "
+ "process but encountered exit status %d\n",
+ __FILE__, __LINE__, WEXITSTATUS(wstatus));
+ } else if (WIFSIGNALED(wstatus)) {
+ int sig = WTERMSIG(wstatus);
+ const char *signame = strsignal(sig) ?: "unknown ???";
+ const char *dump = WCOREDUMP(wstatus) ? " (core dumped)" : "";
+
+ fprintf(stderr, "%s:%d: kill_qemu() detected QEMU death "
+ "from signal %d (%s)%s\n",
+ __FILE__, __LINE__, sig, signame, dump);
}
+ abort();
}
}
@@ -187,8 +204,7 @@ static const char *qtest_qemu_binary(void)
return qemu_bin;
}
-QTestState *qtest_init_without_qmp_handshake(bool use_oob,
- const char *extra_args)
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
{
QTestState *s;
int sock, qmpsock, i;
@@ -219,16 +235,17 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
"-qtest unix:%s,nowait "
"-qtest-log %s "
"-chardev socket,path=%s,nowait,id=char0 "
- "-mon chardev=char0,mode=control%s "
+ "-mon chardev=char0,mode=control "
"-machine accel=qtest "
"-display none "
"%s", qemu_binary, socket_path,
getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
- qmp_socket_path, use_oob ? ",x-oob=on" : "",
+ qmp_socket_path,
extra_args ?: "");
g_test_message("starting QEMU: %s", command);
+ s->wstatus = 0;
s->qemu_pid = fork();
if (s->qemu_pid == 0) {
setenv("QEMU_AUDIO_DRV", "none", true);
@@ -266,7 +283,7 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
QTestState *qtest_init(const char *extra_args)
{
- QTestState *s = qtest_init_without_qmp_handshake(false, extra_args);
+ QTestState *s = qtest_init_without_qmp_handshake(extra_args);
QDict *greeting;
/* Read the QMP greeting and then do the handshake */
@@ -736,6 +753,16 @@ void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
qtest_rsp(s, 0);
}
+void qtest_set_irq_in(QTestState *s, const char *qom_path, const char *name,
+ int num, int level)
+{
+ if (!name) {
+ name = "unnamed-gpio-in";
+ }
+ qtest_sendf(s, "set_irq_in %s %s %d %d\n", qom_path, name, num, level);
+ qtest_rsp(s, 0);
+}
+
static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
{
qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index ed88ff99d5..7ea94139b0 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -55,14 +55,12 @@ QTestState *qtest_init(const char *extra_args);
/**
* qtest_init_without_qmp_handshake:
- * @use_oob: true to have the server advertise OOB support
* @extra_args: other arguments to pass to QEMU. CAUTION: these
* arguments are subject to word splitting and shell evaluation.
*
* Returns: #QTestState instance.
*/
-QTestState *qtest_init_without_qmp_handshake(bool use_oob,
- const char *extra_args);
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
/**
* qtest_quit:
@@ -233,6 +231,19 @@ void qtest_irq_intercept_in(QTestState *s, const char *string);
void qtest_irq_intercept_out(QTestState *s, const char *string);
/**
+ * qtest_set_irq_in:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device
+ * @name: IRQ name
+ * @irq: IRQ number
+ * @level: IRQ level
+ *
+ * Force given device/irq GPIO-in pin to the given level.
+ */
+void qtest_set_irq_in(QTestState *s, const char *string, const char *name,
+ int irq, int level);
+
+/**
* qtest_outb:
* @s: #QTestState instance to operate on.
* @addr: I/O port to write to.
@@ -1013,4 +1024,12 @@ bool qmp_rsp_is_err(QDict *rsp);
*/
void qmp_assert_error_class(QDict *rsp, const char *class);
+/**
+ * qtest_probe_child:
+ * @s: QTestState instance to operate on.
+ *
+ * Returns: true if the child is still alive.
+ */
+bool qtest_probe_child(QTestState *s);
+
#endif
diff --git a/tests/machine-none-test.c b/tests/machine-none-test.c
index 2b3b750500..4c6d470798 100644
--- a/tests/machine-none-test.c
+++ b/tests/machine-none-test.c
@@ -75,6 +75,7 @@ static void test_machine_cpu_cli(void)
QDict *response;
const char *arch = qtest_get_arch();
const char *cpu_model = get_cpu_model_by_arch(arch);
+ QTestState *qts;
if (!cpu_model) {
if (!(!strcmp(arch, "microblaze") || !strcmp(arch, "microblazeel"))) {
@@ -83,13 +84,13 @@ static void test_machine_cpu_cli(void)
}
return; /* TODO: die here to force all targets have a test */
}
- global_qtest = qtest_initf("-machine none -cpu '%s'", cpu_model);
+ qts = qtest_initf("-machine none -cpu '%s'", cpu_model);
- response = qmp("{ 'execute': 'quit' }");
+ response = qtest_qmp(qts, "{ 'execute': 'quit' }");
g_assert(qdict_haskey(response, "return"));
qobject_unref(response);
- qtest_quit(global_qtest);
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/tests/microbit-test.c b/tests/microbit-test.c
new file mode 100644
index 0000000000..0c125535f6
--- /dev/null
+++ b/tests/microbit-test.c
@@ -0,0 +1,255 @@
+/*
+ * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC.
+ *
+ * nRF51:
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Microbit Board: http://microbit.org/
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+
+#include "qemu/osdep.h"
+#include "exec/hwaddr.h"
+#include "libqtest.h"
+
+#include "hw/arm/nrf51.h"
+#include "hw/gpio/nrf51_gpio.h"
+#include "hw/timer/nrf51_timer.h"
+
+static void test_nrf51_gpio(void)
+{
+ size_t i;
+ uint32_t actual, expected;
+
+ struct {
+ hwaddr addr;
+ uint32_t expected;
+ } const reset_state[] = {
+ {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000},
+ {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000},
+ {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000},
+ {NRF51_GPIO_REG_DIRCLR, 0x00000000}
+ };
+
+ /* Check reset state */
+ for (i = 0; i < ARRAY_SIZE(reset_state); i++) {
+ expected = reset_state[i].expected;
+ actual = readl(NRF51_GPIO_BASE + reset_state[i].addr);
+ g_assert_cmpuint(actual, ==, expected);
+ }
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ expected = 0x00000002;
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4);
+ g_assert_cmpuint(actual, ==, expected);
+ }
+
+ /* Check dir bit consistency between dir and cnf */
+ /* Check set via DIRSET */
+ expected = 0x80000001;
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ /* Check clear via DIRCLR */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, 0x00000000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+
+ /* Check set via DIR */
+ expected = 0x80000001;
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ /* Reset DIR */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000);
+
+ /* Check Input propagates */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+ /* Check pull-up working */
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+ /* Check pull-down working */
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+
+ /* Check Output propagates */
+ irq_intercept_out("/machine/nrf51");
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ g_assert_true(get_irq(0));
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+ g_assert_false(get_irq(0));
+
+ /* Check self-stimulation */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+
+ /*
+ * Check short-circuit - generates an guest_error which must be checked
+ * manually as long as qtest can not scan qemu_log messages
+ */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+}
+
+static void timer_task(hwaddr task)
+{
+ writel(NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
+}
+
+static void timer_clear_event(hwaddr event)
+{
+ writel(NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
+}
+
+static void timer_set_bitmode(uint8_t mode)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
+}
+
+static void timer_set_prescaler(uint8_t prescaler)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
+}
+
+static void timer_set_cc(size_t idx, uint32_t value)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
+}
+
+static void timer_assert_events(uint32_t ev0, uint32_t ev1, uint32_t ev2,
+ uint32_t ev3)
+{
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0) == ev0);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1) == ev1);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2) == ev2);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3) == ev3);
+}
+
+static void test_nrf51_timer(void)
+{
+ uint32_t steps_to_overflow = 408;
+
+ /* Compare Match */
+ timer_task(NRF51_TIMER_TASK_STOP);
+ timer_task(NRF51_TIMER_TASK_CLEAR);
+
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
+
+ timer_set_bitmode(NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
+ timer_set_prescaler(0);
+ /* Swept over in first step */
+ timer_set_cc(0, 2);
+ /* Barely miss on first step */
+ timer_set_cc(1, 162);
+ /* Spot on on third step */
+ timer_set_cc(2, 480);
+
+ timer_assert_events(0, 0, 0, 0);
+
+ timer_task(NRF51_TIMER_TASK_START);
+ clock_step(10000);
+ timer_assert_events(1, 0, 0, 0);
+
+ /* Swept over on first overflow */
+ timer_set_cc(3, 114);
+
+ clock_step(10000);
+ timer_assert_events(1, 1, 0, 0);
+
+ clock_step(10000);
+ timer_assert_events(1, 1, 1, 0);
+
+ /* Wrap time until internal counter overflows */
+ while (steps_to_overflow--) {
+ timer_assert_events(1, 1, 1, 0);
+ clock_step(10000);
+ }
+
+ timer_assert_events(1, 1, 1, 1);
+
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
+ timer_assert_events(0, 0, 0, 0);
+
+ timer_task(NRF51_TIMER_TASK_STOP);
+
+ /* Test Proposal: Stop/Shutdown */
+ /* Test Proposal: Shortcut Compare -> Clear */
+ /* Test Proposal: Shortcut Compare -> Stop */
+ /* Test Proposal: Counter Mode */
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ global_qtest = qtest_initf("-machine microbit");
+
+ qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
+ qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
+
+ ret = g_test_run();
+
+ qtest_quit(global_qtest);
+ return ret;
+}
diff --git a/tests/migration-test.c b/tests/migration-test.c
index 06ca5068d8..8352612364 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -789,7 +789,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
if (!ufd_version_check()) {
- return 0;
+ return g_test_run();
}
/*
@@ -800,7 +800,7 @@ int main(int argc, char **argv)
if (g_str_equal(qtest_get_arch(), "ppc64") &&
access("/sys/module/kvm_hv", F_OK)) {
g_test_message("Skipping test: kvm_hv not available");
- return 0;
+ return g_test_run();
}
/*
@@ -811,11 +811,11 @@ int main(int argc, char **argv)
#if defined(HOST_S390X)
if (access("/dev/kvm", R_OK | W_OK)) {
g_test_message("Skipping test: kvm not available");
- return 0;
+ return g_test_run();
}
#else
g_test_message("Skipping test: Need s390x host to work properly");
- return 0;
+ return g_test_run();
#endif
}
diff --git a/tests/pnv-xscom-test.c b/tests/pnv-xscom-test.c
index 70f4c84d1b..974f8da5b2 100644
--- a/tests/pnv-xscom-test.c
+++ b/tests/pnv-xscom-test.c
@@ -63,14 +63,15 @@ static uint64_t pnv_xscom_addr(const PnvChip *chip, uint32_t pcba)
return addr;
}
-static uint64_t pnv_xscom_read(const PnvChip *chip, uint32_t pcba)
+static uint64_t pnv_xscom_read(QTestState *qts, const PnvChip *chip,
+ uint32_t pcba)
{
- return readq(pnv_xscom_addr(chip, pcba));
+ return qtest_readq(qts, pnv_xscom_addr(chip, pcba));
}
-static void test_xscom_cfam_id(const PnvChip *chip)
+static void test_xscom_cfam_id(QTestState *qts, const PnvChip *chip)
{
- uint64_t f000f = pnv_xscom_read(chip, 0xf000f);
+ uint64_t f000f = pnv_xscom_read(qts, chip, 0xf000f);
g_assert_cmphex(f000f, ==, chip->cfam_id);
}
@@ -78,11 +79,11 @@ static void test_xscom_cfam_id(const PnvChip *chip)
static void test_cfam_id(const void *data)
{
const PnvChip *chip = data;
+ QTestState *qts;
- global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s",
- chip->cpu_model);
- test_xscom_cfam_id(chip);
- qtest_quit(global_qtest);
+ qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
+ test_xscom_cfam_id(qts, chip);
+ qtest_quit(qts);
}
@@ -94,7 +95,7 @@ static void test_cfam_id(const void *data)
#define PNV_XSCOM_EX_DTS_RESULT0 0x50000
-static void test_xscom_core(const PnvChip *chip)
+static void test_xscom_core(QTestState *qts, const PnvChip *chip)
{
uint32_t first_core_dts0 = PNV_XSCOM_EX_DTS_RESULT0;
uint64_t dts0;
@@ -105,7 +106,7 @@ static void test_xscom_core(const PnvChip *chip)
first_core_dts0 |= PNV_XSCOM_P9_EC_BASE(chip->first_core);
}
- dts0 = pnv_xscom_read(chip, first_core_dts0);
+ dts0 = pnv_xscom_read(qts, chip, first_core_dts0);
g_assert_cmphex(dts0, ==, 0x26f024f023f0000ull);
}
@@ -113,11 +114,11 @@ static void test_xscom_core(const PnvChip *chip)
static void test_core(const void *data)
{
const PnvChip *chip = data;
+ QTestState *qts;
- global_qtest = qtest_initf("-M powernv,accel=tcg -cpu %s",
- chip->cpu_model);
- test_xscom_core(chip);
- qtest_quit(global_qtest);
+ qts = qtest_initf("-M powernv,accel=tcg -cpu %s", chip->cpu_model);
+ test_xscom_core(qts, chip);
+ qtest_quit(qts);
}
static void add_test(const char *name, void (*test)(const void *data))
diff --git a/tests/prom-env-test.c b/tests/prom-env-test.c
index 198d007f1b..4821254b7e 100644
--- a/tests/prom-env-test.c
+++ b/tests/prom-env-test.c
@@ -25,14 +25,14 @@
#define MAGIC 0xcafec0de
#define ADDRESS 0x4000
-static void check_guest_memory(void)
+static void check_guest_memory(QTestState *qts)
{
uint32_t signature;
int i;
/* Poll until code has run and modified memory. Wait at most 600 seconds */
for (i = 0; i < 60000; ++i) {
- signature = readl(ADDRESS);
+ signature = qtest_readl(qts, ADDRESS);
if (signature == MAGIC) {
break;
}
@@ -45,17 +45,16 @@ static void check_guest_memory(void)
static void test_machine(const void *machine)
{
const char *extra_args;
+ QTestState *qts;
/* The pseries firmware boots much faster without the default devices */
extra_args = strcmp(machine, "pseries") == 0 ? "-nodefaults" : "";
- global_qtest = qtest_initf("-M %s,accel=tcg %s "
- "-prom-env 'use-nvramrc?=true' "
- "-prom-env 'nvramrc=%x %x l!' ",
- (const char *)machine, extra_args,
- MAGIC, ADDRESS);
- check_guest_memory();
- qtest_quit(global_qtest);
+ qts = qtest_initf("-M %s,accel=tcg %s -prom-env 'use-nvramrc?=true' "
+ "-prom-env 'nvramrc=%x %x l!' ", (const char *)machine,
+ extra_args, MAGIC, ADDRESS);
+ check_guest_memory(qts);
+ qtest_quit(qts);
}
static void add_tests(const char *machines[])
diff --git a/tests/pvpanic-test.c b/tests/pvpanic-test.c
index 7461a7254f..ff9176adf3 100644
--- a/tests/pvpanic-test.c
+++ b/tests/pvpanic-test.c
@@ -15,13 +15,16 @@ static void test_panic(void)
{
uint8_t val;
QDict *response, *data;
+ QTestState *qts;
- val = inb(0x505);
+ qts = qtest_init("-device pvpanic");
+
+ val = qtest_inb(qts, 0x505);
g_assert_cmpuint(val, ==, 1);
- outb(0x505, 0x1);
+ qtest_outb(qts, 0x505, 0x1);
- response = qmp_receive();
+ response = qtest_qmp_receive(qts);
g_assert(qdict_haskey(response, "event"));
g_assert_cmpstr(qdict_get_str(response, "event"), ==, "GUEST_PANICKED");
g_assert(qdict_haskey(response, "data"));
@@ -29,6 +32,8 @@ static void test_panic(void)
g_assert(qdict_haskey(data, "action"));
g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause");
qobject_unref(response);
+
+ qtest_quit(qts);
}
int main(int argc, char **argv)
@@ -38,10 +43,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_func("/pvpanic/panic", test_panic);
- qtest_start("-device pvpanic");
ret = g_test_run();
- qtest_end();
-
return ret;
}
diff --git a/tests/pxe-test.c b/tests/pxe-test.c
index 6e3679672c..73ac1d1c61 100644
--- a/tests/pxe-test.c
+++ b/tests/pxe-test.c
@@ -61,6 +61,7 @@ static testdef_t s390x_tests[] = {
static void test_pxe_one(const testdef_t *test, bool ipv6)
{
+ QTestState *qts;
char *args;
args = g_strdup_printf(
@@ -70,9 +71,9 @@ static void test_pxe_one(const testdef_t *test, bool ipv6)
test->machine, disk, ipv6 ? "off" : "on", ipv6 ? "on" : "off",
test->model);
- qtest_start(args);
- boot_sector_test(global_qtest);
- qtest_quit(global_qtest);
+ qts = qtest_init(args);
+ boot_sector_test(qts);
+ qtest_quit(qts);
g_free(args);
}
diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err
index 30d8a34373..ebe05bc898 100644
--- a/tests/qapi-schema/alternate-base.err
+++ b/tests/qapi-schema/alternate-base.err
@@ -1 +1,2 @@
tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
+Valid keys are 'alternate', 'data', 'if'.
diff --git a/tests/qapi-schema/alternate-invalid-dict.err b/tests/qapi-schema/alternate-invalid-dict.err
new file mode 100644
index 0000000000..631d46628e
--- /dev/null
+++ b/tests/qapi-schema/alternate-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-invalid-dict.json:2: Key 'type' is missing from member 'two' of alternate 'Alt'
diff --git a/tests/qapi-schema/enum-dict-member.exit b/tests/qapi-schema/alternate-invalid-dict.exit
index d00491fd7e..d00491fd7e 100644
--- a/tests/qapi-schema/enum-dict-member.exit
+++ b/tests/qapi-schema/alternate-invalid-dict.exit
diff --git a/tests/qapi-schema/alternate-invalid-dict.json b/tests/qapi-schema/alternate-invalid-dict.json
new file mode 100644
index 0000000000..8e0b2ac287
--- /dev/null
+++ b/tests/qapi-schema/alternate-invalid-dict.json
@@ -0,0 +1,4 @@
+# exploded member form must have a 'type'
+{ 'alternate': 'Alt',
+ 'data': { 'one': 'str',
+ 'two': { 'if': 'foo' } } }
diff --git a/tests/qapi-schema/enum-dict-member.out b/tests/qapi-schema/alternate-invalid-dict.out
index e69de29bb2..e69de29bb2 100644
--- a/tests/qapi-schema/enum-dict-member.out
+++ b/tests/qapi-schema/alternate-invalid-dict.out
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 8d2f1ce8a2..d1abc4b5a1 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,5 +1,15 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module comments.json
-enum Status ['good', 'bad', 'ugly']
+enum Status
+ member good
+ member bad
+ member ugly
diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out
index cd28721568..db8014eed0 100644
--- a/tests/qapi-schema/doc-bad-section.out
+++ b/tests/qapi-schema/doc-bad-section.out
@@ -1,8 +1,17 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module doc-bad-section.json
-enum Enum ['one', 'two']
+enum Enum
+ member one
+ member two
doc symbol=Enum
body=
== Produces *invalid* texinfo
diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json
index 984cd8ed06..f7fb48af38 100644
--- a/tests/qapi-schema/doc-good.json
+++ b/tests/qapi-schema/doc-good.json
@@ -55,7 +55,9 @@
#
# @two is undocumented
##
-{ 'enum': 'Enum', 'data': [ 'one', 'two' ], 'if': 'defined(IFCOND)' }
+{ 'enum': 'Enum', 'data':
+ [ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ],
+ 'if': 'defined(IFCOND)' }
##
# @Base:
@@ -70,7 +72,8 @@
#
# Another paragraph (but no @var: line)
##
-{ 'struct': 'Variant1', 'data': { 'var1': 'str' } }
+{ 'struct': 'Variant1',
+ 'data': { 'var1': { 'type': 'str', 'if': 'defined(IFSTR)' } } }
##
# @Variant2:
@@ -83,13 +86,13 @@
{ 'union': 'Object',
'base': 'Base',
'discriminator': 'base1',
- 'data': { 'one': 'Variant1', 'two': 'Variant2' } }
+ 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# @SugaredUnion:
##
{ 'union': 'SugaredUnion',
- 'data': { 'one': 'Variant1', 'two': 'Variant2' } }
+ 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
##
# == Another subsection
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 35f3f1164c..21bf345ff0 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -1,29 +1,45 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module doc-good.json
-enum Enum ['one', 'two']
+enum Enum
+ member one
+ if ['defined(IFONE)']
+ member two
if ['defined(IFCOND)']
object Base
member base1: Enum optional=False
object Variant1
member var1: str optional=False
+ if ['defined(IFSTR)']
object Variant2
object Object
base Base
tag base1
case one: Variant1
case two: Variant2
+ if ['IFTWO']
object q_obj_Variant1-wrapper
member data: Variant1 optional=False
object q_obj_Variant2-wrapper
member data: Variant2 optional=False
-enum SugaredUnionKind ['one', 'two']
+enum SugaredUnionKind
+ member one
+ member two
+ if ['IFTWO']
object SugaredUnion
member type: SugaredUnionKind optional=False
tag type
case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper
+ if ['IFTWO']
object q_obj_cmd-arg
member arg1: int optional=False
member arg2: str optional=True
diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi
index e42eace474..2526abc6d9 100644
--- a/tests/qapi-schema/doc-good.texi
+++ b/tests/qapi-schema/doc-good.texi
@@ -84,12 +84,12 @@ Examples:
@table @asis
@item @code{one}
The @emph{one} @{and only@}
+@*@b{If:} @code{defined(IFONE)}
@item @code{two}
Not documented
@end table
@code{two} is undocumented
-
@b{If:} @code{defined(IFCOND)}
@end deftp
@@ -119,6 +119,7 @@ Another paragraph (but no @code{var}: line)
@table @asis
@item @code{var1: string}
Not documented
+@*@b{If:} @code{defined(IFSTR)}
@end table
@end deftp
@@ -141,7 +142,7 @@ Not documented
@table @asis
@item The members of @code{Base}
@item The members of @code{Variant1} when @code{base1} is @t{"one"}
-@item The members of @code{Variant2} when @code{base1} is @t{"two"}
+@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
@end deftp
@@ -157,7 +158,7 @@ Not documented
@item @code{type}
One of @t{"one"}, @t{"two"}
@item @code{data: Variant1} when @code{type} is @t{"one"}
-@item @code{data: Variant2} when @code{type} is @t{"two"}
+@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
@end table
@end deftp
diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err
index f9613c6d6b..799193dba1 100644
--- a/tests/qapi-schema/double-type.err
+++ b/tests/qapi-schema/double-type.err
@@ -1 +1,2 @@
tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar'
+Valid keys are 'base', 'data', 'if', 'struct'.
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 0ec234eec4..5483cb7bc6 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,3 +1,10 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
diff --git a/tests/qapi-schema/enum-bad-member.err b/tests/qapi-schema/enum-bad-member.err
new file mode 100644
index 0000000000..211db9e6fc
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-bad-member.json:2: Member of enum 'MyEnum' requires a string name
diff --git a/tests/qapi-schema/enum-bad-member.exit b/tests/qapi-schema/enum-bad-member.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-bad-member.json b/tests/qapi-schema/enum-bad-member.json
new file mode 100644
index 0000000000..98da6828b4
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string
+{ 'enum': 'MyEnum', 'data': [ [ ] ] }
diff --git a/tests/qapi-schema/enum-bad-member.out b/tests/qapi-schema/enum-bad-member.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/enum-bad-member.out
diff --git a/tests/qapi-schema/enum-dict-member-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err
new file mode 100644
index 0000000000..2aae618be0
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.err
@@ -0,0 +1,2 @@
+tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in dictionary member of enum 'MyEnum'
+Valid keys are 'if', 'name'.
diff --git a/tests/qapi-schema/enum-dict-member-unknown.exit b/tests/qapi-schema/enum-dict-member-unknown.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-dict-member-unknown.json b/tests/qapi-schema/enum-dict-member-unknown.json
new file mode 100644
index 0000000000..6664c59201
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.json
@@ -0,0 +1,2 @@
+# we reject any enum member that is not a string or a dict with 'name'
+{ 'enum': 'MyEnum', 'data': [ { 'name': 'foo', 'bad-key': 'str' } ] }
diff --git a/tests/qapi-schema/enum-dict-member-unknown.out b/tests/qapi-schema/enum-dict-member-unknown.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/enum-dict-member-unknown.out
diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err
deleted file mode 100644
index 8ca146ea59..0000000000
--- a/tests/qapi-schema/enum-dict-member.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json
deleted file mode 100644
index 79672e0f09..0000000000
--- a/tests/qapi-schema/enum-dict-member.json
+++ /dev/null
@@ -1,2 +0,0 @@
-# we reject any enum member that is not a string
-{ 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err
new file mode 100644
index 0000000000..54c3cf887b
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.err
@@ -0,0 +1 @@
+tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings
diff --git a/tests/qapi-schema/enum-if-invalid.exit b/tests/qapi-schema/enum-if-invalid.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/enum-if-invalid.json b/tests/qapi-schema/enum-if-invalid.json
new file mode 100644
index 0000000000..60bd0ef1d7
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.json
@@ -0,0 +1,3 @@
+# check invalid 'if' type
+{ 'enum': 'TestIfEnum', 'data':
+ [ 'foo', { 'name' : 'bar', 'if': { 'val': 'foo' } } ] }
diff --git a/tests/qapi-schema/enum-if-invalid.out b/tests/qapi-schema/enum-if-invalid.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/enum-if-invalid.out
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 88c0964917..f69d4ffe4e 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -1,6 +1,13 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module event-case.json
event oops None
boxed=False
diff --git a/tests/qapi-schema/event-member-invalid-dict.err b/tests/qapi-schema/event-member-invalid-dict.err
new file mode 100644
index 0000000000..1a57fa29b0
--- /dev/null
+++ b/tests/qapi-schema/event-member-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/event-member-invalid-dict.json:1: Key 'type' is missing from member 'a' of 'data' for event 'EVENT_A'
diff --git a/tests/qapi-schema/event-member-invalid-dict.exit b/tests/qapi-schema/event-member-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/event-member-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/event-member-invalid-dict.json b/tests/qapi-schema/event-member-invalid-dict.json
new file mode 100644
index 0000000000..ee6f3ecb6f
--- /dev/null
+++ b/tests/qapi-schema/event-member-invalid-dict.json
@@ -0,0 +1,2 @@
+{ 'event': 'EVENT_A',
+ 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/event-member-invalid-dict.out b/tests/qapi-schema/event-member-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/event-member-invalid-dict.out
diff --git a/tests/qapi-schema/event-nest-struct.json b/tests/qapi-schema/event-nest-struct.json
index ee6f3ecb6f..355ddaeff1 100644
--- a/tests/qapi-schema/event-nest-struct.json
+++ b/tests/qapi-schema/event-nest-struct.json
@@ -1,2 +1,2 @@
{ 'event': 'EVENT_A',
- 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
+ 'data': { 'a' : { 'type' : { 'integer': 'int' } }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.err b/tests/qapi-schema/flat-union-inline-invalid-dict.err
new file mode 100644
index 0000000000..9c4c45b7f0
--- /dev/null
+++ b/tests/qapi-schema/flat-union-inline-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-inline-invalid-dict.json:7: Key 'type' is missing from member 'value1' of union 'TestUnion'
diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.exit b/tests/qapi-schema/flat-union-inline-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/flat-union-inline-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.json b/tests/qapi-schema/flat-union-inline-invalid-dict.json
new file mode 100644
index 0000000000..62c7cda617
--- /dev/null
+++ b/tests/qapi-schema/flat-union-inline-invalid-dict.json
@@ -0,0 +1,11 @@
+# we require branches to be a struct name
+# TODO: should we allow anonymous inline branch types?
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+{ 'struct': 'Base',
+ 'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
+{ 'union': 'TestUnion',
+ 'base': 'Base',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': { 'string': 'str' },
+ 'value2': { 'integer': 'int' } } }
diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.out b/tests/qapi-schema/flat-union-inline-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/flat-union-inline-invalid-dict.out
diff --git a/tests/qapi-schema/flat-union-inline.json b/tests/qapi-schema/flat-union-inline.json
index 62c7cda617..a9b3ce3f0d 100644
--- a/tests/qapi-schema/flat-union-inline.json
+++ b/tests/qapi-schema/flat-union-inline.json
@@ -7,5 +7,5 @@
{ 'union': 'TestUnion',
'base': 'Base',
'discriminator': 'enum1',
- 'data': { 'value1': { 'string': 'str' },
+ 'data': { 'value1': { 'type': {} },
'value2': { 'integer': 'int' } } }
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.err b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
new file mode 100644
index 0000000000..0c94c9860d
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-invalid-if-discriminator.json:13: The discriminator TestBase.enum1 for union TestUnion must not be conditional
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.exit b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.json b/tests/qapi-schema/flat-union-invalid-if-discriminator.json
new file mode 100644
index 0000000000..618ec36396
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+ 'data': [ 'value1', 'value2' ] }
+
+{ 'struct': 'TestBase',
+ 'data': { 'enum1': { 'type': 'TestEnum', 'if': 'FOO' } } }
+
+{ 'struct': 'TestTypeA',
+ 'data': { 'string': 'str' } }
+
+{ 'struct': 'TestTypeB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+ 'base': 'TestBase',
+ 'discriminator': 'enum1',
+ 'data': { 'value1': 'TestTypeA',
+ 'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.out b/tests/qapi-schema/flat-union-invalid-if-discriminator.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.out
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 24c976f473..7f891f7e90 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -1,6 +1,13 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module ident-with-escape.json
object q_obj_fooA-arg
member bar1: str optional=False
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index ebbabd7a18..783ccfc855 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -1,9 +1,19 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module include-relpath.json
include include/relpath.json
module include/relpath.json
include include-relpath-sub.json
module include-relpath-sub.json
-enum Status ['good', 'bad', 'ugly']
+enum Status
+ member good
+ member bad
+ member ugly
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 7235e055bc..d45977ee56 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,10 +1,20 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module include-repetition.json
include comments.json
module comments.json
-enum Status ['good', 'bad', 'ugly']
+enum Status
+ member good
+ member bad
+ member ugly
module include-repetition.json
include include-repetition-sub.json
module include-repetition-sub.json
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 006f723eeb..1afe20802a 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,7 +1,17 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module include-simple.json
include include-simple-sub.json
module include-simple-sub.json
-enum Status ['good', 'bad', 'ugly']
+enum Status
+ member good
+ member bad
+ member ugly
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index bd8a48630e..c0cf3243f3 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,6 +1,13 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module indented-expr.json
command eins None -> None
gen=True success_response=True boxed=False oob=False preconfig=False
diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.err b/tests/qapi-schema/nested-struct-data-invalid-dict.err
new file mode 100644
index 0000000000..5bd364e8d9
--- /dev/null
+++ b/tests/qapi-schema/nested-struct-data-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/nested-struct-data-invalid-dict.json:2: Key 'type' is missing from member 'a' of 'data' for command 'foo'
diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.exit b/tests/qapi-schema/nested-struct-data-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/nested-struct-data-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.json b/tests/qapi-schema/nested-struct-data-invalid-dict.json
new file mode 100644
index 0000000000..efbe773ded
--- /dev/null
+++ b/tests/qapi-schema/nested-struct-data-invalid-dict.json
@@ -0,0 +1,3 @@
+# inline subtypes collide with our desired future use of defaults
+{ 'command': 'foo',
+ 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.out b/tests/qapi-schema/nested-struct-data-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/nested-struct-data-invalid-dict.out
diff --git a/tests/qapi-schema/nested-struct-data.json b/tests/qapi-schema/nested-struct-data.json
index efbe773ded..5b8a40cca3 100644
--- a/tests/qapi-schema/nested-struct-data.json
+++ b/tests/qapi-schema/nested-struct-data.json
@@ -1,3 +1,3 @@
# inline subtypes collide with our desired future use of defaults
{ 'command': 'foo',
- 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
+ 'data': { 'a' : { 'type': {} }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index fb03163430..cb0857df52 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -11,7 +11,7 @@
'guest-sync' ] } }
{ 'struct': 'TestStruct',
- 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
+ 'data': { 'integer': {'type': 'int'}, 'boolean': 'bool', 'string': 'str' } }
# for testing enums
{ 'struct': 'NestedEnumsOne',
@@ -77,7 +77,7 @@
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase', # intentional forward reference
'discriminator': 'enum1',
- 'data': { 'value1' : 'UserDefA',
+ 'data': { 'value1' : {'type': 'UserDefA'},
'value2' : 'UserDefB',
'value3' : 'UserDefB'
# 'value4' defaults to empty
@@ -98,7 +98,7 @@
{ 'struct': 'WrapAlternate',
'data': { 'alt': 'UserDefAlternate' } }
{ 'alternate': 'UserDefAlternate',
- 'data': { 'udfu': 'UserDefFlatUnion', 'e': 'EnumOne', 'i': 'int',
+ 'data': { 'udfu': {'type': 'UserDefFlatUnion'}, 'e': 'EnumOne', 'i': 'int',
'n': 'null' } }
{ 'struct': 'UserDefC',
@@ -134,7 +134,7 @@
{ 'command': 'user_def_cmd', 'data': {} }
{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
{ 'command': 'user_def_cmd2',
- 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
+ 'data': {'ud1a': {'type': 'UserDefOne'}, '*ud1b': 'UserDefOne'},
'returns': 'UserDefTwo' }
{ 'command': 'cmd-success-response', 'data': {}, 'success-response': false }
@@ -166,7 +166,7 @@
# testing event
{ 'struct': 'EventStructOne',
- 'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }
+ 'data': { 'struct1': {'type': 'UserDefOne'}, 'string': 'str', '*enum2': 'EnumOne' } }
{ 'event': 'EVENT_A' }
{ 'event': 'EVENT_B',
@@ -201,23 +201,40 @@
# test 'if' condition handling
-{ 'struct': 'TestIfStruct', 'data': { 'foo': 'int' },
+{ 'struct': 'TestIfStruct', 'data':
+ { 'foo': 'int',
+ 'bar': { 'type': 'int', 'if': 'defined(TEST_IF_STRUCT_BAR)'} },
'if': 'defined(TEST_IF_STRUCT)' }
-{ 'enum': 'TestIfEnum', 'data': [ 'foo', 'bar' ],
+{ 'enum': 'TestIfEnum', 'data':
+ [ 'foo', { 'name' : 'bar', 'if': 'defined(TEST_IF_ENUM_BAR)' } ],
'if': 'defined(TEST_IF_ENUM)' }
-{ 'union': 'TestIfUnion', 'data': { 'foo': 'TestStruct' },
+{ 'union': 'TestIfUnion', 'data':
+ { 'foo': 'TestStruct',
+ 'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
-{ 'alternate': 'TestIfAlternate', 'data': { 'foo': 'int', 'bar': 'TestStruct' },
+{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
+ 'if': 'defined(TEST_IF_UNION)' }
+
+{ 'alternate': 'TestIfAlternate', 'data':
+ { 'foo': 'int',
+ 'bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
-{ 'command': 'TestIfCmd', 'data': { 'foo': 'TestIfStruct' },
+{ 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
+ 'if': 'defined(TEST_IF_ALT)' }
+
+{ 'command': 'TestIfCmd', 'data':
+ { 'foo': 'TestIfStruct',
+ 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
'returns': 'UserDefThree',
'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
{ 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' }
-{ 'event': 'TestIfEvent', 'data': { 'foo': 'TestIfStruct' },
+{ 'event': 'TestIfEvent', 'data':
+ { 'foo': 'TestIfStruct',
+ 'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_EVT_BAR)' } },
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 218ac7d556..9464101d26 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,6 +1,13 @@
object q_empty
-enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
+enum QType
prefix QTYPE
+ member none
+ member qnull
+ member qnum
+ member qstring
+ member qdict
+ member qlist
+ member qbool
module qapi-schema-test.json
object TestStruct
member integer: int optional=False
@@ -11,19 +18,25 @@ object NestedEnumsOne
member enum2: EnumOne optional=True
member enum3: EnumOne optional=False
member enum4: EnumOne optional=True
-enum MyEnum []
+enum MyEnum
object Empty1
object Empty2
base Empty1
command user_def_cmd0 Empty2 -> Empty2
gen=True success_response=True boxed=False oob=False preconfig=False
-enum QEnumTwo ['value1', 'value2']
+enum QEnumTwo
prefix QENUM_TWO
+ member value1
+ member value2
object UserDefOne
base UserDefZero
member string: str optional=False
member enum1: EnumOne optional=True
-enum EnumOne ['value1', 'value2', 'value3', 'value4']
+enum EnumOne
+ member value1
+ member value2
+ member value3
+ member value4
object UserDefZero
member integer: int optional=False
object UserDefTwoDictDict
@@ -127,7 +140,21 @@ object q_obj_sizeList-wrapper
member data: sizeList optional=False
object q_obj_anyList-wrapper
member data: anyList optional=False
-enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
+enum UserDefNativeListUnionKind
+ member integer
+ member s8
+ member s16
+ member s32
+ member s64
+ member u8
+ member u16
+ member u32
+ member u64
+ member number
+ member boolean
+ member string
+ member sizes
+ member any
object UserDefNativeListUnion
member type: UserDefNativeListUnionKind optional=False
tag type
@@ -204,7 +231,8 @@ event EVENT_E UserDefZero
boxed=True
event EVENT_F UserDefAlternate
boxed=True
-enum __org.qemu_x-Enum ['__org.qemu_x-value']
+enum __org.qemu_x-Enum
+ member __org.qemu_x-value
object __org.qemu_x-Base
member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
object __org.qemu_x-Struct
@@ -213,7 +241,8 @@ object __org.qemu_x-Struct
member wchar-t: int optional=True
object q_obj_str-wrapper
member data: str optional=False
-enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
+enum __org.qemu_x-Union1Kind
+ member __org.qemu_x-branch
object __org.qemu_x-Union1
member type: __org.qemu_x-Union1Kind optional=False
tag type
@@ -239,25 +268,50 @@ command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Unio
gen=True success_response=True boxed=False oob=False preconfig=False
object TestIfStruct
member foo: int optional=False
+ member bar: int optional=False
+ if ['defined(TEST_IF_STRUCT_BAR)']
if ['defined(TEST_IF_STRUCT)']
-enum TestIfEnum ['foo', 'bar']
+enum TestIfEnum
+ member foo
+ member bar
+ if ['defined(TEST_IF_ENUM_BAR)']
if ['defined(TEST_IF_ENUM)']
object q_obj_TestStruct-wrapper
member data: TestStruct optional=False
-enum TestIfUnionKind ['foo']
+enum TestIfUnionKind
+ member foo
+ member union_bar
+ if ['defined(TEST_IF_UNION_BAR)']
if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
object TestIfUnion
member type: TestIfUnionKind optional=False
tag type
case foo: q_obj_TestStruct-wrapper
+ case union_bar: q_obj_str-wrapper
+ if ['defined(TEST_IF_UNION_BAR)']
if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
+object q_obj_TestIfUnionCmd-arg
+ member union_cmd_arg: TestIfUnion optional=False
+ if ['defined(TEST_IF_UNION)']
+command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
+ gen=True success_response=True boxed=False oob=False preconfig=False
+ if ['defined(TEST_IF_UNION)']
alternate TestIfAlternate
tag type
case foo: int
case bar: TestStruct
+ if ['defined(TEST_IF_ALT_BAR)']
if ['defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)']
+object q_obj_TestIfAlternateCmd-arg
+ member alt_cmd_arg: TestIfAlternate optional=False
+ if ['defined(TEST_IF_ALT)']
+command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
+ gen=True success_response=True boxed=False oob=False preconfig=False
+ if ['defined(TEST_IF_ALT)']
object q_obj_TestIfCmd-arg
member foo: TestIfStruct optional=False
+ member bar: TestIfEnum optional=False
+ if ['defined(TEST_IF_CMD_BAR)']
if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
@@ -266,6 +320,8 @@ command TestCmdReturnDefThree None -> UserDefThree
gen=True success_response=True boxed=False oob=False preconfig=False
object q_obj_TestIfEvent-arg
member foo: TestIfStruct optional=False
+ member bar: TestIfEnum optional=False
+ if ['defined(TEST_IF_EVT_BAR)']
if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
event TestIfEvent q_obj_TestIfEvent-arg
boxed=False
diff --git a/tests/qapi-schema/struct-member-invalid-dict.err b/tests/qapi-schema/struct-member-invalid-dict.err
new file mode 100644
index 0000000000..6a765bc668
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/struct-member-invalid-dict.json:2: Key 'type' is missing from member '*a' of 'data' for struct 'foo'
diff --git a/tests/qapi-schema/struct-member-invalid-dict.exit b/tests/qapi-schema/struct-member-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/struct-member-invalid-dict.json b/tests/qapi-schema/struct-member-invalid-dict.json
new file mode 100644
index 0000000000..9fe0d455a9
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.json
@@ -0,0 +1,3 @@
+# Long form of member must have a value member 'type'
+{ 'struct': 'foo',
+ 'data': { '*a': { 'case': 'foo' } } }
diff --git a/tests/qapi-schema/struct-member-invalid-dict.out b/tests/qapi-schema/struct-member-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/struct-member-invalid-dict.out
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index cea21c773a..d592854601 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -23,10 +23,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
def visit_include(self, name, info):
print('include %s' % name)
- def visit_enum_type(self, name, info, ifcond, values, prefix):
- print('enum %s %s' % (name, values))
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
+ print('enum %s' % name)
if prefix:
print(' prefix %s' % prefix)
+ for m in members:
+ print(' member %s' % m.name)
+ self._print_if(m.ifcond, indent=8)
self._print_if(ifcond)
def visit_object_type(self, name, info, ifcond, base, members, variants):
@@ -36,6 +39,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
for m in members:
print(' member %s: %s optional=%s'
% (m.name, m.type.name, m.optional))
+ self._print_if(m.ifcond, 8)
self._print_variants(variants)
self._print_if(ifcond)
@@ -64,6 +68,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print(' tag %s' % variants.tag_member.name)
for v in variants.variants:
print(' case %s: %s' % (v.name, v.type.name))
+ QAPISchemaTestVisitor._print_if(v.ifcond, indent=8)
@staticmethod
def _print_if(ifcond, indent=4):
diff --git a/tests/qapi-schema/union-branch-invalid-dict.err b/tests/qapi-schema/union-branch-invalid-dict.err
new file mode 100644
index 0000000000..89f9b36791
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-branch-invalid-dict.json:2: Key 'type' is missing from member 'integer' of union 'UnionInvalidBranch'
diff --git a/tests/qapi-schema/union-branch-invalid-dict.exit b/tests/qapi-schema/union-branch-invalid-dict.exit
new file mode 100644
index 0000000000..d00491fd7e
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-branch-invalid-dict.json b/tests/qapi-schema/union-branch-invalid-dict.json
new file mode 100644
index 0000000000..9778598dbd
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.json
@@ -0,0 +1,4 @@
+# Long form of member must have a value member 'type'
+{ 'union': 'UnionInvalidBranch',
+ 'data': { 'integer': { 'if': 'foo'},
+ 's8': 'int8' } }
diff --git a/tests/qapi-schema/union-branch-invalid-dict.out b/tests/qapi-schema/union-branch-invalid-dict.out
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/qapi-schema/union-branch-invalid-dict.out
diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err
index 12f5ed5b43..6ff8bb99c5 100644
--- a/tests/qapi-schema/unknown-expr-key.err
+++ b/tests/qapi-schema/unknown-expr-key.err
@@ -1 +1,2 @@
-tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar'
+tests/qapi-schema/unknown-expr-key.json:2: Unknown keys 'bogus', 'phony' in struct 'bar'
+Valid keys are 'base', 'data', 'if', 'struct'.
diff --git a/tests/qapi-schema/unknown-expr-key.json b/tests/qapi-schema/unknown-expr-key.json
index 3b2be00cc4..13292d75ed 100644
--- a/tests/qapi-schema/unknown-expr-key.json
+++ b/tests/qapi-schema/unknown-expr-key.json
@@ -1,2 +1,2 @@
# we reject an expression with unknown top-level keys
-{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } }
+{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { }, 'phony': { } }
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index d67c6234a4..af623cfd86 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -419,7 +419,7 @@ QMP_VERSION
write failed: Input/output error
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Testing incoming inactive corrupted image ===
@@ -430,7 +430,7 @@ qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); fur
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
corrupt: false
*** done
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index 1d5e28d730..bca0c02f5c 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -46,7 +46,7 @@ QMP_VERSION
read failed: Input/output error
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Testing blkverify on existing block device ===
@@ -85,7 +85,7 @@ wrote 512/512 bytes at offset 0
read failed: Input/output error
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index 8d81736336..8ec1783ffe 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -36,7 +36,7 @@ read 10485760/10485760 bytes at offset 0
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
== using quorum rewrite corrupted mode ==
@@ -80,7 +80,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
Testing:
QMP_VERSION
@@ -89,7 +89,7 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
== dynamically removing a child from a quorum ==
@@ -99,7 +99,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
Testing:
QMP_VERSION
@@ -107,7 +107,7 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
Testing:
QMP_VERSION
@@ -115,7 +115,7 @@ QMP_VERSION
{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
{"error": {"class": "GenericError", "desc": "Cannot find device=drive0-quorum nor node_name=drive0-quorum"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
Testing:
QMP_VERSION
@@ -123,6 +123,6 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out
index f9af8bb691..7419722cd7 100644
--- a/tests/qemu-iotests/083.out
+++ b/tests/qemu-iotests/083.out
@@ -41,8 +41,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after neg2 ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
=== Check disconnect 8 neg2 ===
@@ -55,40 +53,30 @@ can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before request ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
=== Check disconnect after request ===
-Connection closed
read failed: Input/output error
=== Check disconnect before reply ===
-Connection closed
read failed: Input/output error
=== Check disconnect after reply ===
-Unexpected end-of-file before all bytes were read
read failed: Input/output error
=== Check disconnect 4 reply ===
-Unexpected end-of-file before all bytes were read
-Connection closed
read failed: Input/output error
=== Check disconnect 8 reply ===
-Unexpected end-of-file before all bytes were read
-Connection closed
read failed: Input/output error
=== Check disconnect before data ===
-Unexpected end-of-file before all bytes were read
read failed: Input/output error
=== Check disconnect after data ===
@@ -118,8 +106,6 @@ can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect after neg-classic ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
=== Check disconnect before neg1 ===
@@ -164,8 +150,6 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg2 ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
=== Check disconnect 8 neg2 ===
@@ -178,40 +162,30 @@ can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
=== Check disconnect before request ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
=== Check disconnect after request ===
-Connection closed
read failed: Input/output error
=== Check disconnect before reply ===
-Connection closed
read failed: Input/output error
=== Check disconnect after reply ===
-Unexpected end-of-file before all bytes were read
read failed: Input/output error
=== Check disconnect 4 reply ===
-Unexpected end-of-file before all bytes were read
-Connection closed
read failed: Input/output error
=== Check disconnect 8 reply ===
-Unexpected end-of-file before all bytes were read
-Connection closed
read failed: Input/output error
=== Check disconnect before data ===
-Unexpected end-of-file before all bytes were read
read failed: Input/output error
=== Check disconnect after data ===
@@ -241,8 +215,6 @@ can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg-classic ===
-Unable to read from socket: Connection reset by peer
-Connection closed
read failed: Input/output error
*** done
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index b1318c6ed6..2d92ea847b 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -8,7 +8,7 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Duplicate ID ===
@@ -19,7 +19,7 @@ QMP_VERSION
{"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}}
{"error": {"class": "GenericError", "desc": "Duplicate node name"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== aio=native without O_DIRECT ===
@@ -29,7 +29,7 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "aio=native was specified, but it requires cache.direct=on, which was not specified."}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Encrypted image QCow ===
@@ -41,7 +41,7 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Encrypted image LUKS ===
@@ -53,7 +53,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Missing driver ===
@@ -64,6 +64,6 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/094.out b/tests/qemu-iotests/094.out
index 665b630b08..f3b9ecf22b 100644
--- a/tests/qemu-iotests/094.out
+++ b/tests/qemu-iotests/094.out
@@ -14,5 +14,5 @@ Formatting 'TEST_DIR/source.IMGFMT', fmt=IMGFMT size=67108864
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
index ad0ee6fb48..9c1159bf08 100644
--- a/tests/qemu-iotests/109.out
+++ b/tests/qemu-iotests/109.out
@@ -18,7 +18,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -29,7 +29,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
@@ -56,7 +56,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -67,7 +67,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
@@ -94,7 +94,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -105,7 +105,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
@@ -132,7 +132,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -143,7 +143,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
@@ -170,7 +170,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -181,7 +181,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
@@ -208,7 +208,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -219,7 +219,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
@@ -245,7 +245,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -256,7 +256,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
@@ -282,7 +282,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -293,7 +293,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
@@ -319,7 +319,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -330,7 +330,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
@@ -356,7 +356,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": []}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": {}}
@@ -367,7 +367,7 @@ read 65536/65536 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
@@ -390,7 +390,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
@@ -406,7 +406,7 @@ Images are identical.
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
diff --git a/tests/qemu-iotests/117.out b/tests/qemu-iotests/117.out
index 851e214144..57079af167 100644
--- a/tests/qemu-iotests/117.out
+++ b/tests/qemu-iotests/117.out
@@ -7,7 +7,7 @@ wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
No errors were found on the image.
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/119.out b/tests/qemu-iotests/119.out
index a8743b810e..7b7f0f4bcc 100644
--- a/tests/qemu-iotests/119.out
+++ b/tests/qemu-iotests/119.out
@@ -6,6 +6,6 @@ read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/120.out b/tests/qemu-iotests/120.out
index 1af1aeb38d..0744c1f136 100644
--- a/tests/qemu-iotests/120.out
+++ b/tests/qemu-iotests/120.out
@@ -6,7 +6,7 @@ wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 65536/65536 bytes at offset 0
diff --git a/tests/qemu-iotests/127.out b/tests/qemu-iotests/127.out
index 83b522d4c2..6c98b1824e 100644
--- a/tests/qemu-iotests/127.out
+++ b/tests/qemu-iotests/127.out
@@ -17,5 +17,5 @@ wrote 42/42 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133
index a9a47a3c36..565e0b1b6e 100755
--- a/tests/qemu-iotests/133
+++ b/tests/qemu-iotests/133
@@ -91,6 +91,24 @@ echo
IMGOPTSSYNTAX=false $QEMU_IO -f null-co -c 'reopen' -c 'info' \
"json:{'driver': 'null-co', 'size': 65536}"
+echo
+echo "=== Check that mixing -c/-r/-w and their corresponding options is forbidden ==="
+echo
+
+$QEMU_IO -c 'reopen -r -o read-only=on' $TEST_IMG
+$QEMU_IO -c 'reopen -w -o read-only=on' $TEST_IMG
+$QEMU_IO -c 'reopen -c none -o cache.direct=on' $TEST_IMG
+$QEMU_IO -c 'reopen -c writeback -o cache.direct=on' $TEST_IMG
+$QEMU_IO -c 'reopen -c directsync -o cache.no-flush=on' $TEST_IMG
+
+echo
+echo "=== Check that invalid options are handled correctly ==="
+echo
+
+$QEMU_IO -c 'reopen -o read-only=foo' $TEST_IMG
+$QEMU_IO -c 'reopen -o cache.no-flush=bar' $TEST_IMG
+$QEMU_IO -c 'reopen -o cache.direct=baz' $TEST_IMG
+$QEMU_IO -c 'reopen -o auto-read-only=qux' $TEST_IMG
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out
index f4a85aeb63..414c7fa27f 100644
--- a/tests/qemu-iotests/133.out
+++ b/tests/qemu-iotests/133.out
@@ -24,4 +24,19 @@ Cannot change the option 'driver'
format name: null-co
format name: null-co
+
+=== Check that mixing -c/-r/-w and their corresponding options is forbidden ===
+
+Cannot set both -r/-w and 'read-only'
+Cannot set both -r/-w and 'read-only'
+Cannot set both -c and the cache options
+Cannot set both -c and the cache options
+Cannot set both -c and the cache options
+
+=== Check that invalid options are handled correctly ===
+
+Parameter 'read-only' expects 'on' or 'off'
+Parameter 'cache.no-flush' expects 'on' or 'off'
+Parameter 'cache.direct' expects 'on' or 'off'
+Parameter 'auto-read-only' expects 'on' or 'off'
*** done
diff --git a/tests/qemu-iotests/140.out b/tests/qemu-iotests/140.out
index 7295b3d975..704adcef40 100644
--- a/tests/qemu-iotests/140.out
+++ b/tests/qemu-iotests/140.out
@@ -11,5 +11,5 @@ read 65536/65536 bytes at offset 0
can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: Requested export not available
server reported: export 'drv' not present
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/143.out b/tests/qemu-iotests/143.out
index 1c7fb45543..3e55fcd0ac 100644
--- a/tests/qemu-iotests/143.out
+++ b/tests/qemu-iotests/143.out
@@ -4,5 +4,5 @@ QA output created by 143
can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: Requested export not available
server reported: export 'no_such_export' not present
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out
index 34c057b626..4c391a7603 100644
--- a/tests/qemu-iotests/156.out
+++ b/tests/qemu-iotests/156.out
@@ -41,7 +41,7 @@ read 65536/65536 bytes at offset 196608
{"return": ""}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/176.out b/tests/qemu-iotests/176.out
index f03a2e776c..cc33def96b 100644
--- a/tests/qemu-iotests/176.out
+++ b/tests/qemu-iotests/176.out
@@ -170,7 +170,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -207,7 +207,7 @@ QMP_VERSION
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Test pass bitmap.1 ===
@@ -219,7 +219,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -257,7 +257,7 @@ QMP_VERSION
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Test pass bitmap.2 ===
@@ -269,7 +269,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -307,7 +307,7 @@ QMP_VERSION
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Test pass bitmap.3 ===
@@ -319,7 +319,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -354,5 +354,5 @@ QMP_VERSION
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
*** done
diff --git a/tests/qemu-iotests/183.out b/tests/qemu-iotests/183.out
index 103fdc778b..112cf31f8b 100644
--- a/tests/qemu-iotests/183.out
+++ b/tests/qemu-iotests/183.out
@@ -36,8 +36,8 @@ wrote 65536/65536 bytes at offset 1048576
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
No errors were found on the image.
No errors were found on the image.
wrote 65536/65536 bytes at offset 1048576
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
index 672650cde8..3deb3cfb94 100644
--- a/tests/qemu-iotests/184.out
+++ b/tests/qemu-iotests/184.out
@@ -94,7 +94,8 @@ Testing:
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -173,7 +174,8 @@ Testing:
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -214,7 +216,8 @@ Testing:
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -249,7 +252,8 @@ Testing:
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
diff --git a/tests/qemu-iotests/185.out b/tests/qemu-iotests/185.out
index 4e0ca0dffa..ddfbf3c765 100644
--- a/tests/qemu-iotests/185.out
+++ b/tests/qemu-iotests/185.out
@@ -21,7 +21,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}}
=== Start active commit job and exit qemu ===
@@ -31,7 +31,7 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 backing_file=TEST_DIR/t.q
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}}
=== Start mirror job and exit qemu ===
@@ -42,7 +42,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}}
=== Start backup job and exit qemu ===
@@ -53,7 +53,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}}
=== Start streaming job and exit qemu ===
@@ -63,7 +63,7 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=67108864 cluster_size=65536 l
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}}
No errors were found on the image.
*** done
diff --git a/tests/qemu-iotests/191.out b/tests/qemu-iotests/191.out
index 31a0c7d4c4..a513ccca0b 100644
--- a/tests/qemu-iotests/191.out
+++ b/tests/qemu-iotests/191.out
@@ -389,7 +389,8 @@ wrote 65536/65536 bytes at offset 1048576
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
image: TEST_DIR/t.IMGFMT
@@ -806,7 +807,8 @@ wrote 65536/65536 bytes at offset 1048576
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
image: TEST_DIR/t.IMGFMT
diff --git a/tests/qemu-iotests/195.out b/tests/qemu-iotests/195.out
index 7613575c64..1e9330b1be 100644
--- a/tests/qemu-iotests/195.out
+++ b/tests/qemu-iotests/195.out
@@ -28,7 +28,8 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -65,7 +66,8 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
diff --git a/tests/qemu-iotests/206 b/tests/qemu-iotests/206
index 128c334c7c..5bb738bf23 100755
--- a/tests/qemu-iotests/206
+++ b/tests/qemu-iotests/206
@@ -26,7 +26,9 @@ from iotests import imgfmt
iotests.verify_image_format(supported_fmts=['qcow2'])
def blockdev_create(vm, options):
- result = vm.qmp_log('blockdev-create', job_id='job0', options=options)
+ result = vm.qmp_log('blockdev-create',
+ filters=[iotests.filter_qmp_testfiles],
+ job_id='job0', options=options)
if 'return' in result:
assert result['return'] == {}
@@ -52,7 +54,9 @@ with iotests.FilePath('t.qcow2') as disk_path, \
'filename': disk_path,
'size': 0 })
- vm.qmp_log('blockdev-add', driver='file', filename=disk_path,
+ vm.qmp_log('blockdev-add',
+ filters=[iotests.filter_qmp_testfiles],
+ driver='file', filename=disk_path,
node_name='imgfile')
blockdev_create(vm, { 'driver': imgfmt,
diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223
index 397b865d34..f120a01646 100755
--- a/tests/qemu-iotests/223
+++ b/tests/qemu-iotests/223
@@ -25,6 +25,7 @@ status=1 # failure is the default!
_cleanup()
{
+ nbd_server_stop
_cleanup_test_img
_cleanup_qemu
rm -f "$TEST_DIR/nbd"
@@ -35,6 +36,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
. ./common.qemu
+. ./common.nbd
_supported_fmt qcow2
_supported_proto file # uses NBD as well
@@ -61,6 +63,8 @@ echo "=== Create partially sparse image, then add dirty bitmaps ==="
echo
# Two bitmaps, to contrast granularity issues
+# Also note that b will be disabled, while b2 is left enabled, to
+# check for read-only interactions
_make_test_img -o cluster_size=4k 4M
$QEMU_IO -c 'w -P 0x11 1M 2M' "$TEST_IMG" | _filter_qemu_io
run_qemu <<EOF
@@ -107,26 +111,39 @@ echo
_launch_qemu 2> >(_filter_nbd)
+# Intentionally provoke some errors as well, to check error handling
silent=
_send_qemu_cmd $QEMU_HANDLE '{"execute":"qmp_capabilities"}' "return"
_send_qemu_cmd $QEMU_HANDLE '{"execute":"blockdev-add",
"arguments":{"driver":"qcow2", "node-name":"n",
"file":{"driver":"file", "filename":"'"$TEST_IMG"'"}}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable",
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"block-dirty-bitmap-disable",
"arguments":{"node":"n", "name":"b"}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-block-dirty-bitmap-disable",
- "arguments":{"node":"n", "name":"b2"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"n"}}' "error" # Attempt add without server
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
"arguments":{"addr":{"type":"unix",
"data":{"path":"'"$TEST_DIR/nbd"'"}}}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-start",
+ "arguments":{"addr":{"type":"unix",
+ "data":{"path":"'"$TEST_DIR/nbd"1'"}}}}' "error" # Attempt second server
+$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"n", "bitmap":"b"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"nosuch"}}' "error" # Attempt to export missing node
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
- "arguments":{"device":"n"}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
- "arguments":{"name":"n", "bitmap":"b"}}' "return"
+ "arguments":{"device":"n"}}' "error" # Attempt to export same name twice
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
- "arguments":{"device":"n", "name":"n2"}}' "return"
-_send_qemu_cmd $QEMU_HANDLE '{"execute":"x-nbd-server-add-bitmap",
- "arguments":{"name":"n2", "bitmap":"b2"}}' "return"
+ "arguments":{"device":"n", "name":"n2",
+ "bitmap":"b2"}}' "error" # enabled vs. read-only
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"n", "name":"n2",
+ "bitmap":"b3"}}' "error" # Missing bitmap
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-add",
+ "arguments":{"device":"n", "name":"n2", "writable":true,
+ "bitmap":"b2"}}' "return"
+$QEMU_NBD_PROG -L -k "$TEST_DIR/nbd"
echo
echo "=== Contrast normal status to large granularity dirty-bitmap ==="
@@ -150,16 +167,33 @@ $QEMU_IMG map --output=json --image-opts \
"$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
echo
-echo "=== End NBD server ==="
+echo "=== End qemu NBD server ==="
echo
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
"arguments":{"name":"n"}}' "return"
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-remove",
+ "arguments":{"name":"n2"}}' "error" # Attempt duplicate clean
_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "return"
+_send_qemu_cmd $QEMU_HANDLE '{"execute":"nbd-server-stop"}' "error" # Again
_send_qemu_cmd $QEMU_HANDLE '{"execute":"quit"}' "return"
+echo
+echo "=== Use qemu-nbd as server ==="
+echo
+
+nbd_server_start_unix_socket -r -f $IMGFMT -B b "$TEST_IMG"
+IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b" | _filter_qemu_img_map
+
+nbd_server_start_unix_socket -f $IMGFMT -B b2 "$TEST_IMG"
+IMG="driver=nbd,server.type=unix,server.path=$nbd_unix_socket"
+$QEMU_IMG map --output=json --image-opts \
+ "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:b2" | _filter_qemu_img_map
+
# success, all done
echo '*** done'
rm -f $seq.full
diff --git a/tests/qemu-iotests/223.out b/tests/qemu-iotests/223.out
index de417477de..6476b77ba2 100644
--- a/tests/qemu-iotests/223.out
+++ b/tests/qemu-iotests/223.out
@@ -12,7 +12,7 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
=== Write part of the file under active bitmap ===
@@ -27,12 +27,35 @@ wrote 2097152/2097152 bytes at offset 2097152
{"return": {}}
{"return": {}}
{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
-{"return": {}}
+{"error": {"class": "GenericError", "desc": "NBD server not running"}}
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "NBD server already running"}}
+exports available: 0
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "Cannot find device=nosuch nor node_name=nosuch"}}
+{"error": {"class": "GenericError", "desc": "NBD server already has export named 'n'"}}
+{"error": {"class": "GenericError", "desc": "Enabled bitmap 'b2' incompatible with readonly export"}}
+{"error": {"class": "GenericError", "desc": "Bitmap 'b3' is not found"}}
+{"return": {}}
+exports available: 2
+ export: 'n'
+ size: 4194304
+ flags: 0x4ef ( readonly flush fua trim zeroes df cache )
+ min block: 512
+ opt block: 4096
+ max block: 33554432
+ available meta contexts: 2
+ base:allocation
+ qemu:dirty-bitmap:b
+ export: 'n2'
+ size: 4194304
+ flags: 0x4ed ( flush fua trim zeroes df cache )
+ min block: 512
+ opt block: 4096
+ max block: 33554432
+ available meta contexts: 2
+ base:allocation
+ qemu:dirty-bitmap:b2
=== Contrast normal status to large granularity dirty-bitmap ===
@@ -58,10 +81,22 @@ read 2097152/2097152 bytes at offset 2097152
{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true},
{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
-=== End NBD server ===
+=== End qemu NBD server ===
{"return": {}}
{"return": {}}
+{"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}}
{"return": {}}
+{"error": {"class": "GenericError", "desc": "NBD server not running"}}
{"return": {}}
+
+=== Use qemu-nbd as server ===
+
+[{ "start": 0, "length": 65536, "depth": 0, "zero": false, "data": false},
+{ "start": 65536, "length": 2031616, "depth": 0, "zero": false, "data": true},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
+[{ "start": 0, "length": 512, "depth": 0, "zero": false, "data": true},
+{ "start": 512, "length": 512, "depth": 0, "zero": false, "data": false},
+{ "start": 1024, "length": 2096128, "depth": 0, "zero": false, "data": true},
+{ "start": 2097152, "length": 2097152, "depth": 0, "zero": false, "data": false}]
*** done
diff --git a/tests/qemu-iotests/227.out b/tests/qemu-iotests/227.out
index 736f2e3b11..e77efaf4cf 100644
--- a/tests/qemu-iotests/227.out
+++ b/tests/qemu-iotests/227.out
@@ -53,7 +53,8 @@ Testing: -drive driver=null-co,if=virtio
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -110,7 +111,8 @@ Testing: -drive driver=null-co,if=none
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -140,7 +142,8 @@ Testing: -blockdev driver=null-co,node-name=null
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
@@ -198,7 +201,8 @@ Testing: -blockdev driver=null-co,node-name=null -device virtio-blk,drive=null,i
},
"event": "SHUTDOWN",
"data": {
- "guest": false
+ "guest": false,
+ "reason": "host-qmp-quit"
}
}
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
index 86602437ff..893d098ad2 100755
--- a/tests/qemu-iotests/229
+++ b/tests/qemu-iotests/229
@@ -69,7 +69,6 @@ echo
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'drive-mirror',
'arguments': {'device': 'testdisk',
- 'mode': 'absolute-paths',
'format': '$IMGFMT',
'target': '$DEST_IMG',
'sync': 'full',
diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233
index 1814efe333..fc345a1a46 100755
--- a/tests/qemu-iotests/233
+++ b/tests/qemu-iotests/233
@@ -2,7 +2,7 @@
#
# Test NBD TLS certificate / authorization integration
#
-# Copyright (C) 2018 Red Hat, Inc.
+# Copyright (C) 2018-2019 Red Hat, Inc.
#
# 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
@@ -30,6 +30,7 @@ _cleanup()
{
nbd_server_stop
_cleanup_test_img
+ rm -f "$TEST_DIR/server.log"
tls_x509_cleanup
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -66,12 +67,14 @@ $QEMU_IO -c 'w -P 0x11 1m 1m' "$TEST_IMG" | _filter_qemu_io
echo
echo "== check TLS client to plain server fails =="
-nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG"
+nbd_server_start_tcp_socket -f $IMGFMT "$TEST_IMG" 2> "$TEST_DIR/server.log"
-$QEMU_IMG info --image-opts \
- --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
+obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
+ --tls-creds=tls0
nbd_server_stop
@@ -81,23 +84,28 @@ echo "== check plain client to TLS server fails =="
nbd_server_start_tcp_socket \
--object tls-creds-x509,dir=${tls_dir}/server1,endpoint=server,id=tls0,verify-peer=yes \
--tls-creds tls0 \
- -f $IMGFMT "$TEST_IMG"
+ -f $IMGFMT "$TEST_IMG" 2>> "$TEST_DIR/server.log"
$QEMU_IMG info nbd://localhost:$nbd_tcp_port 2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port
echo
echo "== check TLS works =="
-$QEMU_IMG info --image-opts \
- --object tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0 \
+obj=tls-creds-x509,dir=${tls_dir}/client1,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
+ --tls-creds=tls0
echo
echo "== check TLS with different CA fails =="
-$QEMU_IMG info --image-opts \
- --object tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0 \
+obj=tls-creds-x509,dir=${tls_dir}/client2,endpoint=client,id=tls0
+$QEMU_IMG info --image-opts --object $obj \
driver=nbd,host=$nbd_tcp_addr,port=$nbd_tcp_port,tls-creds=tls0 \
2>&1 | sed "s/$nbd_tcp_port/PORT/g"
+$QEMU_NBD_PROG -L -b $nbd_tcp_addr -p $nbd_tcp_port --object $obj \
+ --tls-creds=tls0
echo
echo "== perform I/O over TLS =="
@@ -109,6 +117,10 @@ $QEMU_IO -c 'r -P 0x11 1m 1m' -c 'w -P 0x22 1m 1m' --image-opts \
$QEMU_IO -f $IMGFMT -r -U -c 'r -P 0x22 1m 1m' "$TEST_IMG" | _filter_qemu_io
+echo
+echo "== final server log =="
+cat "$TEST_DIR/server.log"
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out
index 94acd9b947..6d45f3b230 100644
--- a/tests/qemu-iotests/233.out
+++ b/tests/qemu-iotests/233.out
@@ -15,20 +15,33 @@ wrote 1048576/1048576 bytes at offset 1048576
== check TLS client to plain server fails ==
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Denied by server for option 5 (starttls)
server reported: TLS not configured
+qemu-nbd: Denied by server for option 5 (starttls)
+server reported: TLS not configured
== check plain client to TLS server fails ==
qemu-img: Could not open 'nbd://localhost:PORT': TLS negotiation required before option 8 (structured reply)
server reported: Option 0x8 not permitted before TLS
+qemu-nbd: TLS negotiation required before option 8 (structured reply)
+server reported: Option 0x8 not permitted before TLS
== check TLS works ==
image: nbd://127.0.0.1:PORT
file format: nbd
virtual size: 64M (67108864 bytes)
disk size: unavailable
+exports available: 1
+ export: ''
+ size: 67108864
+ flags: 0x4ed ( flush fua trim zeroes df cache )
+ min block: 512
+ opt block: 4096
+ max block: 33554432
+ available meta contexts: 1
+ base:allocation
== check TLS with different CA fails ==
-option negotiation failed: Verify failed: No certificate was found.
qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': The certificate hasn't got a known issuer
+qemu-nbd: The certificate hasn't got a known issuer
== perform I/O over TLS ==
read 1048576/1048576 bytes at offset 1048576
@@ -37,4 +50,8 @@ wrote 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== final server log ==
+qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
+qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
*** done
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
index da044ed34e..d6edd97ab4 100755
--- a/tests/qemu-iotests/235
+++ b/tests/qemu-iotests/235
@@ -49,7 +49,9 @@ qemu_img_create('-f', iotests.imgfmt, '-o', 'preallocation=metadata', disk,
str(size))
vm = QEMUMachine(iotests.qemu_prog)
-vm.add_args('-machine', 'pc,accel=kvm')
+vm.add_args('-machine', 'accel=kvm')
+if iotests.qemu_default_machine == 's390-ccw-virtio':
+ vm.add_args('-no-shutdown')
vm.add_args('-drive', 'id=src,file=' + disk)
vm.launch()
diff --git a/tests/qemu-iotests/236 b/tests/qemu-iotests/236
new file mode 100755
index 0000000000..79a6381f8e
--- /dev/null
+++ b/tests/qemu-iotests/236
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+#
+# Test bitmap merges.
+#
+# Copyright (c) 2018 John Snow for Red Hat, Inc.
+#
+# 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; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 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/>.
+#
+# owner=jsnow@redhat.com
+
+import iotests
+from iotests import log
+
+iotests.verify_image_format(supported_fmts=['generic'])
+size = 64 * 1024 * 1024
+granularity = 64 * 1024
+
+patterns = [("0x5d", "0", "64k"),
+ ("0xd5", "1M", "64k"),
+ ("0xdc", "32M", "64k"),
+ ("0xcd", "0x3ff0000", "64k")] # 64M - 64K
+
+overwrite = [("0xab", "0", "64k"), # Full overwrite
+ ("0xad", "0x00f8000", "64k"), # Partial-left (1M-32K)
+ ("0x1d", "0x2008000", "64k"), # Partial-right (32M+32K)
+ ("0xea", "0x3fe0000", "64k")] # Adjacent-left (64M - 128K)
+
+def query_bitmaps(vm):
+ res = vm.qmp("query-block")
+ return { "bitmaps": { device['device']: device.get('dirty-bitmaps', []) for
+ device in res['return'] } }
+
+with iotests.FilePath('img') as img_path, \
+ iotests.VM() as vm:
+
+ log('--- Preparing image & VM ---\n')
+ iotests.qemu_img_create('-f', iotests.imgfmt, img_path, str(size))
+ vm.add_drive(img_path)
+ vm.launch()
+
+ log('\n--- Adding preliminary bitmaps A & B ---\n')
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="bitmapA", granularity=granularity)
+ vm.qmp_log("block-dirty-bitmap-add", node="drive0",
+ name="bitmapB", granularity=granularity)
+
+ # Dirties 4 clusters. count=262144
+ log('\n--- Emulating writes ---\n')
+ for p in patterns:
+ cmd = "write -P%s %s %s" % p
+ log(cmd)
+ log(vm.hmp_qemu_io("drive0", cmd))
+
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Submitting & Aborting Transaction ---\n')
+ vm.qmp_log("transaction", indent=2, actions=[
+ { "type": "block-dirty-bitmap-disable",
+ "data": { "node": "drive0", "name": "bitmapB" }},
+ { "type": "block-dirty-bitmap-add",
+ "data": { "node": "drive0", "name": "bitmapC",
+ "granularity": granularity }},
+ { "type": "block-dirty-bitmap-clear",
+ "data": { "node": "drive0", "name": "bitmapA" }},
+ { "type": "abort", "data": {}}
+ ])
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Disabling B & Adding C ---\n')
+ vm.qmp_log("transaction", indent=2, actions=[
+ { "type": "block-dirty-bitmap-disable",
+ "data": { "node": "drive0", "name": "bitmapB" }},
+ { "type": "block-dirty-bitmap-add",
+ "data": { "node": "drive0", "name": "bitmapC",
+ "granularity": granularity }},
+ # Purely extraneous, but test that it works:
+ { "type": "block-dirty-bitmap-disable",
+ "data": { "node": "drive0", "name": "bitmapC" }},
+ { "type": "block-dirty-bitmap-enable",
+ "data": { "node": "drive0", "name": "bitmapC" }},
+ ])
+
+ log('\n--- Emulating further writes ---\n')
+ # Dirties 6 clusters, 3 of which are new in contrast to "A".
+ # A = 64 * 1024 * (4 + 3) = 458752
+ # C = 64 * 1024 * 6 = 393216
+ for p in overwrite:
+ cmd = "write -P%s %s %s" % p
+ log(cmd)
+ log(vm.hmp_qemu_io("drive0", cmd))
+
+ log('\n--- Disabling A & C ---\n')
+ vm.qmp_log("transaction", indent=2, actions=[
+ { "type": "block-dirty-bitmap-disable",
+ "data": { "node": "drive0", "name": "bitmapA" }},
+ { "type": "block-dirty-bitmap-disable",
+ "data": { "node": "drive0", "name": "bitmapC" }}
+ ])
+
+ # A: 7 clusters
+ # B: 4 clusters
+ # C: 6 clusters
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Submitting & Aborting Merge Transaction ---\n')
+ vm.qmp_log("transaction", indent=2, actions=[
+ { "type": "block-dirty-bitmap-add",
+ "data": { "node": "drive0", "name": "bitmapD",
+ "disabled": True, "granularity": granularity }},
+ { "type": "block-dirty-bitmap-merge",
+ "data": { "node": "drive0", "target": "bitmapD",
+ "bitmaps": ["bitmapB", "bitmapC"] }},
+ { "type": "abort", "data": {}}
+ ])
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Creating D as a merge of B & C ---\n')
+ # Good hygiene: create a disabled bitmap as a merge target.
+ vm.qmp_log("transaction", indent=2, actions=[
+ { "type": "block-dirty-bitmap-add",
+ "data": { "node": "drive0", "name": "bitmapD",
+ "disabled": True, "granularity": granularity }},
+ { "type": "block-dirty-bitmap-merge",
+ "data": { "node": "drive0", "target": "bitmapD",
+ "bitmaps": ["bitmapB", "bitmapC"] }}
+ ])
+
+ # A and D should now both have 7 clusters apiece.
+ # B and C remain unchanged with 4 and 6 respectively.
+ log(query_bitmaps(vm), indent=2)
+
+ # A and D should be equivalent.
+ # Some formats round the size of the disk, so don't print the checksums.
+ check_a = vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node="drive0", name="bitmapA")['return']['sha256']
+ check_d = vm.qmp('x-debug-block-dirty-bitmap-sha256',
+ node="drive0", name="bitmapD")['return']['sha256']
+ assert(check_a == check_d)
+
+ log('\n--- Removing bitmaps A, B, C, and D ---\n')
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapA")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapB")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapC")
+ vm.qmp_log("block-dirty-bitmap-remove", node="drive0", name="bitmapD")
+
+ log('\n--- Final Query ---\n')
+ log(query_bitmaps(vm), indent=2)
+
+ log('\n--- Done ---\n')
+ vm.shutdown()
diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out
new file mode 100644
index 0000000000..1dad24db0d
--- /dev/null
+++ b/tests/qemu-iotests/236.out
@@ -0,0 +1,351 @@
+--- Preparing image & VM ---
+
+
+--- Adding preliminary bitmaps A & B ---
+
+{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmapA", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-add", "arguments": {"granularity": 65536, "name": "bitmapB", "node": "drive0"}}
+{"return": {}}
+
+--- Emulating writes ---
+
+write -P0x5d 0 64k
+{"return": ""}
+write -P0xd5 1M 64k
+{"return": ""}
+write -P0xdc 32M 64k
+{"return": ""}
+write -P0xcd 0x3ff0000 64k
+{"return": ""}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapB",
+ "status": "active"
+ },
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapA",
+ "status": "active"
+ }
+ ]
+ }
+}
+
+--- Submitting & Aborting Transaction ---
+
+{
+ "execute": "transaction",
+ "arguments": {
+ "actions": [
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapB"
+ },
+ "type": "block-dirty-bitmap-disable"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapC",
+ "granularity": 65536
+ },
+ "type": "block-dirty-bitmap-add"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapA"
+ },
+ "type": "block-dirty-bitmap-clear"
+ },
+ {
+ "data": {},
+ "type": "abort"
+ }
+ ]
+ }
+}
+{
+ "error": {
+ "class": "GenericError",
+ "desc": "Transaction aborted using Abort action"
+ }
+}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapB",
+ "status": "active"
+ },
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapA",
+ "status": "active"
+ }
+ ]
+ }
+}
+
+--- Disabling B & Adding C ---
+
+{
+ "execute": "transaction",
+ "arguments": {
+ "actions": [
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapB"
+ },
+ "type": "block-dirty-bitmap-disable"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapC",
+ "granularity": 65536
+ },
+ "type": "block-dirty-bitmap-add"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapC"
+ },
+ "type": "block-dirty-bitmap-disable"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapC"
+ },
+ "type": "block-dirty-bitmap-enable"
+ }
+ ]
+ }
+}
+{
+ "return": {}
+}
+
+--- Emulating further writes ---
+
+write -P0xab 0 64k
+{"return": ""}
+write -P0xad 0x00f8000 64k
+{"return": ""}
+write -P0x1d 0x2008000 64k
+{"return": ""}
+write -P0xea 0x3fe0000 64k
+{"return": ""}
+
+--- Disabling A & C ---
+
+{
+ "execute": "transaction",
+ "arguments": {
+ "actions": [
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapA"
+ },
+ "type": "block-dirty-bitmap-disable"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "name": "bitmapC"
+ },
+ "type": "block-dirty-bitmap-disable"
+ }
+ ]
+ }
+}
+{
+ "return": {}
+}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "count": 393216,
+ "granularity": 65536,
+ "name": "bitmapC",
+ "status": "disabled"
+ },
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapB",
+ "status": "disabled"
+ },
+ {
+ "count": 458752,
+ "granularity": 65536,
+ "name": "bitmapA",
+ "status": "disabled"
+ }
+ ]
+ }
+}
+
+--- Submitting & Aborting Merge Transaction ---
+
+{
+ "execute": "transaction",
+ "arguments": {
+ "actions": [
+ {
+ "data": {
+ "node": "drive0",
+ "disabled": true,
+ "name": "bitmapD",
+ "granularity": 65536
+ },
+ "type": "block-dirty-bitmap-add"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "target": "bitmapD",
+ "bitmaps": [
+ "bitmapB",
+ "bitmapC"
+ ]
+ },
+ "type": "block-dirty-bitmap-merge"
+ },
+ {
+ "data": {},
+ "type": "abort"
+ }
+ ]
+ }
+}
+{
+ "error": {
+ "class": "GenericError",
+ "desc": "Transaction aborted using Abort action"
+ }
+}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "count": 393216,
+ "granularity": 65536,
+ "name": "bitmapC",
+ "status": "disabled"
+ },
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapB",
+ "status": "disabled"
+ },
+ {
+ "count": 458752,
+ "granularity": 65536,
+ "name": "bitmapA",
+ "status": "disabled"
+ }
+ ]
+ }
+}
+
+--- Creating D as a merge of B & C ---
+
+{
+ "execute": "transaction",
+ "arguments": {
+ "actions": [
+ {
+ "data": {
+ "node": "drive0",
+ "disabled": true,
+ "name": "bitmapD",
+ "granularity": 65536
+ },
+ "type": "block-dirty-bitmap-add"
+ },
+ {
+ "data": {
+ "node": "drive0",
+ "target": "bitmapD",
+ "bitmaps": [
+ "bitmapB",
+ "bitmapC"
+ ]
+ },
+ "type": "block-dirty-bitmap-merge"
+ }
+ ]
+ }
+}
+{
+ "return": {}
+}
+{
+ "bitmaps": {
+ "drive0": [
+ {
+ "count": 458752,
+ "granularity": 65536,
+ "name": "bitmapD",
+ "status": "disabled"
+ },
+ {
+ "count": 393216,
+ "granularity": 65536,
+ "name": "bitmapC",
+ "status": "disabled"
+ },
+ {
+ "count": 262144,
+ "granularity": 65536,
+ "name": "bitmapB",
+ "status": "disabled"
+ },
+ {
+ "count": 458752,
+ "granularity": 65536,
+ "name": "bitmapA",
+ "status": "disabled"
+ }
+ ]
+ }
+}
+
+--- Removing bitmaps A, B, C, and D ---
+
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapA", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapB", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapC", "node": "drive0"}}
+{"return": {}}
+{"execute": "block-dirty-bitmap-remove", "arguments": {"name": "bitmapD", "node": "drive0"}}
+{"return": {}}
+
+--- Final Query ---
+
+{
+ "bitmaps": {
+ "drive0": []
+ }
+}
+
+--- Done ---
+
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 61a6d98ebd..f6b245917a 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -233,3 +233,4 @@
233 auto quick
234 auto quick migration
235 auto quick
+236 auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index d537538ba0..cbedfaf1df 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -30,6 +30,7 @@ import signal
import logging
import atexit
import io
+from collections import OrderedDict
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts'))
import qtest
@@ -63,7 +64,7 @@ socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper')
debug = False
luks_default_secret_object = 'secret,id=keysec0,data=' + \
- os.environ['IMGKEYSECRET']
+ os.environ.get('IMGKEYSECRET', '')
luks_default_key_secret_opt = 'key-secret=keysec0'
@@ -75,6 +76,16 @@ def qemu_img(*args):
sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
return exitcode
+def ordered_kwargs(kwargs):
+ # kwargs prior to 3.6 are not ordered, so:
+ od = OrderedDict()
+ for k, v in sorted(kwargs.items()):
+ if isinstance(v, dict):
+ od[k] = ordered_kwargs(v)
+ else:
+ od[k] = v
+ return od
+
def qemu_img_create(*args):
args = list(args)
@@ -235,10 +246,36 @@ def filter_qmp_event(event):
event['timestamp']['microseconds'] = 'USECS'
return event
+def filter_qmp(qmsg, filter_fn):
+ '''Given a string filter, filter a QMP object's values.
+ filter_fn takes a (key, value) pair.'''
+ # Iterate through either lists or dicts;
+ if isinstance(qmsg, list):
+ items = enumerate(qmsg)
+ else:
+ items = qmsg.items()
+
+ for k, v in items:
+ if isinstance(v, list) or isinstance(v, dict):
+ qmsg[k] = filter_qmp(v, filter_fn)
+ else:
+ qmsg[k] = filter_fn(k, v)
+ return qmsg
+
def filter_testfiles(msg):
prefix = os.path.join(test_dir, "%s-" % (os.getpid()))
return msg.replace(prefix, 'TEST_DIR/PID-')
+def filter_qmp_testfiles(qmsg):
+ def _filter(key, value):
+ if key == 'filename' or key == 'backing-file':
+ return filter_testfiles(value)
+ return value
+ return filter_qmp(qmsg, _filter)
+
+def filter_generated_node_ids(msg):
+ return re.sub("#block[0-9]+", "NODE_NAME", msg)
+
def filter_img_info(output, filename):
lines = []
for line in output.split('\n'):
@@ -251,11 +288,18 @@ def filter_img_info(output, filename):
lines.append(line)
return '\n'.join(lines)
-def log(msg, filters=[]):
+def log(msg, filters=[], indent=None):
+ '''Logs either a string message or a JSON serializable message (like QMP).
+ If indent is provided, JSON serializable messages are pretty-printed.'''
for flt in filters:
msg = flt(msg)
- if type(msg) is dict or type(msg) is list:
- print(json.dumps(msg, sort_keys=True))
+ if isinstance(msg, dict) or isinstance(msg, list):
+ # Python < 3.4 needs to know not to add whitespace when pretty-printing:
+ separators = (', ', ': ') if indent is None else (',', ': ')
+ # Don't sort if it's already sorted
+ do_sort = not isinstance(msg, OrderedDict)
+ print(json.dumps(msg, sort_keys=do_sort,
+ indent=indent, separators=separators))
else:
print(msg)
@@ -444,12 +488,14 @@ class VM(qtest.QEMUQtestMachine):
result.append(filter_qmp_event(ev))
return result
- def qmp_log(self, cmd, filters=[filter_testfiles], **kwargs):
- logmsg = '{"execute": "%s", "arguments": %s}' % \
- (cmd, json.dumps(kwargs, sort_keys=True))
- log(logmsg, filters)
+ def qmp_log(self, cmd, filters=[], indent=None, **kwargs):
+ full_cmd = OrderedDict((
+ ("execute", cmd),
+ ("arguments", ordered_kwargs(kwargs))
+ ))
+ log(full_cmd, filters, indent=indent)
result = self.qmp(cmd, **kwargs)
- log(json.dumps(result, sort_keys=True), filters)
+ log(result, filters, indent=indent)
return result
def run_job(self, job, auto_finalize=True, auto_dismiss=False):
diff --git a/tests/qht-bench.c b/tests/qht-bench.c
index 2089e2bed1..e3b512f26f 100644
--- a/tests/qht-bench.c
+++ b/tests/qht-bench.c
@@ -9,7 +9,7 @@
#include "qemu/atomic.h"
#include "qemu/qht.h"
#include "qemu/rcu.h"
-#include "exec/tb-hash-xx.h"
+#include "qemu/xxhash.h"
struct thread_stats {
size_t rd;
@@ -72,6 +72,7 @@ static const char commands_string[] =
" -n = number of threads\n"
"\n"
" -o = offset at which keys start\n"
+ " -p = precompute hashes\n"
"\n"
" -g = set -s,-k,-K,-l,-r to the same value\n"
" -s = initial size hint\n"
@@ -104,7 +105,7 @@ static bool is_equal(const void *ap, const void *bp)
static uint32_t h(unsigned long v)
{
- return tb_hash_func7(v, 0, 0, 0, 0);
+ return qemu_xxhash2(v);
}
static uint32_t hval(unsigned long v)
@@ -397,16 +398,14 @@ static void pr_stats(void)
static void run_test(void)
{
- unsigned int remaining;
int i;
while (atomic_read(&n_ready_threads) != n_rw_threads + n_rz_threads) {
cpu_relax();
}
+
atomic_set(&test_start, true);
- do {
- remaining = sleep(duration);
- } while (remaining);
+ g_usleep(duration * G_USEC_PER_SEC);
atomic_set(&test_stop, true);
for (i = 0; i < n_rw_threads; i++) {
diff --git a/tests/qmp-test.c b/tests/qmp-test.c
index 7517be4654..48a4fa791a 100644
--- a/tests/qmp-test.c
+++ b/tests/qmp-test.c
@@ -108,7 +108,7 @@ static void test_qmp_protocol(void)
QList *capabilities;
QTestState *qts;
- qts = qtest_init_without_qmp_handshake(false, common_args);
+ qts = qtest_init_without_qmp_handshake(common_args);
/* Test greeting */
resp = qtest_qmp_receive(qts);
@@ -116,7 +116,7 @@ static void test_qmp_protocol(void)
g_assert(q);
test_version(qdict_get(q, "version"));
capabilities = qdict_get_qlist(q, "capabilities");
- g_assert(capabilities && qlist_empty(capabilities));
+ g_assert(capabilities);
qobject_unref(resp);
/* Test valid command before handshake */
@@ -219,7 +219,7 @@ static void test_qmp_oob(void)
QList *capabilities;
QString *qstr;
- qts = qtest_init_without_qmp_handshake(true, common_args);
+ qts = qtest_init_without_qmp_handshake(common_args);
/* Check the greeting message. */
resp = qtest_qmp_receive(qts);
diff --git a/tests/tcg/alpha/test-cond.c b/tests/tcg/alpha/test-cond.c
index e625313b3e..3e11c4c105 100644
--- a/tests/tcg/alpha/test-cond.c
+++ b/tests/tcg/alpha/test-cond.c
@@ -6,7 +6,7 @@
int test_##N (long a) \
{ \
int res = 1; \
- \
+ \
asm ("cmov"#N" %1,$31,%0" \
: "+r" (res) : "r" (a)); \
return !res; \
@@ -18,7 +18,7 @@ int test_##N (long a) \
int test_##N (long a) \
{ \
int res = 1; \
- \
+ \
asm ("b"#N" %1,1f\n\t" \
"addq $31,$31,%0\n\t" \
"1: unop\n" \
diff --git a/tests/tcg/arm/hello-arm.c b/tests/tcg/arm/hello-arm.c
index e0daa7ad98..e33edf949f 100644
--- a/tests/tcg/arm/hello-arm.c
+++ b/tests/tcg/arm/hello-arm.c
@@ -11,7 +11,7 @@
#define __syscall_return(type, res) \
do { \
- return (type) (res); \
+ return (type) (res); \
} while (0)
#define _syscall0(type,name) \
@@ -33,7 +33,7 @@ type name(type1 arg1) { \
"mov %0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)) \
- : "r0","lr"); \
+ : "r0","lr"); \
__syscall_return(type,__res); \
}
@@ -47,7 +47,7 @@ type name(type1 arg1,type2 arg2) { \
"mov\t%0,r0" \
: "=r" (__res) \
: "r" ((long)(arg1)),"r" ((long)(arg2)) \
- : "r0","r1","lr"); \
+ : "r0","r1","lr"); \
__syscall_return(type,__res); \
}
@@ -78,9 +78,9 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
"mov\tr3,%4\n\t" \
__syscall(name) \
"mov\t%0,r0" \
- : "=r" (__res) \
- : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
- : "r0","r1","r2","r3","lr"); \
+ : "=r" (__res) \
+ : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \
+ : "r0","r1","r2","r3","lr"); \
__syscall_return(type,__res); \
}
@@ -96,10 +96,10 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
"mov\tr4,%5\n\t" \
__syscall(name) \
"mov\t%0,r0" \
- : "=r" (__res) \
- : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
- "r" ((long)(arg5)) \
- : "r0","r1","r2","r3","r4","lr"); \
+ : "=r" (__res) \
+ : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \
+ "r" ((long)(arg5)) \
+ : "r0","r1","r2","r3","r4","lr"); \
__syscall_return(type,__res); \
}
diff --git a/tests/tcg/cris/check_glibc_kernelversion.c b/tests/tcg/cris/check_glibc_kernelversion.c
index 07448722c0..7aada89911 100644
--- a/tests/tcg/cris/check_glibc_kernelversion.c
+++ b/tests/tcg/cris/check_glibc_kernelversion.c
@@ -109,8 +109,8 @@ int main(void)
if (parts < 3)
version <<= 8 * (3 - parts);
- if (version < __LINUX_KERNEL_VERSION)
- err();
- pass();
- exit(0);
+ if (version < __LINUX_KERNEL_VERSION)
+ err();
+ pass();
+ exit(0);
}
diff --git a/tests/tcg/cris/check_mmap3.c b/tests/tcg/cris/check_mmap3.c
index 34401fa0c9..cb890ef120 100644
--- a/tests/tcg/cris/check_mmap3.c
+++ b/tests/tcg/cris/check_mmap3.c
@@ -17,7 +17,7 @@ int main (int argc, char *argv[])
/* Check that we can map a non-multiple of a page and still get a full page. */
a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (a == NULL || a == (unsigned char *) -1)
abort ();
diff --git a/tests/tcg/cris/check_openpf1.c b/tests/tcg/cris/check_openpf1.c
index fdcf4c5c3f..251d26eec2 100644
--- a/tests/tcg/cris/check_openpf1.c
+++ b/tests/tcg/cris/check_openpf1.c
@@ -19,7 +19,7 @@ int main (int argc, char *argv[])
{
fnam = malloc (strlen (argv[0]) + 2);
if (fnam == NULL)
- abort ();
+ abort ();
strcpy (fnam, "/");
strcat (fnam, argv[0]);
}
diff --git a/tests/tcg/cris/check_settls1.c b/tests/tcg/cris/check_settls1.c
index 69d202652a..3abc3a9ea8 100644
--- a/tests/tcg/cris/check_settls1.c
+++ b/tests/tcg/cris/check_settls1.c
@@ -35,7 +35,7 @@ int main (void)
syscall (SYS_set_thread_area, old_tp);
if (tp != 0xeddeed00) {
- * (volatile int *) 0 = 0;
+ * (volatile int *) 0 = 0;
perror ("tls2");
abort ();
}
diff --git a/tests/tcg/i386/hello-i386.c b/tests/tcg/i386/hello-i386.c
index cfeb24b2f5..59196dd0b7 100644
--- a/tests/tcg/i386/hello-i386.c
+++ b/tests/tcg/i386/hello-i386.c
@@ -4,19 +4,19 @@ static inline void exit(int status)
{
int __res;
__asm__ volatile ("movl %%ecx,%%ebx\n"\
- "int $0x80" \
- : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
+ "int $0x80" \
+ : "=a" (__res) : "0" (__NR_exit),"c" ((long)(status)));
}
static inline int write(int fd, const char * buf, int len)
{
int status;
__asm__ volatile ("pushl %%ebx\n"\
- "movl %%esi,%%ebx\n"\
- "int $0x80\n" \
- "popl %%ebx\n"\
- : "=a" (status) \
- : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
+ "movl %%esi,%%ebx\n"\
+ "int $0x80\n" \
+ "popl %%ebx\n"\
+ : "=a" (status) \
+ : "0" (__NR_write),"S" ((long)(fd)),"c" ((long)(buf)),"d" ((long)(len)));
return status;
}
diff --git a/tests/tcg/i386/test-i386.c b/tests/tcg/i386/test-i386.c
index a29b41e764..18d5609665 100644
--- a/tests/tcg/i386/test-i386.c
+++ b/tests/tcg/i386/test-i386.c
@@ -1137,7 +1137,7 @@ void test_xchg(void)
TEST_XCHG(xchgb, "b", "+q");
#if defined(__x86_64__)
- TEST_XCHG(xchgq, "", "=m");
+ TEST_XCHG(xchgq, "", "+m");
#endif
TEST_XCHG(xchgl, "k", "+m");
TEST_XCHG(xchgw, "w", "+m");
diff --git a/tests/tcg/mips/hello-mips.c b/tests/tcg/mips/hello-mips.c
index f8256730dd..c7052fdf2e 100644
--- a/tests/tcg/mips/hello-mips.c
+++ b/tests/tcg/mips/hello-mips.c
@@ -24,9 +24,9 @@ static inline void exit1(int status)
" syscall \n"
" .set pop "
:
- : "i" (__NR_exit), "r" (__a0)
- : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
- "memory");
+ : "i" (__NR_exit), "r" (__a0)
+ : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
+ "memory");
}
static inline int write(int fd, const char *buf, int len)
@@ -46,8 +46,8 @@ static inline int write(int fd, const char *buf, int len)
" .set pop "
: "=r" (__v0), "=r" (__a3)
: "i" (__NR_write), "r" (__a0), "r" (__a1), "r" (__a2)
- : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
- "memory");
+ : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
+ "memory");
/* if (__a3 == 0) */
return (int) __v0;
diff --git a/tests/tcg/mips/mipsr5900/Makefile b/tests/tcg/mips/mipsr5900/Makefile
index a1c388bc3c..27ee5d5f54 100644
--- a/tests/tcg/mips/mipsr5900/Makefile
+++ b/tests/tcg/mips/mipsr5900/Makefile
@@ -10,6 +10,8 @@ CFLAGS = -Wall -mabi=32 -march=r5900 -static
TESTCASES = div1.tst
TESTCASES += divu1.tst
+TESTCASES += madd.tst
+TESTCASES += maddu.tst
TESTCASES += mflohi1.tst
TESTCASES += mtlohi1.tst
TESTCASES += mult.tst
diff --git a/tests/tcg/mips/mipsr5900/madd.c b/tests/tcg/mips/mipsr5900/madd.c
new file mode 100644
index 0000000000..f6f215e1c3
--- /dev/null
+++ b/tests/tcg/mips/mipsr5900/madd.c
@@ -0,0 +1,78 @@
+/*
+ * Test R5900-specific three-operand MADD and MADD1.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <assert.h>
+
+int64_t madd(int64_t a, int32_t rs, int32_t rt)
+{
+ int32_t lo = a;
+ int32_t hi = a >> 32;
+ int32_t rd;
+ int64_t r;
+
+ __asm__ __volatile__ (
+ " mtlo %5\n"
+ " mthi %6\n"
+ " madd %0, %3, %4\n"
+ " mflo %1\n"
+ " mfhi %2\n"
+ : "=r" (rd), "=r" (lo), "=r" (hi)
+ : "r" (rs), "r" (rt), "r" (lo), "r" (hi));
+ r = ((int64_t)hi << 32) | (uint32_t)lo;
+
+ assert(a + (int64_t)rs * rt == r);
+ assert(rd == lo);
+
+ return r;
+}
+
+int64_t madd1(int64_t a, int32_t rs, int32_t rt)
+{
+ int32_t lo = a;
+ int32_t hi = a >> 32;
+ int32_t rd;
+ int64_t r;
+
+ __asm__ __volatile__ (
+ " mtlo1 %5\n"
+ " mthi1 %6\n"
+ " madd1 %0, %3, %4\n"
+ " mflo1 %1\n"
+ " mfhi1 %2\n"
+ : "=r" (rd), "=r" (lo), "=r" (hi)
+ : "r" (rs), "r" (rt), "r" (lo), "r" (hi));
+ r = ((int64_t)hi << 32) | (uint32_t)lo;
+
+ assert(a + (int64_t)rs * rt == r);
+ assert(rd == lo);
+
+ return r;
+}
+
+static int64_t madd_variants(int64_t a, int32_t rs, int32_t rt)
+{
+ int64_t rd = madd(a, rs, rt);
+ int64_t rd1 = madd1(a, rs, rt);
+
+ assert(rd == rd1);
+
+ return rd;
+}
+
+static void verify_madd(int64_t a, int32_t rs, int32_t rt, int64_t expected)
+{
+ assert(madd_variants(a, rs, rt) == expected);
+ assert(madd_variants(a, -rs, rt) == a + a - expected);
+ assert(madd_variants(a, rs, -rt) == a + a - expected);
+ assert(madd_variants(a, -rs, -rt) == expected);
+}
+
+int main()
+{
+ verify_madd(13, 17, 19, 336);
+
+ return 0;
+}
diff --git a/tests/tcg/mips/mipsr5900/maddu.c b/tests/tcg/mips/mipsr5900/maddu.c
new file mode 100644
index 0000000000..30936fb2b4
--- /dev/null
+++ b/tests/tcg/mips/mipsr5900/maddu.c
@@ -0,0 +1,70 @@
+/*
+ * Test R5900-specific three-operand MADDU and MADDU1.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <assert.h>
+
+uint64_t maddu(uint64_t a, uint32_t rs, uint32_t rt)
+{
+ uint32_t lo = a;
+ uint32_t hi = a >> 32;
+ uint32_t rd;
+ uint64_t r;
+
+ __asm__ __volatile__ (
+ " mtlo %5\n"
+ " mthi %6\n"
+ " maddu %0, %3, %4\n"
+ " mflo %1\n"
+ " mfhi %2\n"
+ : "=r" (rd), "=r" (lo), "=r" (hi)
+ : "r" (rs), "r" (rt), "r" (lo), "r" (hi));
+ r = ((uint64_t)hi << 32) | (uint32_t)lo;
+
+ assert(a + (uint64_t)rs * rt == r);
+ assert(rd == lo);
+
+ return r;
+}
+
+uint64_t maddu1(uint64_t a, uint32_t rs, uint32_t rt)
+{
+ uint32_t lo = a;
+ uint32_t hi = a >> 32;
+ uint32_t rd;
+ uint64_t r;
+
+ __asm__ __volatile__ (
+ " mtlo1 %5\n"
+ " mthi1 %6\n"
+ " maddu1 %0, %3, %4\n"
+ " mflo1 %1\n"
+ " mfhi1 %2\n"
+ : "=r" (rd), "=r" (lo), "=r" (hi)
+ : "r" (rs), "r" (rt), "r" (lo), "r" (hi));
+ r = ((uint64_t)hi << 32) | (uint32_t)lo;
+
+ assert(a + (uint64_t)rs * rt == r);
+ assert(rd == lo);
+
+ return r;
+}
+
+static int64_t maddu_variants(int64_t a, int32_t rs, int32_t rt)
+{
+ int64_t rd = maddu(a, rs, rt);
+ int64_t rd1 = maddu1(a, rs, rt);
+
+ assert(rd == rd1);
+
+ return rd;
+}
+
+int main()
+{
+ assert(maddu_variants(13, 17, 19) == 336);
+
+ return 0;
+}
diff --git a/tests/tcg/multiarch/sha1.c b/tests/tcg/multiarch/sha1.c
index 93b7c8e808..87bfbcdf52 100644
--- a/tests/tcg/multiarch/sha1.c
+++ b/tests/tcg/multiarch/sha1.c
@@ -152,7 +152,7 @@ uint32_t j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
- context->count[1]++;
+ context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
@@ -186,11 +186,11 @@ unsigned char c;
for (i = 0; i < 2; i++)
{
- uint32_t t = context->count[i];
- int j;
+ uint32_t t = context->count[i];
+ int j;
- for (j = 0; j < 4; t >>= 8, j++)
- *--fcp = (unsigned char) t;
+ for (j = 0; j < 4; t >>= 8, j++)
+ *--fcp = (unsigned char) t;
}
#else
for (i = 0; i < 8; i++) {
@@ -201,7 +201,7 @@ unsigned char c;
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
- c = 0000;
+ c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
diff --git a/tests/test-arm-mptimer.c b/tests/test-arm-mptimer.c
index cb8f2df914..156a39f50d 100644
--- a/tests/test-arm-mptimer.c
+++ b/tests/test-arm-mptimer.c
@@ -991,10 +991,25 @@ static void test_timer_zero_load_nonscaled_periodic_to_prescaled_oneshot(void)
g_assert_cmpuint(timer_get_and_clr_int_sts(), ==, 0);
}
+/*
+ * Add a qtest test that comes in two versions: one with
+ * a timer scaler setting, and one with the timer nonscaled.
+ */
+static void add_scaler_test(const char *str, bool scale,
+ void (*fn)(const void *))
+{
+ char *name;
+ int *scaler = scale ? &scaled : &nonscaled;
+
+ name = g_strdup_printf("%s=%d", str, *scaler);
+ qtest_add_data_func(name, scaler, fn);
+ g_free(name);
+}
+
int main(int argc, char **argv)
{
- int *scaler = &nonscaled;
int ret;
+ int scale;
g_test_init(&argc, &argv, NULL);
@@ -1012,89 +1027,59 @@ int main(int argc, char **argv)
qtest_add_func("mptimer/prescaler", test_timer_prescaler);
qtest_add_func("mptimer/prescaler_on_the_fly", test_timer_prescaler_on_the_fly);
-tests_with_prescaler_arg:
- qtest_add_data_func(
- g_strdup_printf("mptimer/oneshot scaler=%d", *scaler),
- scaler, test_timer_oneshot);
- qtest_add_data_func(
- g_strdup_printf("mptimer/pause scaler=%d", *scaler),
- scaler, test_timer_pause);
- qtest_add_data_func(
- g_strdup_printf("mptimer/reload scaler=%d", *scaler),
- scaler, test_timer_reload);
- qtest_add_data_func(
- g_strdup_printf("mptimer/periodic scaler=%d", *scaler),
- scaler, test_timer_periodic);
- qtest_add_data_func(
- g_strdup_printf("mptimer/oneshot_to_periodic scaler=%d", *scaler),
- scaler, test_timer_oneshot_to_periodic);
- qtest_add_data_func(
- g_strdup_printf("mptimer/periodic_to_oneshot scaler=%d", *scaler),
- scaler, test_timer_periodic_to_oneshot);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_oneshot_counter_to_0 scaler=%d", *scaler),
- scaler, test_timer_set_oneshot_counter_to_0);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_periodic_counter_to_0 scaler=%d", *scaler),
- scaler, test_timer_set_periodic_counter_to_0);
- qtest_add_data_func(
- g_strdup_printf("mptimer/noload_oneshot scaler=%d", *scaler),
- scaler, test_timer_noload_oneshot);
- qtest_add_data_func(
- g_strdup_printf("mptimer/noload_periodic scaler=%d", *scaler),
- scaler, test_timer_noload_periodic);
- qtest_add_data_func(
- g_strdup_printf("mptimer/zero_load_oneshot scaler=%d", *scaler),
- scaler, test_timer_zero_load_oneshot);
- qtest_add_data_func(
- g_strdup_printf("mptimer/zero_load_periodic scaler=%d", *scaler),
- scaler, test_timer_zero_load_periodic);
- qtest_add_data_func(
- g_strdup_printf("mptimer/zero_load_oneshot_to_nonzero scaler=%d", *scaler),
- scaler, test_timer_zero_load_oneshot_to_nonzero);
- qtest_add_data_func(
- g_strdup_printf("mptimer/zero_load_periodic_to_nonzero scaler=%d", *scaler),
- scaler, test_timer_zero_load_periodic_to_nonzero);
- qtest_add_data_func(
- g_strdup_printf("mptimer/nonzero_load_oneshot_to_zero scaler=%d", *scaler),
- scaler, test_timer_nonzero_load_oneshot_to_zero);
- qtest_add_data_func(
- g_strdup_printf("mptimer/nonzero_load_periodic_to_zero scaler=%d", *scaler),
- scaler, test_timer_nonzero_load_periodic_to_zero);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_periodic_counter_on_the_fly scaler=%d", *scaler),
- scaler, test_timer_set_periodic_counter_on_the_fly);
- qtest_add_data_func(
- g_strdup_printf("mptimer/enable_and_set_counter scaler=%d", *scaler),
- scaler, test_timer_enable_and_set_counter);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_counter_and_enable scaler=%d", *scaler),
- scaler, test_timer_set_counter_and_enable);
- qtest_add_data_func(
- g_strdup_printf("mptimer/oneshot_with_counter_0_on_start scaler=%d", *scaler),
- scaler, test_timer_oneshot_with_counter_0_on_start);
- qtest_add_data_func(
- g_strdup_printf("mptimer/periodic_with_counter_0_on_start scaler=%d", *scaler),
- scaler, test_timer_periodic_with_counter_0_on_start);
- qtest_add_data_func(
- g_strdup_printf("mptimer/periodic_counter scaler=%d", *scaler),
- scaler, test_periodic_counter);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_counter_periodic_with_zero_load scaler=%d", *scaler),
- scaler, test_timer_set_counter_periodic_with_zero_load);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_oneshot_load_to_0 scaler=%d", *scaler),
- scaler, test_timer_set_oneshot_load_to_0);
- qtest_add_data_func(
- g_strdup_printf("mptimer/set_periodic_load_to_0 scaler=%d", *scaler),
- scaler, test_timer_set_periodic_load_to_0);
- qtest_add_data_func(
- g_strdup_printf("mptimer/zero_load_mode_switch scaler=%d", *scaler),
- scaler, test_timer_zero_load_mode_switch);
-
- if (scaler == &nonscaled) {
- scaler = &scaled;
- goto tests_with_prescaler_arg;
+ for (scale = 0; scale < 2; scale++) {
+ add_scaler_test("mptimer/oneshot scaler",
+ scale, test_timer_oneshot);
+ add_scaler_test("mptimer/pause scaler",
+ scale, test_timer_pause);
+ add_scaler_test("mptimer/reload scaler",
+ scale, test_timer_reload);
+ add_scaler_test("mptimer/periodic scaler",
+ scale, test_timer_periodic);
+ add_scaler_test("mptimer/oneshot_to_periodic scaler",
+ scale, test_timer_oneshot_to_periodic);
+ add_scaler_test("mptimer/periodic_to_oneshot scaler",
+ scale, test_timer_periodic_to_oneshot);
+ add_scaler_test("mptimer/set_oneshot_counter_to_0 scaler",
+ scale, test_timer_set_oneshot_counter_to_0);
+ add_scaler_test("mptimer/set_periodic_counter_to_0 scaler",
+ scale, test_timer_set_periodic_counter_to_0);
+ add_scaler_test("mptimer/noload_oneshot scaler",
+ scale, test_timer_noload_oneshot);
+ add_scaler_test("mptimer/noload_periodic scaler",
+ scale, test_timer_noload_periodic);
+ add_scaler_test("mptimer/zero_load_oneshot scaler",
+ scale, test_timer_zero_load_oneshot);
+ add_scaler_test("mptimer/zero_load_periodic scaler",
+ scale, test_timer_zero_load_periodic);
+ add_scaler_test("mptimer/zero_load_oneshot_to_nonzero scaler",
+ scale, test_timer_zero_load_oneshot_to_nonzero);
+ add_scaler_test("mptimer/zero_load_periodic_to_nonzero scaler",
+ scale, test_timer_zero_load_periodic_to_nonzero);
+ add_scaler_test("mptimer/nonzero_load_oneshot_to_zero scaler",
+ scale, test_timer_nonzero_load_oneshot_to_zero);
+ add_scaler_test("mptimer/nonzero_load_periodic_to_zero scaler",
+ scale, test_timer_nonzero_load_periodic_to_zero);
+ add_scaler_test("mptimer/set_periodic_counter_on_the_fly scaler",
+ scale, test_timer_set_periodic_counter_on_the_fly);
+ add_scaler_test("mptimer/enable_and_set_counter scaler",
+ scale, test_timer_enable_and_set_counter);
+ add_scaler_test("mptimer/set_counter_and_enable scaler",
+ scale, test_timer_set_counter_and_enable);
+ add_scaler_test("mptimer/oneshot_with_counter_0_on_start scaler",
+ scale, test_timer_oneshot_with_counter_0_on_start);
+ add_scaler_test("mptimer/periodic_with_counter_0_on_start scaler",
+ scale, test_timer_periodic_with_counter_0_on_start);
+ add_scaler_test("mptimer/periodic_counter scaler",
+ scale, test_periodic_counter);
+ add_scaler_test("mptimer/set_counter_periodic_with_zero_load scaler",
+ scale, test_timer_set_counter_periodic_with_zero_load);
+ add_scaler_test("mptimer/set_oneshot_load_to_0 scaler",
+ scale, test_timer_set_oneshot_load_to_0);
+ add_scaler_test("mptimer/set_periodic_load_to_0 scaler",
+ scale, test_timer_set_periodic_load_to_0);
+ add_scaler_test("mptimer/zero_load_mode_switch scaler",
+ scale, test_timer_zero_load_mode_switch);
}
qtest_start("-machine vexpress-a9");
diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c
index fae4ffc453..d309d044ef 100644
--- a/tests/test-crypto-block.c
+++ b/tests/test-crypto-block.c
@@ -305,6 +305,7 @@ static void test_block(gconstpointer opaque)
test_block_read_func,
&header,
0,
+ 1,
NULL);
g_assert(blk == NULL);
@@ -313,6 +314,7 @@ static void test_block(gconstpointer opaque)
test_block_read_func,
&header,
QCRYPTO_BLOCK_OPEN_NO_IO,
+ 1,
&error_abort);
g_assert(qcrypto_block_get_cipher(blk) == NULL);
@@ -327,6 +329,7 @@ static void test_block(gconstpointer opaque)
test_block_read_func,
&header,
0,
+ 1,
&error_abort);
g_assert(blk);
diff --git a/tests/test-crypto-pbkdf.c b/tests/test-crypto-pbkdf.c
index d937aff6b2..85ed1f9b33 100644
--- a/tests/test-crypto-pbkdf.c
+++ b/tests/test-crypto-pbkdf.c
@@ -440,6 +440,7 @@ int main(int argc, char **argv)
#else
int main(int argc, char **argv)
{
- return 0;
+ g_test_init(&argc, &argv, NULL);
+ return g_test_run();
}
#endif
diff --git a/tests/test-cutils.c b/tests/test-cutils.c
index d85c3e0f6d..1aa8351520 100644
--- a/tests/test-cutils.c
+++ b/tests/test-cutils.c
@@ -1950,7 +1950,7 @@ static void test_qemu_strtou64_full_max(void)
static void test_qemu_strtosz_simple(void)
{
const char *str;
- char *endptr = NULL;
+ const char *endptr;
int err;
uint64_t res = 0xbaadf00d;
@@ -2017,7 +2017,7 @@ static void test_qemu_strtosz_units(void)
const char *p = "1P";
const char *e = "1E";
int err;
- char *endptr = NULL;
+ const char *endptr;
uint64_t res = 0xbaadf00d;
/* default is M */
@@ -2066,7 +2066,7 @@ static void test_qemu_strtosz_float(void)
{
const char *str = "12.345M";
int err;
- char *endptr = NULL;
+ const char *endptr;
uint64_t res = 0xbaadf00d;
err = qemu_strtosz(str, &endptr, &res);
@@ -2078,7 +2078,7 @@ static void test_qemu_strtosz_float(void)
static void test_qemu_strtosz_invalid(void)
{
const char *str;
- char *endptr = NULL;
+ const char *endptr;
int err;
uint64_t res = 0xbaadf00d;
@@ -2096,12 +2096,22 @@ static void test_qemu_strtosz_invalid(void)
err = qemu_strtosz(str, &endptr, &res);
g_assert_cmpint(err, ==, -EINVAL);
g_assert(endptr == str);
+
+ str = "inf";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
+
+ str = "NaN";
+ err = qemu_strtosz(str, &endptr, &res);
+ g_assert_cmpint(err, ==, -EINVAL);
+ g_assert(endptr == str);
}
static void test_qemu_strtosz_trailing(void)
{
const char *str;
- char *endptr = NULL;
+ const char *endptr;
int err;
uint64_t res = 0xbaadf00d;
@@ -2126,7 +2136,7 @@ static void test_qemu_strtosz_trailing(void)
static void test_qemu_strtosz_erange(void)
{
const char *str;
- char *endptr = NULL;
+ const char *endptr;
int err;
uint64_t res = 0xbaadf00d;
@@ -2160,7 +2170,7 @@ static void test_qemu_strtosz_metric(void)
{
const char *str = "12345k";
int err;
- char *endptr = NULL;
+ const char *endptr;
uint64_t res = 0xbaadf00d;
err = qemu_strtosz_metric(str, &endptr, &res);
diff --git a/tests/test-filter-mirror.c b/tests/test-filter-mirror.c
index d15917e2cf..7ab2aed8a0 100644
--- a/tests/test-filter-mirror.c
+++ b/tests/test-filter-mirror.c
@@ -17,7 +17,7 @@
#include "qemu/main-loop.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
static void test_mirror(void)
{
@@ -29,6 +29,7 @@ static void test_mirror(void)
uint32_t size = sizeof(send_buf);
size = htonl(size);
const char *devstr = "e1000";
+ QTestState *qts;
if (g_str_equal(qtest_get_arch(), "s390x")) {
devstr = "virtio-net-ccw";
@@ -40,7 +41,7 @@ static void test_mirror(void)
ret = mkstemp(sock_path);
g_assert_cmpint(ret, !=, -1);
- global_qtest = qtest_initf(
+ qts = qtest_initf(
"-netdev socket,id=qtest-bn0,fd=%d "
"-device %s,netdev=qtest-bn0,id=qtest-e0 "
"-chardev socket,id=mirror0,path=%s,server,nowait "
@@ -61,7 +62,7 @@ static void test_mirror(void)
};
/* send a qmp command to guarantee that 'connected' is setting to true. */
- qmp_discard_response("{ 'execute' : 'query-status'}");
+ qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
ret = iov_send(send_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf));
g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
close(send_sock[0]);
@@ -78,6 +79,7 @@ static void test_mirror(void)
g_free(recv_buf);
close(recv_sock);
unlink(sock_path);
+ qtest_quit(qts);
}
int main(int argc, char **argv)
@@ -88,7 +90,6 @@ int main(int argc, char **argv)
qtest_add_func("/netfilter/mirror", test_mirror);
ret = g_test_run();
- qtest_end();
return ret;
}
diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c
index 615ff5cb9f..9ca9feabf8 100644
--- a/tests/test-filter-redirector.c
+++ b/tests/test-filter-redirector.c
@@ -59,7 +59,7 @@
#include "qemu/main-loop.h"
/* TODO actually test the results and get rid of this */
-#define qmp_discard_response(...) qobject_unref(qmp(__VA_ARGS__))
+#define qmp_discard_response(qs, ...) qobject_unref(qtest_qmp(qs, __VA_ARGS__))
static const char *get_devstr(void)
{
@@ -81,6 +81,7 @@ static void test_redirector_tx(void)
char *recv_buf;
uint32_t size = sizeof(send_buf);
size = htonl(size);
+ QTestState *qts;
ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
g_assert_cmpint(ret, !=, -1);
@@ -90,7 +91,7 @@ static void test_redirector_tx(void)
ret = mkstemp(sock_path1);
g_assert_cmpint(ret, !=, -1);
- global_qtest = qtest_initf(
+ qts = qtest_initf(
"-netdev socket,id=qtest-bn0,fd=%d "
"-device %s,netdev=qtest-bn0,id=qtest-e0 "
"-chardev socket,id=redirector0,path=%s,server,nowait "
@@ -108,7 +109,7 @@ static void test_redirector_tx(void)
g_assert_cmpint(recv_sock, !=, -1);
/* send a qmp command to guarantee that 'connected' is setting to true. */
- qmp_discard_response("{ 'execute' : 'query-status'}");
+ qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
struct iovec iov[] = {
{
@@ -137,7 +138,7 @@ static void test_redirector_tx(void)
close(recv_sock);
unlink(sock_path0);
unlink(sock_path1);
- qtest_end();
+ qtest_quit(qts);
}
static void test_redirector_rx(void)
@@ -150,6 +151,7 @@ static void test_redirector_rx(void)
char *recv_buf;
uint32_t size = sizeof(send_buf);
size = htonl(size);
+ QTestState *qts;
ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock);
g_assert_cmpint(ret, !=, -1);
@@ -159,7 +161,7 @@ static void test_redirector_rx(void)
ret = mkstemp(sock_path1);
g_assert_cmpint(ret, !=, -1);
- global_qtest = qtest_initf(
+ qts = qtest_initf(
"-netdev socket,id=qtest-bn0,fd=%d "
"-device %s,netdev=qtest-bn0,id=qtest-e0 "
"-chardev socket,id=redirector0,path=%s,server,nowait "
@@ -186,7 +188,7 @@ static void test_redirector_rx(void)
send_sock = unix_connect(sock_path1, NULL);
g_assert_cmpint(send_sock, !=, -1);
/* send a qmp command to guarantee that 'connected' is setting to true. */
- qmp_discard_response("{ 'execute' : 'query-status'}");
+ qmp_discard_response(qts, "{ 'execute' : 'query-status'}");
ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf));
g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size));
@@ -204,7 +206,7 @@ static void test_redirector_rx(void)
g_free(recv_buf);
unlink(sock_path0);
unlink(sock_path1);
- qtest_end();
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index 5e67ac1d3a..592d8219db 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -30,18 +30,6 @@ typedef struct TestHBitmapData {
} TestHBitmapData;
-static int64_t check_hbitmap_iter_next(HBitmapIter *hbi)
-{
- int next0, next1;
-
- next0 = hbitmap_iter_next(hbi, false);
- next1 = hbitmap_iter_next(hbi, true);
-
- g_assert_cmpint(next0, ==, next1);
-
- return next0;
-}
-
/* Check that the HBitmap and the shadow bitmap contain the same data,
* ignoring the same "first" bits.
*/
@@ -58,7 +46,7 @@ static void hbitmap_test_check(TestHBitmapData *data,
i = first;
for (;;) {
- next = check_hbitmap_iter_next(&hbi);
+ next = hbitmap_iter_next(&hbi);
if (next < 0) {
next = data->size;
}
@@ -447,25 +435,25 @@ static void test_hbitmap_iter_granularity(TestHBitmapData *data,
/* Note that hbitmap_test_check has to be invoked manually in this test. */
hbitmap_test_init(data, 131072 << 7, 7);
hbitmap_iter_init(&hbi, data->hb, 0);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8);
hbitmap_iter_init(&hbi, data->hb, 0);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7);
- g_assert_cmpint(hbitmap_iter_next(&hbi, true), <, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
hbitmap_test_set(data, (131072 << 7) - 8, 8);
hbitmap_iter_init(&hbi, data->hb, 0);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), ==, 131071 << 7);
- g_assert_cmpint(check_hbitmap_iter_next(&hbi), <, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
}
static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff)
@@ -905,7 +893,7 @@ static void test_hbitmap_serialize_zeroes(TestHBitmapData *data,
for (i = 0; i < num_positions; i++) {
hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true);
hbitmap_iter_init(&iter, data->hb, 0);
- next = check_hbitmap_iter_next(&iter);
+ next = hbitmap_iter_next(&iter);
if (i == num_positions - 1) {
g_assert_cmpint(next, ==, -1);
} else {
@@ -931,37 +919,55 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data,
hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1);
- check_hbitmap_iter_next(&hbi);
+ hbitmap_iter_next(&hbi);
hbitmap_reset_all(data->hb);
- check_hbitmap_iter_next(&hbi);
+ hbitmap_iter_next(&hbi);
}
-static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start)
+static void test_hbitmap_next_zero_check_range(TestHBitmapData *data,
+ uint64_t start,
+ uint64_t count)
{
- int64_t ret1 = hbitmap_next_zero(data->hb, start);
+ int64_t ret1 = hbitmap_next_zero(data->hb, start, count);
int64_t ret2 = start;
- for ( ; ret2 < data->size && hbitmap_get(data->hb, ret2); ret2++) {
+ int64_t end = start >= data->size || data->size - start < count ?
+ data->size : start + count;
+
+ for ( ; ret2 < end && hbitmap_get(data->hb, ret2); ret2++) {
;
}
- if (ret2 == data->size) {
+ if (ret2 == end) {
ret2 = -1;
}
g_assert_cmpint(ret1, ==, ret2);
}
+static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start)
+{
+ test_hbitmap_next_zero_check_range(data, start, UINT64_MAX);
+}
+
static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity)
{
hbitmap_test_init(data, L3, granularity);
test_hbitmap_next_zero_check(data, 0);
test_hbitmap_next_zero_check(data, L3 - 1);
+ test_hbitmap_next_zero_check_range(data, 0, 1);
+ test_hbitmap_next_zero_check_range(data, L3 - 1, 1);
hbitmap_set(data->hb, L2, 1);
test_hbitmap_next_zero_check(data, 0);
test_hbitmap_next_zero_check(data, L2 - 1);
test_hbitmap_next_zero_check(data, L2);
test_hbitmap_next_zero_check(data, L2 + 1);
+ test_hbitmap_next_zero_check_range(data, 0, 1);
+ test_hbitmap_next_zero_check_range(data, 0, L2);
+ test_hbitmap_next_zero_check_range(data, L2 - 1, 1);
+ test_hbitmap_next_zero_check_range(data, L2 - 1, 2);
+ test_hbitmap_next_zero_check_range(data, L2, 1);
+ test_hbitmap_next_zero_check_range(data, L2 + 1, 1);
hbitmap_set(data->hb, L2 + 5, L1);
test_hbitmap_next_zero_check(data, 0);
@@ -970,6 +976,10 @@ static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity)
test_hbitmap_next_zero_check(data, L2 + 5);
test_hbitmap_next_zero_check(data, L2 + L1 - 1);
test_hbitmap_next_zero_check(data, L2 + L1);
+ test_hbitmap_next_zero_check_range(data, L2, 6);
+ test_hbitmap_next_zero_check_range(data, L2 + 1, 3);
+ test_hbitmap_next_zero_check_range(data, L2 + 4, L1);
+ test_hbitmap_next_zero_check_range(data, L2 + 5, L1);
hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2);
test_hbitmap_next_zero_check(data, L2 * 2 - L1);
@@ -977,6 +987,8 @@ static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity)
test_hbitmap_next_zero_check(data, L2 * 2 - 1);
test_hbitmap_next_zero_check(data, L2 * 2);
test_hbitmap_next_zero_check(data, L3 - 1);
+ test_hbitmap_next_zero_check_range(data, L2 * 2 - L1, L1 + 1);
+ test_hbitmap_next_zero_check_range(data, L2 * 2, L2);
hbitmap_set(data->hb, 0, L3);
test_hbitmap_next_zero_check(data, 0);
@@ -992,6 +1004,106 @@ static void test_hbitmap_next_zero_4(TestHBitmapData *data, const void *unused)
test_hbitmap_next_zero_do(data, 4);
}
+static void test_hbitmap_next_dirty_area_check(TestHBitmapData *data,
+ uint64_t offset,
+ uint64_t count)
+{
+ uint64_t off1, off2;
+ uint64_t len1 = 0, len2;
+ bool ret1, ret2;
+ int64_t end;
+
+ off1 = offset;
+ len1 = count;
+ ret1 = hbitmap_next_dirty_area(data->hb, &off1, &len1);
+
+ end = offset > data->size || data->size - offset < count ? data->size :
+ offset + count;
+
+ for (off2 = offset; off2 < end && !hbitmap_get(data->hb, off2); off2++) {
+ ;
+ }
+
+ for (len2 = 1; off2 + len2 < end && hbitmap_get(data->hb, off2 + len2);
+ len2++) {
+ ;
+ }
+
+ ret2 = off2 < end;
+ if (!ret2) {
+ /* leave unchanged */
+ off2 = offset;
+ len2 = count;
+ }
+
+ g_assert_cmpint(ret1, ==, ret2);
+ g_assert_cmpint(off1, ==, off2);
+ g_assert_cmpint(len1, ==, len2);
+}
+
+static void test_hbitmap_next_dirty_area_do(TestHBitmapData *data,
+ int granularity)
+{
+ hbitmap_test_init(data, L3, granularity);
+ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, 0, 1);
+ test_hbitmap_next_dirty_area_check(data, L3 - 1, 1);
+
+ hbitmap_set(data->hb, L2, 1);
+ test_hbitmap_next_dirty_area_check(data, 0, 1);
+ test_hbitmap_next_dirty_area_check(data, 0, L2);
+ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 - 1, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 - 1, 1);
+ test_hbitmap_next_dirty_area_check(data, L2 - 1, 2);
+ test_hbitmap_next_dirty_area_check(data, L2 - 1, 3);
+ test_hbitmap_next_dirty_area_check(data, L2, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2, 1);
+ test_hbitmap_next_dirty_area_check(data, L2 + 1, 1);
+
+ hbitmap_set(data->hb, L2 + 5, L1);
+ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 - 2, 8);
+ test_hbitmap_next_dirty_area_check(data, L2 + 1, 5);
+ test_hbitmap_next_dirty_area_check(data, L2 + 1, 3);
+ test_hbitmap_next_dirty_area_check(data, L2 + 4, L1);
+ test_hbitmap_next_dirty_area_check(data, L2 + 5, L1);
+ test_hbitmap_next_dirty_area_check(data, L2 + 7, L1);
+ test_hbitmap_next_dirty_area_check(data, L2 + L1, L1);
+ test_hbitmap_next_dirty_area_check(data, L2, 0);
+ test_hbitmap_next_dirty_area_check(data, L2 + 1, 0);
+
+ hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2);
+ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 + 1, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1 - 1, UINT64_MAX);
+ test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1, 5);
+ test_hbitmap_next_dirty_area_check(data, L2 * 2 - L1, L1 + 1);
+ test_hbitmap_next_dirty_area_check(data, L2 * 2, L2);
+
+ hbitmap_set(data->hb, 0, L3);
+ test_hbitmap_next_dirty_area_check(data, 0, UINT64_MAX);
+}
+
+static void test_hbitmap_next_dirty_area_0(TestHBitmapData *data,
+ const void *unused)
+{
+ test_hbitmap_next_dirty_area_do(data, 0);
+}
+
+static void test_hbitmap_next_dirty_area_1(TestHBitmapData *data,
+ const void *unused)
+{
+ test_hbitmap_next_dirty_area_do(data, 1);
+}
+
+static void test_hbitmap_next_dirty_area_4(TestHBitmapData *data,
+ const void *unused)
+{
+ test_hbitmap_next_dirty_area_do(data, 4);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -1058,6 +1170,13 @@ int main(int argc, char **argv)
hbitmap_test_add("/hbitmap/next_zero/next_zero_4",
test_hbitmap_next_zero_4);
+ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_0",
+ test_hbitmap_next_dirty_area_0);
+ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_1",
+ test_hbitmap_next_dirty_area_1);
+ hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_4",
+ test_hbitmap_next_dirty_area_4);
+
g_test_run();
return 0;
diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c
index d81b0862d5..60231b1372 100644
--- a/tests/test-qdev-global-props.c
+++ b/tests/test-qdev-global-props.c
@@ -89,6 +89,16 @@ static void test_static_prop(void)
g_test_trap_assert_stdout("");
}
+static void register_global_properties(GlobalProperty *props)
+{
+ int i;
+
+ for (i = 0; props[i].driver != NULL; i++) {
+ qdev_prop_register_global(props + i);
+ }
+}
+
+
/* Test setting of static property using global properties */
static void test_static_globalprop_subprocess(void)
{
@@ -98,7 +108,7 @@ static void test_static_globalprop_subprocess(void)
{}
};
- qdev_prop_register_global_list(props);
+ register_global_properties(props);
mt = STATIC_TYPE(object_new(TYPE_STATIC_PROPS));
qdev_init_nofail(DEVICE(mt));
@@ -206,25 +216,25 @@ static void test_dynamic_globalprop_subprocess(void)
{
MyType *mt;
static GlobalProperty props[] = {
- { TYPE_DYNAMIC_PROPS, "prop1", "101", true },
- { TYPE_DYNAMIC_PROPS, "prop2", "102", true },
- { TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", true },
- { TYPE_UNUSED_HOTPLUG, "prop4", "104", true },
- { TYPE_UNUSED_NOHOTPLUG, "prop5", "105", true },
- { TYPE_NONDEVICE, "prop6", "106", true },
+ { TYPE_DYNAMIC_PROPS, "prop1", "101", },
+ { TYPE_DYNAMIC_PROPS, "prop2", "102", },
+ { TYPE_DYNAMIC_PROPS"-bad", "prop3", "103", },
+ { TYPE_UNUSED_HOTPLUG, "prop4", "104", },
+ { TYPE_UNUSED_NOHOTPLUG, "prop5", "105", },
+ { TYPE_NONDEVICE, "prop6", "106", },
{}
};
- int all_used;
+ int global_error;
- qdev_prop_register_global_list(props);
+ register_global_properties(props);
mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS));
qdev_init_nofail(DEVICE(mt));
g_assert_cmpuint(mt->prop1, ==, 101);
g_assert_cmpuint(mt->prop2, ==, 102);
- all_used = qdev_prop_check_globals();
- g_assert_cmpuint(all_used, ==, 1);
+ global_error = qdev_prop_check_globals();
+ g_assert_cmpuint(global_error, ==, 1);
g_assert(props[0].used);
g_assert(props[1].used);
g_assert(!props[2].used);
@@ -246,46 +256,6 @@ static void test_dynamic_globalprop(void)
g_test_trap_assert_stdout("");
}
-/* Test setting of dynamic properties using user_provided=false properties */
-static void test_dynamic_globalprop_nouser_subprocess(void)
-{
- MyType *mt;
- static GlobalProperty props[] = {
- { TYPE_DYNAMIC_PROPS, "prop1", "101" },
- { TYPE_DYNAMIC_PROPS, "prop2", "102" },
- { TYPE_DYNAMIC_PROPS"-bad", "prop3", "103" },
- { TYPE_UNUSED_HOTPLUG, "prop4", "104" },
- { TYPE_UNUSED_NOHOTPLUG, "prop5", "105" },
- { TYPE_NONDEVICE, "prop6", "106" },
- {}
- };
- int all_used;
-
- qdev_prop_register_global_list(props);
-
- mt = DYNAMIC_TYPE(object_new(TYPE_DYNAMIC_PROPS));
- qdev_init_nofail(DEVICE(mt));
-
- g_assert_cmpuint(mt->prop1, ==, 101);
- g_assert_cmpuint(mt->prop2, ==, 102);
- all_used = qdev_prop_check_globals();
- g_assert_cmpuint(all_used, ==, 0);
- g_assert(props[0].used);
- g_assert(props[1].used);
- g_assert(!props[2].used);
- g_assert(!props[3].used);
- g_assert(!props[4].used);
- g_assert(!props[5].used);
-}
-
-static void test_dynamic_globalprop_nouser(void)
-{
- g_test_trap_subprocess("/qdev/properties/dynamic/global/nouser/subprocess", 0, 0);
- g_test_trap_assert_passed();
- g_test_trap_assert_stderr("");
- g_test_trap_assert_stdout("");
-}
-
/* Test if global props affecting subclasses are applied in the right order */
static void test_subclass_global_props(void)
{
@@ -299,7 +269,7 @@ static void test_subclass_global_props(void)
{}
};
- qdev_prop_register_global_list(props);
+ register_global_properties(props);
mt = STATIC_TYPE(object_new(TYPE_SUBCLASS));
qdev_init_nofail(DEVICE(mt));
@@ -335,11 +305,6 @@ int main(int argc, char **argv)
g_test_add_func("/qdev/properties/dynamic/global",
test_dynamic_globalprop);
- g_test_add_func("/qdev/properties/dynamic/global/nouser/subprocess",
- test_dynamic_globalprop_nouser_subprocess);
- g_test_add_func("/qdev/properties/dynamic/global/nouser",
- test_dynamic_globalprop_nouser);
-
g_test_add_func("/qdev/properties/global/subclass",
test_subclass_global_props);
diff --git a/tests/test-qmp-cmds.c b/tests/test-qmp-cmds.c
index 4ab2b6e5ce..481cb069ca 100644
--- a/tests/test-qmp-cmds.c
+++ b/tests/test-qmp-cmds.c
@@ -126,6 +126,21 @@ static void test_dispatch_cmd(void)
qobject_unref(req);
}
+static void test_dispatch_cmd_oob(void)
+{
+ QDict *req = qdict_new();
+ QDict *resp;
+
+ qdict_put_str(req, "exec-oob", "test-flags-command");
+
+ resp = qmp_dispatch(&qmp_commands, QOBJECT(req), true);
+ assert(resp != NULL);
+ assert(!qdict_haskey(resp, "error"));
+
+ qobject_unref(resp);
+ qobject_unref(req);
+}
+
/* test commands that return an error due to invalid parameters */
static void test_dispatch_cmd_failure(void)
{
@@ -302,6 +317,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
+ g_test_add_func("/qmp/dispatch_cmd_oob", test_dispatch_cmd_oob);
g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
g_test_add_func("/qmp/dispatch_cmd_success_response",
diff --git a/tests/test-rcu-list.c b/tests/test-rcu-list.c
index 2e6f70bd59..6f076473e0 100644
--- a/tests/test-rcu-list.c
+++ b/tests/test-rcu-list.c
@@ -108,7 +108,7 @@ static void reclaim_list_el(struct rcu_head *prcu)
}
#if TEST_LIST_TYPE == 1
-static QLIST_HEAD(q_list_head, list_element) Q_list_head;
+static QLIST_HEAD(, list_element) Q_list_head;
#define TEST_NAME "qlist"
#define TEST_LIST_REMOVE_RCU QLIST_REMOVE_RCU
diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c
index 88e0e1aa9a..34b54dfc89 100644
--- a/tests/test-string-input-visitor.c
+++ b/tests/test-string-input-visitor.c
@@ -92,16 +92,6 @@ static void check_ulist(Visitor *v, uint64_t *expected, size_t n)
uint64List *tail;
int i;
- /* BUG: unsigned numbers above INT64_MAX don't work */
- for (i = 0; i < n; i++) {
- if (expected[i] > INT64_MAX) {
- Error *err = NULL;
- visit_type_uint64List(v, NULL, &res, &err);
- error_free_or_abort(&err);
- return;
- }
- }
-
visit_type_uint64List(v, NULL, &res, &error_abort);
tail = res;
for (i = 0; i < n; i++) {
@@ -117,14 +107,14 @@ static void check_ulist(Visitor *v, uint64_t *expected, size_t n)
static void test_visitor_in_intList(TestInputVisitorData *data,
const void *unused)
{
- /* Note: the visitor *sorts* ranges *unsigned* */
- int64_t expect1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20 };
+ int64_t expect1[] = { 1, 2, 0, 2, 3, 4, 20, 5, 6, 7,
+ 8, 9, 1, 2, 3, 4, 5, 6, 7, 8 };
int64_t expect2[] = { 32767, -32768, -32767 };
- int64_t expect3[] = { INT64_MAX, INT64_MIN };
- uint64_t expect4[] = { UINT64_MAX };
+ int64_t expect3[] = { INT64_MIN, INT64_MAX };
+ int64_t expect4[] = { 1 };
+ int64_t expect5[] = { INT64_MAX - 2, INT64_MAX - 1, INT64_MAX };
Error *err = NULL;
int64List *res = NULL;
- int64List *tail;
Visitor *v;
int64_t val;
@@ -140,8 +130,45 @@ static void test_visitor_in_intList(TestInputVisitorData *data,
"-9223372036854775808,9223372036854775807");
check_ilist(v, expect3, ARRAY_SIZE(expect3));
- v = visitor_input_test_init(data, "18446744073709551615");
- check_ulist(v, expect4, ARRAY_SIZE(expect4));
+ v = visitor_input_test_init(data, "1-1");
+ check_ilist(v, expect4, ARRAY_SIZE(expect4));
+
+ v = visitor_input_test_init(data,
+ "9223372036854775805-9223372036854775807");
+ check_ilist(v, expect5, ARRAY_SIZE(expect5));
+
+ /* Value too large */
+
+ v = visitor_input_test_init(data, "9223372036854775808");
+ visit_type_int64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Value too small */
+
+ v = visitor_input_test_init(data, "-9223372036854775809");
+ visit_type_int64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Range not ascending */
+
+ v = visitor_input_test_init(data, "3-1");
+ visit_type_int64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ v = visitor_input_test_init(data, "9223372036854775807-0");
+ visit_type_int64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Range too big (65536 is the limit against DOS attacks) */
+
+ v = visitor_input_test_init(data, "0-65536");
+ visit_type_int64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
/* Empty list */
@@ -161,39 +188,140 @@ static void test_visitor_in_intList(TestInputVisitorData *data,
v = visitor_input_test_init(data, "0,2-3");
- /* Would be simpler if the visitor genuinely supported virtual walks */
- visit_start_list(v, NULL, (GenericList **)&res, sizeof(*res),
- &error_abort);
- tail = res;
- visit_type_int64(v, NULL, &tail->value, &error_abort);
- g_assert_cmpint(tail->value, ==, 0);
- tail = (int64List *)visit_next_list(v, (GenericList *)tail, sizeof(*res));
- g_assert(tail);
- visit_type_int64(v, NULL, &tail->value, &error_abort);
- g_assert_cmpint(tail->value, ==, 2);
- tail = (int64List *)visit_next_list(v, (GenericList *)tail, sizeof(*res));
- g_assert(tail);
+ visit_start_list(v, NULL, NULL, 0, &error_abort);
+ visit_type_int64(v, NULL, &val, &error_abort);
+ g_assert_cmpint(val, ==, 0);
+ visit_type_int64(v, NULL, &val, &error_abort);
+ g_assert_cmpint(val, ==, 2);
visit_check_list(v, &err);
error_free_or_abort(&err);
- visit_end_list(v, (void **)&res);
-
- qapi_free_int64List(res);
+ visit_end_list(v, NULL);
/* Visit beyond end of list */
+
v = visitor_input_test_init(data, "0");
- visit_start_list(v, NULL, (GenericList **)&res, sizeof(*res),
- &error_abort);
- tail = res;
- visit_type_int64(v, NULL, &tail->value, &err);
- g_assert_cmpint(tail->value, ==, 0);
+ visit_start_list(v, NULL, NULL, 0, &error_abort);
visit_type_int64(v, NULL, &val, &err);
- g_assert_cmpint(val, ==, 1); /* BUG */
+ g_assert_cmpint(val, ==, 0);
+ visit_type_int64(v, NULL, &val, &err);
+ error_free_or_abort(&err);
+
visit_check_list(v, &error_abort);
- visit_end_list(v, (void **)&res);
+ visit_end_list(v, NULL);
+}
- qapi_free_int64List(res);
+static void test_visitor_in_uintList(TestInputVisitorData *data,
+ const void *unused)
+{
+ uint64_t expect1[] = { 1, 2, 0, 2, 3, 4, 20, 5, 6, 7,
+ 8, 9, 1, 2, 3, 4, 5, 6, 7, 8 };
+ uint64_t expect2[] = { 32767, -32768, -32767 };
+ uint64_t expect3[] = { INT64_MIN, INT64_MAX };
+ uint64_t expect4[] = { 1 };
+ uint64_t expect5[] = { UINT64_MAX };
+ uint64_t expect6[] = { UINT64_MAX - 2, UINT64_MAX - 1, UINT64_MAX };
+ Error *err = NULL;
+ uint64List *res = NULL;
+ Visitor *v;
+ uint64_t val;
+
+ /* Valid lists */
+
+ v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8");
+ check_ulist(v, expect1, ARRAY_SIZE(expect1));
+
+ v = visitor_input_test_init(data, "32767,-32768--32767");
+ check_ulist(v, expect2, ARRAY_SIZE(expect2));
+
+ v = visitor_input_test_init(data,
+ "-9223372036854775808,9223372036854775807");
+ check_ulist(v, expect3, ARRAY_SIZE(expect3));
+
+ v = visitor_input_test_init(data, "1-1");
+ check_ulist(v, expect4, ARRAY_SIZE(expect4));
+
+ v = visitor_input_test_init(data, "18446744073709551615");
+ check_ulist(v, expect5, ARRAY_SIZE(expect5));
+
+ v = visitor_input_test_init(data,
+ "18446744073709551613-18446744073709551615");
+ check_ulist(v, expect6, ARRAY_SIZE(expect6));
+
+ /* Value too large */
+
+ v = visitor_input_test_init(data, "18446744073709551616");
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Value too small */
+
+ v = visitor_input_test_init(data, "-18446744073709551616");
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Range not ascending */
+
+ v = visitor_input_test_init(data, "3-1");
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ v = visitor_input_test_init(data, "18446744073709551615-0");
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Range too big (65536 is the limit against DOS attacks) */
+
+ v = visitor_input_test_init(data, "0-65536");
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Empty list */
+
+ v = visitor_input_test_init(data, "");
+ visit_type_uint64List(v, NULL, &res, &error_abort);
+ g_assert(!res);
+
+ /* Not a list */
+
+ v = visitor_input_test_init(data, "not an uint list");
+
+ visit_type_uint64List(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+ g_assert(!res);
+
+ /* Unvisited list tail */
+
+ v = visitor_input_test_init(data, "0,2-3");
+
+ visit_start_list(v, NULL, NULL, 0, &error_abort);
+ visit_type_uint64(v, NULL, &val, &error_abort);
+ g_assert_cmpuint(val, ==, 0);
+ visit_type_uint64(v, NULL, &val, &error_abort);
+ g_assert_cmpuint(val, ==, 2);
+
+ visit_check_list(v, &err);
+ error_free_or_abort(&err);
+ visit_end_list(v, NULL);
+
+ /* Visit beyond end of list */
+
+ v = visitor_input_test_init(data, "0");
+
+ visit_start_list(v, NULL, NULL, 0, &error_abort);
+ visit_type_uint64(v, NULL, &val, &err);
+ g_assert_cmpuint(val, ==, 0);
+ visit_type_uint64(v, NULL, &val, &err);
+ error_free_or_abort(&err);
+
+ visit_check_list(v, &error_abort);
+ visit_end_list(v, NULL);
}
static void test_visitor_in_bool(TestInputVisitorData *data,
@@ -252,6 +380,19 @@ static void test_visitor_in_number(TestInputVisitorData *data,
visit_type_number(v, NULL, &res, &err);
g_assert(!err);
g_assert_cmpfloat(res, ==, value);
+
+ /* NaN and infinity has to be rejected */
+
+ v = visitor_input_test_init(data, "NaN");
+
+ visit_type_number(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+
+ v = visitor_input_test_init(data, "inf");
+
+ visit_type_number(v, NULL, &res, &err);
+ error_free_or_abort(&err);
+
}
static void test_visitor_in_string(TestInputVisitorData *data,
@@ -356,6 +497,8 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_int);
input_visitor_test_add("/string-visitor/input/intList",
&in_visitor_data, test_visitor_in_intList);
+ input_visitor_test_add("/string-visitor/input/uintList",
+ &in_visitor_data, test_visitor_in_uintList);
input_visitor_test_add("/string-visitor/input/bool",
&in_visitor_data, test_visitor_in_bool);
input_visitor_test_add("/string-visitor/input/number",
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index 37a7a93784..0ab29a8216 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -630,7 +630,7 @@ struct TestQtailqElement {
typedef struct TestQtailq {
int16_t i16;
- QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q;
+ QTAILQ_HEAD(, TestQtailqElement) q;
int32_t i32;
} TestQtailq;
@@ -735,9 +735,9 @@ static void test_load_q(void)
g_assert_cmpint(eof, ==, QEMU_VM_EOF);
TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q);
- TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead);
+ TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q);
TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q);
- TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead);
+ TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q);
while (1) {
g_assert_cmpint(qele_to->b, ==, qele_from->b);
@@ -755,7 +755,7 @@ static void test_load_q(void)
/* clean up */
TestQtailqElement *qele;
while (!QTAILQ_EMPTY(&tgt.q)) {
- qele = QTAILQ_LAST(&tgt.q, TestQtailqHead);
+ qele = QTAILQ_LAST(&tgt.q);
QTAILQ_REMOVE(&tgt.q, qele, next);
free(qele);
qele = NULL;
diff --git a/tests/tpm-util.h b/tests/tpm-util.h
index 9e98bc5124..5755698ad2 100644
--- a/tests/tpm-util.h
+++ b/tests/tpm-util.h
@@ -13,7 +13,6 @@
#ifndef TESTS_TPM_UTIL_H
#define TESTS_TPM_UTIL_H
-#include "qemu/osdep.h"
#include "io/channel-socket.h"
typedef void (tx_func)(QTestState *s,
diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c
index 0cf8d0baca..0033b61f2e 100644
--- a/tests/vhost-user-bridge.c
+++ b/tests/vhost-user-bridge.c
@@ -29,8 +29,8 @@
#define _FILE_OFFSET_BITS 64
-#include "qemu/atomic.h"
#include "qemu/osdep.h"
+#include "qemu/atomic.h"
#include "qemu/iov.h"
#include "standard-headers/linux/virtio_net.h"
#include "contrib/libvhost-user/libvhost-user.h"
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 45d58d8ea2..84e50d84e7 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -309,7 +309,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
CharBackend *chr = &s->chr;
VhostUserMsg msg;
uint8_t *p = (uint8_t *) &msg;
- int fd;
+ int fd = -1;
if (s->test_fail) {
qemu_chr_fe_disconnect(chr);
@@ -354,8 +354,8 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
break;
case VHOST_USER_SET_FEATURES:
- g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
- !=, 0ULL);
+ g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES),
+ !=, 0ULL);
if (s->test_flags == TEST_FLAGS_DISCONNECT) {
qemu_chr_fe_disconnect(chr);
s->test_flags = TEST_FLAGS_BAD;
diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c
index 0a6fb55f2e..52cdd83ec0 100644
--- a/tests/vmgenid-test.c
+++ b/tests/vmgenid-test.c
@@ -23,89 +23,67 @@
*/
#define RSDP_ADDR_INVALID 0x100000 /* RSDP must be below this address */
-typedef struct {
- AcpiTableHeader header;
- gchar name_op;
- gchar vgia[4];
- gchar val_op;
- uint32_t vgia_val;
-} QEMU_PACKED VgidTable;
-
-static uint32_t acpi_find_vgia(void)
+static uint32_t acpi_find_vgia(QTestState *qts)
{
uint32_t rsdp_offset;
uint32_t guid_offset = 0;
- AcpiRsdpDescriptor rsdp_table;
- uint32_t rsdt, rsdt_table_length;
- AcpiRsdtDescriptorRev1 rsdt_table;
- size_t tables_nr;
- uint32_t *tables;
- AcpiTableHeader ssdt_table;
- VgidTable vgid_table;
- int i;
+ uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
+ uint32_t rsdt_len, table_length;
+ uint8_t *rsdt, *ent;
/* Wait for guest firmware to finish and start the payload. */
- boot_sector_test(global_qtest);
+ boot_sector_test(qts);
/* Tables should be initialized now. */
- rsdp_offset = acpi_find_rsdp_address();
+ rsdp_offset = acpi_find_rsdp_address(qts);
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
- acpi_parse_rsdp_table(rsdp_offset, &rsdp_table);
-
- rsdt = le32_to_cpu(rsdp_table.rsdt_physical_address);
- /* read the header */
- ACPI_READ_TABLE_HEADER(&rsdt_table, rsdt);
- ACPI_ASSERT_CMP(rsdt_table.signature, "RSDT");
- rsdt_table_length = le32_to_cpu(rsdt_table.length);
- /* compute the table entries in rsdt */
- g_assert_cmpint(rsdt_table_length, >, sizeof(AcpiRsdtDescriptorRev1));
- tables_nr = (rsdt_table_length - sizeof(AcpiRsdtDescriptorRev1)) /
- sizeof(uint32_t);
+ acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table);
+ acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
+ "RSDT", true);
- /* get the addresses of the tables pointed by rsdt */
- tables = g_new0(uint32_t, tables_nr);
- ACPI_READ_ARRAY_PTR(tables, tables_nr, rsdt);
+ ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
+ uint8_t *table_aml;
- for (i = 0; i < tables_nr; i++) {
- uint32_t addr = le32_to_cpu(tables[i]);
- ACPI_READ_TABLE_HEADER(&ssdt_table, addr);
- if (!strncmp((char *)ssdt_table.oem_table_id, "VMGENID", 7)) {
+ acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true);
+ if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
+ uint32_t vgia_val;
+ uint8_t *aml = &table_aml[36 /* AML byte-code start */];
/* the first entry in the table should be VGIA
* That's all we need
*/
- ACPI_READ_FIELD(vgid_table.name_op, addr);
- g_assert(vgid_table.name_op == 0x08); /* name */
- ACPI_READ_ARRAY(vgid_table.vgia, addr);
- g_assert(memcmp(vgid_table.vgia, "VGIA", 4) == 0);
- ACPI_READ_FIELD(vgid_table.val_op, addr);
- g_assert(vgid_table.val_op == 0x0C); /* dword */
- ACPI_READ_FIELD(vgid_table.vgia_val, addr);
+ g_assert(aml[0 /* name_op*/] == 0x08);
+ g_assert(memcmp(&aml[1 /* name */], "VGIA", 4) == 0);
+ g_assert(aml[5 /* value op */] == 0x0C /* dword */);
+ memcpy(&vgia_val, &aml[6 /* value */], 4);
+
/* The GUID is written at a fixed offset into the fw_cfg file
* in order to implement the "OVMF SDT Header probe suppressor"
* see docs/specs/vmgenid.txt for more details
*/
- guid_offset = le32_to_cpu(vgid_table.vgia_val) + VMGENID_GUID_OFFSET;
+ guid_offset = le32_to_cpu(vgia_val) + VMGENID_GUID_OFFSET;
+ g_free(table_aml);
break;
}
+ g_free(table_aml);
}
- g_free(tables);
+ g_free(rsdt);
return guid_offset;
}
-static void read_guid_from_memory(QemuUUID *guid)
+static void read_guid_from_memory(QTestState *qts, QemuUUID *guid)
{
uint32_t vmgenid_addr;
int i;
- vmgenid_addr = acpi_find_vgia();
+ vmgenid_addr = acpi_find_vgia(qts);
g_assert(vmgenid_addr);
/* Read the GUID directly from guest memory */
for (i = 0; i < 16; i++) {
- guid->data[i] = readb(vmgenid_addr + i);
+ guid->data[i] = qtest_readb(qts, vmgenid_addr + i);
}
/* The GUID is in little-endian format in the guest, while QEMU
* uses big-endian. Swap after reading.
@@ -113,12 +91,12 @@ static void read_guid_from_memory(QemuUUID *guid)
qemu_uuid_bswap(guid);
}
-static void read_guid_from_monitor(QemuUUID *guid)
+static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid)
{
QDict *rsp, *rsp_ret;
const char *guid_str;
- rsp = qmp("{ 'execute': 'query-vm-generation-id' }");
+ rsp = qtest_qmp(qts, "{ 'execute': 'query-vm-generation-id' }");
if (qdict_haskey(rsp, "return")) {
rsp_ret = qdict_get_qdict(rsp, "return");
g_assert(qdict_haskey(rsp_ret, "guid"));
@@ -139,45 +117,48 @@ static char disk[] = "tests/vmgenid-test-disk-XXXXXX";
static void vmgenid_set_guid_test(void)
{
QemuUUID expected, measured;
+ QTestState *qts;
g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
- global_qtest = qtest_initf(GUID_CMD(VGID_GUID));
+ qts = qtest_initf(GUID_CMD(VGID_GUID));
/* Read the GUID from accessing guest memory */
- read_guid_from_memory(&measured);
+ read_guid_from_memory(qts, &measured);
g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
- qtest_quit(global_qtest);
+ qtest_quit(qts);
}
static void vmgenid_set_guid_auto_test(void)
{
QemuUUID measured;
+ QTestState *qts;
- global_qtest = qtest_initf(GUID_CMD("auto"));
+ qts = qtest_initf(GUID_CMD("auto"));
- read_guid_from_memory(&measured);
+ read_guid_from_memory(qts, &measured);
/* Just check that the GUID is non-null */
g_assert(!qemu_uuid_is_null(&measured));
- qtest_quit(global_qtest);
+ qtest_quit(qts);
}
static void vmgenid_query_monitor_test(void)
{
QemuUUID expected, measured;
+ QTestState *qts;
g_assert(qemu_uuid_parse(VGID_GUID, &expected) == 0);
- global_qtest = qtest_initf(GUID_CMD(VGID_GUID));
+ qts = qtest_initf(GUID_CMD(VGID_GUID));
/* Read the GUID via the monitor */
- read_guid_from_monitor(&measured);
+ read_guid_from_monitor(qts, &measured);
g_assert(memcmp(measured.data, expected.data, sizeof(measured.data)) == 0);
- qtest_quit(global_qtest);
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/trace/simple.c b/trace/simple.c
index 701dec639c..ac904eca91 100644
--- a/trace/simple.c
+++ b/trace/simple.c
@@ -169,9 +169,9 @@ static gpointer writeout_thread(gpointer opaque)
wait_for_trace_records_available();
if (g_atomic_int_get(&dropped_events)) {
- dropped.rec.event = DROPPED_EVENT_ID,
+ dropped.rec.event = DROPPED_EVENT_ID;
dropped.rec.timestamp_ns = get_clock();
- dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t),
+ dropped.rec.length = sizeof(TraceRecord) + sizeof(uint64_t);
dropped.rec.pid = trace_pid;
do {
dropped_count = g_atomic_int_get(&dropped_events);
diff --git a/ui/cocoa.m b/ui/cocoa.m
index ecf12bfc2e..ddc058e76e 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -32,7 +32,8 @@
#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
-#include "qapi/qapi-commands.h"
+#include "qapi/qapi-commands-block.h"
+#include "qapi/qapi-commands-misc.h"
#include "sysemu/blockdev.h"
#include "qemu-version.h"
#include <Carbon/Carbon.h>
diff --git a/ui/console.c b/ui/console.c
index 3a285bae00..6d2282d3e9 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -182,7 +182,7 @@ struct DisplayState {
static DisplayState *display_state;
static QemuConsole *active_console;
-static QTAILQ_HEAD(consoles_head, QemuConsole) consoles =
+static QTAILQ_HEAD(, QemuConsole) consoles =
QTAILQ_HEAD_INITIALIZER(consoles);
static bool cursor_visible_phase;
static QEMUTimer *cursor_timer;
@@ -1303,7 +1303,7 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
s->index = 0;
QTAILQ_INSERT_TAIL(&consoles, s, next);
} else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
- QemuConsole *last = QTAILQ_LAST(&consoles, consoles_head);
+ QemuConsole *last = QTAILQ_LAST(&consoles);
s->index = last->index + 1;
QTAILQ_INSERT_TAIL(&consoles, s, next);
} else {
@@ -1385,42 +1385,6 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
return surface;
}
-static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
- void *unused)
-{
- void *data = pixman_image_get_data(image);
- uint32_t size = pixman_image_get_stride(image) *
- pixman_image_get_height(image);
- cpu_physical_memory_unmap(data, size, 0, 0);
-}
-
-DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
- pixman_format_code_t format,
- int linesize, uint64_t addr)
-{
- DisplaySurface *surface;
- hwaddr size;
- void *data;
-
- if (linesize == 0) {
- linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
- }
-
- size = (hwaddr)linesize * height;
- data = cpu_physical_memory_map(addr, &size, 0);
- if (size != (hwaddr)linesize * height) {
- cpu_physical_memory_unmap(data, size, 0, 0);
- return NULL;
- }
-
- surface = qemu_create_displaysurface_from
- (width, height, format, linesize, data);
- pixman_image_set_destroy_function
- (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
-
- return surface;
-}
-
DisplaySurface *qemu_create_message_surface(int w, int h,
const char *msg)
{
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 4cf3bbc0e4..519e7bad32 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -38,6 +38,14 @@ static void egl_gfx_switch(DisplayChangeListener *dcl,
edpy->ds = new_surface;
}
+static QEMUGLContext egl_create_context(DisplayChangeListener *dcl,
+ QEMUGLParams *params)
+{
+ eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ qemu_egl_rn_ctx);
+ return qemu_egl_create_context(dcl, params);
+}
+
static void egl_scanout_disable(DisplayChangeListener *dcl)
{
egl_dpy *edpy = container_of(dcl, egl_dpy, dcl);
@@ -150,7 +158,7 @@ static const DisplayChangeListenerOps egl_ops = {
.dpy_gfx_update = egl_gfx_update,
.dpy_gfx_switch = egl_gfx_switch,
- .dpy_gl_ctx_create = qemu_egl_create_context,
+ .dpy_gl_ctx_create = egl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context,
.dpy_gl_ctx_make_current = qemu_egl_make_context_current,
.dpy_gl_ctx_get_current = qemu_egl_get_current_context,
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 4f475142fc..5e115b3fb4 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -273,14 +273,14 @@ void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf)
/* ---------------------------------------------------------------------- */
-EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, Window win)
+EGLSurface qemu_egl_init_surface_x11(EGLContext ectx, EGLNativeWindowType win)
{
EGLSurface esurface;
EGLBoolean b;
esurface = eglCreateWindowSurface(qemu_egl_display,
qemu_egl_config,
- (EGLNativeWindowType)win, NULL);
+ win, NULL);
if (esurface == EGL_NO_SURFACE) {
error_report("egl: eglCreateWindowSurface failed");
return NULL;
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 5420c2362b..afd17148c0 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -54,7 +54,8 @@ void gd_egl_init(VirtualConsole *vc)
}
vc->gfx.ectx = qemu_egl_init_ctx();
- vc->gfx.esurface = qemu_egl_init_surface_x11(vc->gfx.ectx, x11_window);
+ vc->gfx.esurface = qemu_egl_init_surface_x11
+ (vc->gfx.ectx, (EGLNativeWindowType)x11_window);
assert(vc->gfx.esurface);
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 579990b865..87c0e33d2a 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -2214,8 +2214,8 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
VirtualConsole *vc;
GtkDisplayState *s = g_malloc0(sizeof(*s));
- char *filename;
GdkDisplay *window_display;
+ GtkIconTheme *theme;
if (!gtkinit) {
fprintf(stderr, "gtk initialization failed\n");
@@ -2224,6 +2224,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
assert(opts->type == DISPLAY_TYPE_GTK);
s->opts = opts;
+ theme = gtk_icon_theme_get_default();
+ gtk_icon_theme_prepend_search_path(theme, CONFIG_QEMU_ICONDIR);
+ g_set_prgname("qemu");
+
s->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
s->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
s->notebook = gtk_notebook_new();
@@ -2248,17 +2252,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
qemu_add_mouse_mode_change_notifier(&s->mouse_mode_notifier);
qemu_add_vm_change_state_handler(gd_change_runstate, s);
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu_logo_no_text.svg");
- if (filename) {
- GError *error = NULL;
- GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error);
- if (pixbuf) {
- gtk_window_set_icon(GTK_WINDOW(s->window), pixbuf);
- } else {
- g_error_free(error);
- }
- g_free(filename);
- }
+ gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu");
gd_create_menus(s);
diff --git a/ui/icons/Makefile b/ui/icons/Makefile
new file mode 100644
index 0000000000..20bd64ccce
--- /dev/null
+++ b/ui/icons/Makefile
@@ -0,0 +1,13 @@
+
+# Regenerate bitmaps from the SVG using inkscape CLI export
+# and ImageMagick. Don't use ImageMagick for the initial
+# SVG conversion, since it merely calls inkscape, but uses
+# 96 DPI res resulting in poor quality output.
+
+regenerate:
+ for s in 16 24 32 48 64 128 256 512; \
+ do \
+ inkscape --without-gui --export-png=qemu_$${s}x$${s}.png \
+ --export-width=$$s --export-height=$$s qemu.svg ; \
+ done
+ convert qemu_32x32.png qemu_32x32.bmp
diff --git a/pc-bios/qemu_logo_no_text.svg b/ui/icons/qemu.svg
index 24ca23a1e9..24ca23a1e9 100644
--- a/pc-bios/qemu_logo_no_text.svg
+++ b/ui/icons/qemu.svg
diff --git a/ui/icons/qemu_128x128.png b/ui/icons/qemu_128x128.png
new file mode 100644
index 0000000000..96831807ba
--- /dev/null
+++ b/ui/icons/qemu_128x128.png
Binary files differ
diff --git a/ui/icons/qemu_16x16.png b/ui/icons/qemu_16x16.png
new file mode 100644
index 0000000000..ff4f046024
--- /dev/null
+++ b/ui/icons/qemu_16x16.png
Binary files differ
diff --git a/ui/icons/qemu_24x24.png b/ui/icons/qemu_24x24.png
new file mode 100644
index 0000000000..f039c6e25d
--- /dev/null
+++ b/ui/icons/qemu_24x24.png
Binary files differ
diff --git a/ui/icons/qemu_256x256.png b/ui/icons/qemu_256x256.png
new file mode 100644
index 0000000000..a39c0e307e
--- /dev/null
+++ b/ui/icons/qemu_256x256.png
Binary files differ
diff --git a/ui/icons/qemu_32x32.bmp b/ui/icons/qemu_32x32.bmp
new file mode 100644
index 0000000000..c0daa54abe
--- /dev/null
+++ b/ui/icons/qemu_32x32.bmp
Binary files differ
diff --git a/ui/icons/qemu_32x32.png b/ui/icons/qemu_32x32.png
new file mode 100644
index 0000000000..b746096cf8
--- /dev/null
+++ b/ui/icons/qemu_32x32.png
Binary files differ
diff --git a/ui/icons/qemu_48x48.png b/ui/icons/qemu_48x48.png
new file mode 100644
index 0000000000..067281225d
--- /dev/null
+++ b/ui/icons/qemu_48x48.png
Binary files differ
diff --git a/ui/icons/qemu_512x512.png b/ui/icons/qemu_512x512.png
new file mode 100644
index 0000000000..86aaa6395f
--- /dev/null
+++ b/ui/icons/qemu_512x512.png
Binary files differ
diff --git a/ui/icons/qemu_64x64.png b/ui/icons/qemu_64x64.png
new file mode 100644
index 0000000000..e00c8b4c9b
--- /dev/null
+++ b/ui/icons/qemu_64x64.png
Binary files differ
diff --git a/ui/input.c b/ui/input.c
index 7c9a4109c4..9494688295 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -19,6 +19,9 @@ struct QemuInputHandlerState {
};
typedef struct QemuInputEventQueue QemuInputEventQueue;
+typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
+ QemuInputEventQueueHead;
+
struct QemuInputEventQueue {
enum {
QEMU_INPUT_QUEUE_DELAY = 1,
@@ -37,8 +40,7 @@ static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
static NotifierList mouse_mode_notifiers =
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
-static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
- QTAILQ_HEAD_INITIALIZER(kbd_queue);
+static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
static QEMUTimer *kbd_timer;
static uint32_t kbd_default_delay_ms = 10;
static uint32_t queue_count;
@@ -257,7 +259,7 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
static void qemu_input_queue_process(void *opaque)
{
- struct QemuInputEventQueueHead *queue = opaque;
+ QemuInputEventQueueHead *queue = opaque;
QemuInputEventQueue *item;
g_assert(!QTAILQ_EMPTY(queue));
@@ -288,7 +290,7 @@ static void qemu_input_queue_process(void *opaque)
}
}
-static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
+static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
QEMUTimer *timer, uint32_t delay_ms)
{
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
@@ -306,7 +308,7 @@ static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
}
}
-static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
+static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
QemuConsole *src, InputEvent *evt)
{
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
@@ -318,7 +320,7 @@ static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
queue_count++;
}
-static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
+static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
{
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
@@ -458,22 +460,18 @@ void qemu_input_event_send_key_delay(uint32_t delay_ms)
}
}
-InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
-{
- InputEvent *evt = g_new0(InputEvent, 1);
- evt->u.btn.data = g_new0(InputBtnEvent, 1);
- evt->type = INPUT_EVENT_KIND_BTN;
- evt->u.btn.data->button = btn;
- evt->u.btn.data->down = down;
- return evt;
-}
-
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
{
- InputEvent *evt;
- evt = qemu_input_event_new_btn(btn, down);
- qemu_input_event_send(src, evt);
- qapi_free_InputEvent(evt);
+ InputBtnEvent bevt = {
+ .button = btn,
+ .down = down,
+ };
+ InputEvent evt = {
+ .type = INPUT_EVENT_KIND_BTN,
+ .u.btn.data = &bevt,
+ };
+
+ qemu_input_event_send(src, &evt);
}
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
@@ -513,37 +511,35 @@ int qemu_input_scale_axis(int value,
return ((int64_t)value - min_in) * range_out / range_in + min_out;
}
-InputEvent *qemu_input_event_new_move(InputEventKind kind,
- InputAxis axis, int value)
-{
- InputEvent *evt = g_new0(InputEvent, 1);
- InputMoveEvent *move = g_new0(InputMoveEvent, 1);
-
- evt->type = kind;
- evt->u.rel.data = move; /* evt->u.rel is the same as evt->u.abs */
- move->axis = axis;
- move->value = value;
- return evt;
-}
-
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
{
- InputEvent *evt;
- evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
- qemu_input_event_send(src, evt);
- qapi_free_InputEvent(evt);
+ InputMoveEvent move = {
+ .axis = axis,
+ .value = value,
+ };
+ InputEvent evt = {
+ .type = INPUT_EVENT_KIND_REL,
+ .u.rel.data = &move,
+ };
+
+ qemu_input_event_send(src, &evt);
}
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
int min_in, int max_in)
{
- InputEvent *evt;
- int scaled = qemu_input_scale_axis(value, min_in, max_in,
+ InputMoveEvent move = {
+ .axis = axis,
+ .value = qemu_input_scale_axis(value, min_in, max_in,
INPUT_EVENT_ABS_MIN,
- INPUT_EVENT_ABS_MAX);
- evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
- qemu_input_event_send(src, evt);
- qapi_free_InputEvent(evt);
+ INPUT_EVENT_ABS_MAX),
+ };
+ InputEvent evt = {
+ .type = INPUT_EVENT_KIND_ABS,
+ .u.abs.data = &move,
+ };
+
+ qemu_input_event_send(src, &evt);
}
void qemu_input_check_mode_change(void)
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 085889b555..6e44f738ed 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -115,10 +115,9 @@ static int parse_keyboard_layout(kbd_layout_t *k,
continue;
}
if (!strncmp(line, "include ", 8)) {
- if (parse_keyboard_layout(k, table, line + 8, errp) < 0) {
- ret = -1;
- goto out;
- }
+ error_setg(errp, "keymap include files are not supported any more");
+ ret = -1;
+ goto out;
} else {
int offset = 0;
while (line[offset] != 0 &&
diff --git a/ui/keymaps.h b/ui/keymaps.h
index 98213a4191..4e9c87fb8f 100644
--- a/ui/keymaps.h
+++ b/ui/keymaps.h
@@ -28,8 +28,8 @@
#include "qemu-common.h"
typedef struct {
- const char* name;
- int keysym;
+ const char* name;
+ int keysym;
} name2keysym_t;
/* scancode without modifiers */
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 3e52abd92d..1429cf08d5 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -36,7 +36,7 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
pf.rshift = 0;
break;
case PIXMAN_TYPE_BGRA:
- pf.bshift = bpp - pf.bbits;
+ pf.bshift = bpp - pf.bbits;
pf.gshift = bpp - (pf.bbits + pf.gbits);
pf.rshift = bpp - (pf.bbits + pf.gbits + pf.rbits);
pf.ashift = 0;
diff --git a/ui/qemu.desktop b/ui/qemu.desktop
new file mode 100644
index 0000000000..20f09f56be
--- /dev/null
+++ b/ui/qemu.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Version=1.0
+Name=QEMU
+Icon=qemu
+Type=Application
+Terminal=false
+Keywords=Emulators;Virtualization;KVM;
+NoDisplay=true
diff --git a/ui/sdl2.c b/ui/sdl2.c
index a10b6e3a08..cde7feba91 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -762,9 +762,9 @@ static void sdl2_display_early_init(DisplayOptions *o)
static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
{
uint8_t data = 0;
- char *filename;
int i;
SDL_SysWMinfo info;
+ SDL_Surface *icon = NULL;
assert(o->type == DISPLAY_TYPE_SDL);
@@ -836,16 +836,18 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
#endif
}
+#ifdef CONFIG_SDL_IMAGE
+ icon = IMG_Load(CONFIG_QEMU_ICONDIR "/hicolor/128x128/apps/qemu.png");
+#else
/* Load a 32x32x4 image. White pixels are transparent. */
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
- if (filename) {
- SDL_Surface *image = SDL_LoadBMP(filename);
- if (image) {
- uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
- SDL_SetColorKey(image, SDL_TRUE, colorkey);
- SDL_SetWindowIcon(sdl2_console[0].real_window, image);
- }
- g_free(filename);
+ icon = SDL_LoadBMP(CONFIG_QEMU_ICONDIR "/hicolor/32x32/apps/qemu.bmp");
+ if (icon) {
+ uint32_t colorkey = SDL_MapRGB(icon->format, 255, 255, 255);
+ SDL_SetColorKey(icon, SDL_TRUE, colorkey);
+ }
+#endif
+ if (icon) {
+ SDL_SetWindowIcon(sdl2_console[0].real_window, icon);
}
gui_grab = 0;
diff --git a/ui/spice-core.c b/ui/spice-core.c
index ebaae24643..a40fb2c00d 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -18,7 +18,6 @@
#include "qemu/osdep.h"
#include <spice.h>
-#include <netdb.h>
#include "sysemu/sysemu.h"
#include "ui/qemu-spice.h"
@@ -745,13 +744,7 @@ void qemu_spice_init(void)
}
if (qemu_opt_get_bool(opts, "disable-agent-file-xfer", 0)) {
-#if SPICE_SERVER_VERSION >= 0x000c04
spice_server_set_agent_file_xfer(spice_server, false);
-#else
- error_report("this qemu build does not support the "
- "\"disable-agent-file-xfer\" option");
- exit(1);
-#endif
}
compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
@@ -817,9 +810,7 @@ void qemu_spice_init(void)
g_free(x509_cert_file);
g_free(x509_cacert_file);
-#if SPICE_SERVER_VERSION >= 0x000c02
qemu_spice_register_ports();
-#endif
#ifdef HAVE_SPICE_GL
if (qemu_opt_get_bool(opts, "gl", 0)) {
diff --git a/ui/vnc-enc-zywrle-template.c b/ui/vnc-enc-zywrle-template.c
index b446380a7a..e9be55966e 100644
--- a/ui/vnc-enc-zywrle-template.c
+++ b/ui/vnc-enc-zywrle-template.c
@@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/* Change Log:
V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
- (Thanks Johannes Schindelin, author of LibVNC
- Server/Client)
+ (Thanks Johannes Schindelin, author of LibVNC
+ Server/Client)
V0.01 : 2007/02/06 : Initial release
*/
diff --git a/ui/vnc.c b/ui/vnc.c
index 0c1b477425..6002d09407 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -742,6 +742,17 @@ static void vnc_update_server_surface(VncDisplay *vd)
width, height);
}
+static bool vnc_check_pageflip(DisplaySurface *s1,
+ DisplaySurface *s2)
+{
+ return (s1 != NULL &&
+ s2 != NULL &&
+ surface_width(s1) == surface_width(s2) &&
+ surface_height(s1) == surface_height(s2) &&
+ surface_format(s1) == surface_format(s2));
+
+}
+
static void vnc_dpy_switch(DisplayChangeListener *dcl,
DisplaySurface *surface)
{
@@ -749,6 +760,7 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
"Display output is not active.";
static DisplaySurface *placeholder;
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
+ bool pageflip = vnc_check_pageflip(vd->ds, surface);
VncState *vs;
if (surface == NULL) {
@@ -761,14 +773,21 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl,
vnc_abort_display_jobs(vd);
vd->ds = surface;
- /* server surface */
- vnc_update_server_surface(vd);
-
/* guest surface */
qemu_pixman_image_unref(vd->guest.fb);
vd->guest.fb = pixman_image_ref(surface->image);
vd->guest.format = surface->format;
+ if (pageflip) {
+ vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
+ surface_width(surface),
+ surface_height(surface));
+ return;
+ }
+
+ /* server surface */
+ vnc_update_server_surface(vd);
+
QTAILQ_FOREACH(vs, &vd->clients, next) {
vnc_colordepth(vs);
vnc_desktop_resize(vs);
@@ -3097,8 +3116,8 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
buffer_init(&vs->zrle.zlib, "vnc-zrle-zlib/%p", sioc);
if (skipauth) {
- vs->auth = VNC_AUTH_NONE;
- vs->subauth = VNC_AUTH_INVALID;
+ vs->auth = VNC_AUTH_NONE;
+ vs->subauth = VNC_AUTH_INVALID;
} else {
if (websocket) {
vs->auth = vd->ws_auth;
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 51c41ed3c9..8640dfde9f 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -200,6 +200,31 @@ static AioHandler *find_aio_handler(AioContext *ctx, int fd)
return NULL;
}
+static bool aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
+{
+ /* If the GSource is in the process of being destroyed then
+ * g_source_remove_poll() causes an assertion failure. Skip
+ * removal in that case, because glib cleans up its state during
+ * destruction anyway.
+ */
+ if (!g_source_is_destroyed(&ctx->source)) {
+ g_source_remove_poll(&ctx->source, &node->pfd);
+ }
+
+ /* If a read is in progress, just mark the node as deleted */
+ if (qemu_lockcnt_count(&ctx->list_lock)) {
+ node->deleted = 1;
+ node->pfd.revents = 0;
+ return false;
+ }
+ /* Otherwise, delete it for real. We can't just mark it as
+ * deleted because deleted nodes are only cleaned up while
+ * no one is walking the handlers list.
+ */
+ QLIST_REMOVE(node, node);
+ return true;
+}
+
void aio_set_fd_handler(AioContext *ctx,
int fd,
bool is_external,
@@ -209,6 +234,7 @@ void aio_set_fd_handler(AioContext *ctx,
void *opaque)
{
AioHandler *node;
+ AioHandler *new_node = NULL;
bool is_new = false;
bool deleted = false;
int poll_disable_change;
@@ -223,50 +249,39 @@ void aio_set_fd_handler(AioContext *ctx,
qemu_lockcnt_unlock(&ctx->list_lock);
return;
}
+ /* Clean events in order to unregister fd from the ctx epoll. */
+ node->pfd.events = 0;
- /* If the GSource is in the process of being destroyed then
- * g_source_remove_poll() causes an assertion failure. Skip
- * removal in that case, because glib cleans up its state during
- * destruction anyway.
- */
- if (!g_source_is_destroyed(&ctx->source)) {
- g_source_remove_poll(&ctx->source, &node->pfd);
- }
-
- /* If a read is in progress, just mark the node as deleted */
- if (qemu_lockcnt_count(&ctx->list_lock)) {
- node->deleted = 1;
- node->pfd.revents = 0;
- } else {
- /* Otherwise, delete it for real. We can't just mark it as
- * deleted because deleted nodes are only cleaned up while
- * no one is walking the handlers list.
- */
- QLIST_REMOVE(node, node);
- deleted = true;
- }
poll_disable_change = -!node->io_poll;
} else {
poll_disable_change = !io_poll - (node && !node->io_poll);
if (node == NULL) {
- /* Alloc and insert if it's not already there */
- node = g_new0(AioHandler, 1);
- node->pfd.fd = fd;
- QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
-
- g_source_add_poll(&ctx->source, &node->pfd);
is_new = true;
}
+ /* Alloc and insert if it's not already there */
+ new_node = g_new0(AioHandler, 1);
/* Update handler with latest information */
- node->io_read = io_read;
- node->io_write = io_write;
- node->io_poll = io_poll;
- node->opaque = opaque;
- node->is_external = is_external;
+ new_node->io_read = io_read;
+ new_node->io_write = io_write;
+ new_node->io_poll = io_poll;
+ new_node->opaque = opaque;
+ new_node->is_external = is_external;
+
+ if (is_new) {
+ new_node->pfd.fd = fd;
+ } else {
+ new_node->pfd = node->pfd;
+ }
+ g_source_add_poll(&ctx->source, &new_node->pfd);
+
+ new_node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
+ new_node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
- node->pfd.events = (io_read ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0);
- node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
+ QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, new_node, node);
+ }
+ if (node) {
+ deleted = aio_remove_fd_handler(ctx, node);
}
/* No need to order poll_disable_cnt writes against other updates;
@@ -278,7 +293,12 @@ void aio_set_fd_handler(AioContext *ctx,
atomic_set(&ctx->poll_disable_cnt,
atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
- aio_epoll_update(ctx, node, is_new);
+ if (new_node) {
+ aio_epoll_update(ctx, new_node, is_new);
+ } else if (node) {
+ /* Unregister deleted fd_handler */
+ aio_epoll_update(ctx, node, false);
+ }
qemu_lockcnt_unlock(&ctx->list_lock);
aio_notify(ctx);
diff --git a/util/aio-win32.c b/util/aio-win32.c
index c58957cc4b..a23b9c364d 100644
--- a/util/aio-win32.c
+++ b/util/aio-win32.c
@@ -35,6 +35,22 @@ struct AioHandler {
QLIST_ENTRY(AioHandler) node;
};
+static void aio_remove_fd_handler(AioContext *ctx, AioHandler *node)
+{
+ /* If aio_poll is in progress, just mark the node as deleted */
+ if (qemu_lockcnt_count(&ctx->list_lock)) {
+ node->deleted = 1;
+ node->pfd.revents = 0;
+ } else {
+ /* Otherwise, delete it for real. We can't just mark it as
+ * deleted because deleted nodes are only cleaned up after
+ * releasing the list_lock.
+ */
+ QLIST_REMOVE(node, node);
+ g_free(node);
+ }
+}
+
void aio_set_fd_handler(AioContext *ctx,
int fd,
bool is_external,
@@ -44,41 +60,23 @@ void aio_set_fd_handler(AioContext *ctx,
void *opaque)
{
/* fd is a SOCKET in our case */
- AioHandler *node;
+ AioHandler *old_node;
+ AioHandler *node = NULL;
qemu_lockcnt_lock(&ctx->list_lock);
- QLIST_FOREACH(node, &ctx->aio_handlers, node) {
- if (node->pfd.fd == fd && !node->deleted) {
+ QLIST_FOREACH(old_node, &ctx->aio_handlers, node) {
+ if (old_node->pfd.fd == fd && !old_node->deleted) {
break;
}
}
- /* Are we deleting the fd handler? */
- if (!io_read && !io_write) {
- if (node) {
- /* If aio_poll is in progress, just mark the node as deleted */
- if (qemu_lockcnt_count(&ctx->list_lock)) {
- node->deleted = 1;
- node->pfd.revents = 0;
- } else {
- /* Otherwise, delete it for real. We can't just mark it as
- * deleted because deleted nodes are only cleaned up after
- * releasing the list_lock.
- */
- QLIST_REMOVE(node, node);
- g_free(node);
- }
- }
- } else {
+ if (io_read || io_write) {
HANDLE event;
long bitmask = 0;
- if (node == NULL) {
- /* Alloc and insert if it's not already there */
- node = g_new0(AioHandler, 1);
- node->pfd.fd = fd;
- QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
- }
+ /* Alloc and insert if it's not already there */
+ node = g_new0(AioHandler, 1);
+ node->pfd.fd = fd;
node->pfd.events = 0;
if (node->io_read) {
@@ -104,9 +102,13 @@ void aio_set_fd_handler(AioContext *ctx,
bitmask |= FD_WRITE | FD_CONNECT;
}
+ QLIST_INSERT_HEAD_RCU(&ctx->aio_handlers, node, node);
event = event_notifier_get_handle(&ctx->notifier);
WSAEventSelect(node->pfd.fd, event, bitmask);
}
+ if (old_node) {
+ aio_remove_fd_handler(ctx, old_node);
+ }
qemu_lockcnt_unlock(&ctx->list_lock);
aio_notify(ctx);
@@ -139,18 +141,7 @@ void aio_set_event_notifier(AioContext *ctx,
if (node) {
g_source_remove_poll(&ctx->source, &node->pfd);
- /* aio_poll is in progress, just mark the node as deleted */
- if (qemu_lockcnt_count(&ctx->list_lock)) {
- node->deleted = 1;
- node->pfd.revents = 0;
- } else {
- /* Otherwise, delete it for real. We can't just mark it as
- * deleted because deleted nodes are only cleaned up after
- * releasing the list_lock.
- */
- QLIST_REMOVE(node, node);
- g_free(node);
- }
+ aio_remove_fd_handler(ctx, node);
}
} else {
if (node == NULL) {
diff --git a/util/bitops.c b/util/bitops.c
index f2364015c4..3fe6b1c4f1 100644
--- a/util/bitops.c
+++ b/util/bitops.c
@@ -18,7 +18,7 @@
* Find the next set bit in a memory region.
*/
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
+ unsigned long offset)
{
const unsigned long *p = addr + BIT_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
@@ -83,7 +83,7 @@ found_middle:
* Linus' asm-alpha/bitops.h.
*/
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
+ unsigned long offset)
{
const unsigned long *p = addr + BIT_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
diff --git a/util/cutils.c b/util/cutils.c
index 698bd315bd..e098debdc0 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -203,23 +203,21 @@ static int64_t suffix_mul(char suffix, int64_t unit)
/*
* Convert string to bytes, allowing either B/b for bytes, K/k for KB,
* M/m for MB, G/g for GB or T/t for TB. End pointer will be returned
- * in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
+ * in *end, if not NULL. Return -ERANGE on overflow, and -EINVAL on
* other error.
*/
-static int do_strtosz(const char *nptr, char **end,
+static int do_strtosz(const char *nptr, const char **end,
const char default_suffix, int64_t unit,
uint64_t *result)
{
int retval;
- char *endptr;
+ const char *endptr;
unsigned char c;
int mul_required = 0;
double val, mul, integral, fraction;
- errno = 0;
- val = strtod(nptr, &endptr);
- if (isnan(val) || endptr == nptr || errno != 0) {
- retval = -EINVAL;
+ retval = qemu_strtod_finite(nptr, &endptr, &val);
+ if (retval) {
goto out;
}
fraction = modf(val, &integral);
@@ -259,17 +257,17 @@ out:
return retval;
}
-int qemu_strtosz(const char *nptr, char **end, uint64_t *result)
+int qemu_strtosz(const char *nptr, const char **end, uint64_t *result)
{
return do_strtosz(nptr, end, 'B', 1024, result);
}
-int qemu_strtosz_MiB(const char *nptr, char **end, uint64_t *result)
+int qemu_strtosz_MiB(const char *nptr, const char **end, uint64_t *result)
{
return do_strtosz(nptr, end, 'M', 1024, result);
}
-int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result)
+int qemu_strtosz_metric(const char *nptr, const char **end, uint64_t *result)
{
return do_strtosz(nptr, end, 'B', 1000, result);
}
@@ -280,6 +278,7 @@ int qemu_strtosz_metric(const char *nptr, char **end, uint64_t *result)
static int check_strtox_error(const char *nptr, char *ep,
const char **endptr, int libc_errno)
{
+ assert(ep >= nptr);
if (endptr) {
*endptr = ep;
}
@@ -327,6 +326,7 @@ int qemu_strtoi(const char *nptr, const char **endptr, int base,
char *ep;
long long lresult;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -379,6 +379,7 @@ int qemu_strtoui(const char *nptr, const char **endptr, int base,
char *ep;
long long lresult;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -435,6 +436,7 @@ int qemu_strtol(const char *nptr, const char **endptr, int base,
{
char *ep;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -477,6 +479,7 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base,
{
char *ep;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -504,6 +507,7 @@ int qemu_strtoi64(const char *nptr, const char **endptr, int base,
{
char *ep;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -527,6 +531,7 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base,
{
char *ep;
+ assert((unsigned) base <= 36 && base != 1);
if (!nptr) {
if (endptr) {
*endptr = nptr;
@@ -545,6 +550,71 @@ int qemu_strtou64(const char *nptr, const char **endptr, int base,
}
/**
+ * Convert string @nptr to a double.
+ *
+ * This is a wrapper around strtod() that is harder to misuse.
+ * Semantics of @nptr and @endptr match strtod() with differences
+ * noted below.
+ *
+ * @nptr may be null, and no conversion is performed then.
+ *
+ * If no conversion is performed, store @nptr in *@endptr and return
+ * -EINVAL.
+ *
+ * If @endptr is null, and the string isn't fully converted, return
+ * -EINVAL. This is the case when the pointer that would be stored in
+ * a non-null @endptr points to a character other than '\0'.
+ *
+ * If the conversion overflows, store +/-HUGE_VAL in @result, depending
+ * on the sign, and return -ERANGE.
+ *
+ * If the conversion underflows, store +/-0.0 in @result, depending on the
+ * sign, and return -ERANGE.
+ *
+ * Else store the converted value in @result, and return zero.
+ */
+int qemu_strtod(const char *nptr, const char **endptr, double *result)
+{
+ char *ep;
+
+ if (!nptr) {
+ if (endptr) {
+ *endptr = nptr;
+ }
+ return -EINVAL;
+ }
+
+ errno = 0;
+ *result = strtod(nptr, &ep);
+ return check_strtox_error(nptr, ep, endptr, errno);
+}
+
+/**
+ * Convert string @nptr to a finite double.
+ *
+ * Works like qemu_strtod(), except that "NaN" and "inf" are rejected
+ * with -EINVAL and no conversion is performed.
+ */
+int qemu_strtod_finite(const char *nptr, const char **endptr, double *result)
+{
+ double tmp;
+ int ret;
+
+ ret = qemu_strtod(nptr, endptr, &tmp);
+ if (!ret && !isfinite(tmp)) {
+ if (endptr) {
+ *endptr = nptr;
+ }
+ ret = -EINVAL;
+ }
+
+ if (ret != -EINVAL) {
+ *result = tmp;
+ }
+ return ret;
+}
+
+/**
* Searches for the first occurrence of 'c' in 's', and returns a pointer
* to the trailing null byte if none was found.
*/
@@ -594,6 +664,7 @@ int parse_uint(const char *s, unsigned long long *value, char **endptr,
char *endp = (char *)s;
unsigned long long val = 0;
+ assert((unsigned) base <= 36 && base != 1);
if (!s) {
r = -EINVAL;
goto out;
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 8d402c59d9..7905212a8b 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -53,6 +53,9 @@
*/
struct HBitmap {
+ /* Size of the bitmap, as requested in hbitmap_alloc. */
+ uint64_t orig_size;
+
/* Number of total bits in the bottom level. */
uint64_t size;
@@ -141,7 +144,7 @@ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
return cur;
}
-int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance)
+int64_t hbitmap_iter_next(HBitmapIter *hbi)
{
unsigned long cur = hbi->cur[HBITMAP_LEVELS - 1] &
hbi->hb->levels[HBITMAP_LEVELS - 1][hbi->pos];
@@ -154,12 +157,8 @@ int64_t hbitmap_iter_next(HBitmapIter *hbi, bool advance)
}
}
- if (advance) {
- /* The next call will resume work from the next bit. */
- hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
- } else {
- hbi->cur[HBITMAP_LEVELS - 1] = cur;
- }
+ /* The next call will resume work from the next bit. */
+ hbi->cur[HBITMAP_LEVELS - 1] = cur & (cur - 1);
item = ((uint64_t)hbi->pos << BITS_PER_LEVEL) + ctzl(cur);
return item << hbi->granularity;
@@ -192,16 +191,28 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first)
}
}
-int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start)
+int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start, uint64_t count)
{
size_t pos = (start >> hb->granularity) >> BITS_PER_LEVEL;
unsigned long *last_lev = hb->levels[HBITMAP_LEVELS - 1];
- uint64_t sz = hb->sizes[HBITMAP_LEVELS - 1];
unsigned long cur = last_lev[pos];
- unsigned start_bit_offset =
- (start >> hb->granularity) & (BITS_PER_LONG - 1);
+ unsigned start_bit_offset;
+ uint64_t end_bit, sz;
int64_t res;
+ if (start >= hb->orig_size || count == 0) {
+ return -1;
+ }
+
+ end_bit = count > hb->orig_size - start ?
+ hb->size :
+ ((start + count - 1) >> hb->granularity) + 1;
+ sz = (end_bit + BITS_PER_LONG - 1) >> BITS_PER_LEVEL;
+
+ /* There may be some zero bits in @cur before @start. We are not interested
+ * in them, let's set them.
+ */
+ start_bit_offset = (start >> hb->granularity) & (BITS_PER_LONG - 1);
cur |= (1UL << start_bit_offset) - 1;
assert((start >> hb->granularity) < hb->size);
@@ -218,7 +229,7 @@ int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start)
}
res = (pos << BITS_PER_LEVEL) + ctol(cur);
- if (res >= hb->size) {
+ if (res >= end_bit) {
return -1;
}
@@ -231,6 +242,45 @@ int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start)
return res;
}
+bool hbitmap_next_dirty_area(const HBitmap *hb, uint64_t *start,
+ uint64_t *count)
+{
+ HBitmapIter hbi;
+ int64_t firt_dirty_off, area_end;
+ uint32_t granularity = 1UL << hb->granularity;
+ uint64_t end;
+
+ if (*start >= hb->orig_size || *count == 0) {
+ return false;
+ }
+
+ end = *count > hb->orig_size - *start ? hb->orig_size : *start + *count;
+
+ hbitmap_iter_init(&hbi, hb, *start);
+ firt_dirty_off = hbitmap_iter_next(&hbi);
+
+ if (firt_dirty_off < 0 || firt_dirty_off >= end) {
+ return false;
+ }
+
+ if (firt_dirty_off + granularity >= end) {
+ area_end = end;
+ } else {
+ area_end = hbitmap_next_zero(hb, firt_dirty_off + granularity,
+ end - firt_dirty_off - granularity);
+ if (area_end < 0) {
+ area_end = end;
+ }
+ }
+
+ if (firt_dirty_off > *start) {
+ *start = firt_dirty_off;
+ }
+ *count = area_end - *start;
+
+ return true;
+}
+
bool hbitmap_empty(const HBitmap *hb)
{
return hb->count == 0;
@@ -652,6 +702,8 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity)
HBitmap *hb = g_new0(struct HBitmap, 1);
unsigned i;
+ hb->orig_size = size;
+
assert(granularity >= 0 && granularity < 64);
size = (size + (1ULL << granularity) - 1) >> granularity;
assert(size <= ((uint64_t)1 << HBITMAP_LOG_MAX_SIZE));
diff --git a/util/osdep.c b/util/osdep.c
index 1c8d1e2ee0..4b5dc7287d 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -470,8 +470,8 @@ void fips_set_state(bool requested)
#ifdef _FIPS_DEBUG
fprintf(stderr, "FIPS mode %s (requested %s)\n",
- (fips_enabled ? "enabled" : "disabled"),
- (requested ? "enabled" : "disabled"));
+ (fips_enabled ? "enabled" : "disabled"),
+ (requested ? "enabled" : "disabled"));
#endif
}
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index c1bee2a581..4ce1ba9ca4 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -233,14 +233,18 @@ void qemu_set_block(int fd)
{
int f;
f = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
+ assert(f != -1);
+ f = fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
+ assert(f != -1);
}
void qemu_set_nonblock(int fd)
{
int f;
f = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, f | O_NONBLOCK);
+ assert(f != -1);
+ f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
+ assert(f != -1);
}
int socket_set_fast_reuse(int fd)
diff --git a/util/qemu-option.c b/util/qemu-option.c
index de42e2a406..ef60af70fc 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -280,7 +280,7 @@ QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
{
QemuOpt *opt;
- QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
+ QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
if (strcmp(opt->name, name) != 0)
continue;
return opt;
@@ -379,7 +379,7 @@ bool qemu_opt_has_help_opt(QemuOpts *opts)
{
QemuOpt *opt;
- QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
+ QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
if (is_help_option(opt->name)) {
return true;
}
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8bd8bb64eb..9705051690 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -270,8 +270,8 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
/* create socket + bind/listen */
for (e = res; e != NULL; e = e->ai_next) {
getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
- uaddr,INET6_ADDRSTRLEN,uport,32,
- NI_NUMERICHOST | NI_NUMERICSERV);
+ uaddr,INET6_ADDRSTRLEN,uport,32,
+ NI_NUMERICHOST | NI_NUMERICSERV);
port_min = inet_getport(e);
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
diff --git a/util/qemu-thread-common.h b/util/qemu-thread-common.h
index a0ea7c0d92..2af6b12085 100644
--- a/util/qemu-thread-common.h
+++ b/util/qemu-thread-common.h
@@ -13,7 +13,6 @@
#ifndef QEMU_THREAD_COMMON_H
#define QEMU_THREAD_COMMON_H
-#include "qemu/typedefs.h"
#include "qemu/thread.h"
#include "trace.h"
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 865e476df5..1bf5e65dea 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -484,12 +484,16 @@ static void *qemu_thread_start(void *args)
void *arg = qemu_thread_args->arg;
void *r;
-#ifdef CONFIG_PTHREAD_SETNAME_NP
+#ifdef CONFIG_THREAD_SETNAME_BYTHREAD
/* Attempt to set the threads name; note that this is for debug, so
* we're not going to fail if we can't set it.
*/
if (name_threads && qemu_thread_args->name) {
+# if defined(CONFIG_PTHREAD_SETNAME_NP_W_TID)
pthread_setname_np(pthread_self(), qemu_thread_args->name);
+# elif defined(CONFIG_PTHREAD_SETNAME_NP_WO_TID)
+ pthread_setname_np(qemu_thread_args->name);
+# endif
}
#endif
g_free(qemu_thread_args->name);
@@ -520,6 +524,11 @@ void qemu_thread_create(QemuThread *thread, const char *name,
/* Leave signal handling to the iothread. */
sigfillset(&set);
+ /* Blocking the signals can result in undefined behaviour. */
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGFPE);
+ sigdelset(&set, SIGILL);
+ /* TODO avoid SIGBUS loss on macOS */
pthread_sigmask(SIG_SETMASK, &set, &oldset);
qemu_thread_args = g_new0(QemuThreadArgs, 1);
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 4a363ca675..572f88535d 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -11,10 +11,6 @@
*
*/
-#ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x0600
-#endif
-
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/thread.h"
diff --git a/util/qsp.c b/util/qsp.c
index a848b09c6d..410f1ba004 100644
--- a/util/qsp.c
+++ b/util/qsp.c
@@ -61,7 +61,7 @@
#include "qemu/timer.h"
#include "qemu/qht.h"
#include "qemu/rcu.h"
-#include "exec/tb-hash-xx.h"
+#include "qemu/xxhash.h"
enum QSPType {
QSP_MUTEX,
@@ -135,13 +135,13 @@ QemuCondWaitFunc qemu_cond_wait_func = qemu_cond_wait_impl;
* without it we still get a pretty unique hash.
*/
static inline
-uint32_t do_qsp_callsite_hash(const QSPCallSite *callsite, uint64_t a)
+uint32_t do_qsp_callsite_hash(const QSPCallSite *callsite, uint64_t ab)
{
- uint64_t b = (uint64_t)(uintptr_t)callsite->obj;
+ uint64_t cd = (uint64_t)(uintptr_t)callsite->obj;
uint32_t e = callsite->line;
uint32_t f = callsite->type;
- return tb_hash_func7(a, b, e, f, 0);
+ return qemu_xxhash6(ab, cd, e, f);
}
static inline
@@ -169,11 +169,11 @@ static uint32_t qsp_entry_no_thread_hash(const QSPEntry *entry)
static uint32_t qsp_entry_no_thread_obj_hash(const QSPEntry *entry)
{
const QSPCallSite *callsite = entry->callsite;
- uint64_t a = g_str_hash(callsite->file);
- uint64_t b = callsite->line;
+ uint64_t ab = g_str_hash(callsite->file);
+ uint64_t cd = callsite->line;
uint32_t e = callsite->type;
- return tb_hash_func7(a, b, e, 0, 0);
+ return qemu_xxhash5(ab, cd, e);
}
static bool qsp_callsite_cmp(const void *ap, const void *bp)
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
index cccc9cd42e..342d4a2285 100644
--- a/util/vfio-helpers.c
+++ b/util/vfio-helpers.c
@@ -348,7 +348,7 @@ static int qemu_vfio_init_pci(QEMUVFIOState *s, const char *device,
goto fail;
}
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < ARRAY_SIZE(s->bar_region_info); i++) {
ret = qemu_vfio_pci_init_bar(s, i, errp);
if (ret) {
goto fail;
diff --git a/vl.c b/vl.c
index a5ae5f23d2..bc9fbec654 100644
--- a/vl.c
+++ b/vl.c
@@ -61,7 +61,7 @@ int main(int argc, char **argv)
#include "hw/display/vga.h"
#include "hw/bt.h"
#include "sysemu/watchdog.h"
-#include "hw/smbios/smbios.h"
+#include "hw/firmware/smbios.h"
#include "hw/acpi/acpi.h"
#include "hw/xen/xen.h"
#include "hw/qdev.h"
@@ -191,7 +191,7 @@ int boot_menu;
bool boot_strict;
uint8_t *boot_splash_filedata;
size_t boot_splash_filedata_size;
-uint8_t qemu_extra_params_fw[2];
+bool wakeup_suspend_enabled;
int icount_align_option;
@@ -337,10 +337,10 @@ static QemuOptsList qemu_boot_opts = {
.type = QEMU_OPT_STRING,
}, {
.name = "splash-time",
- .type = QEMU_OPT_STRING,
+ .type = QEMU_OPT_NUMBER,
}, {
.name = "reboot-timeout",
- .type = QEMU_OPT_STRING,
+ .type = QEMU_OPT_NUMBER,
}, {
.name = "strict",
.type = QEMU_OPT_BOOL,
@@ -1529,7 +1529,7 @@ struct vm_change_state_entry {
QLIST_ENTRY (vm_change_state_entry) entries;
};
-static QLIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head;
+static QLIST_HEAD(, vm_change_state_entry) vm_change_state_head;
VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
void *opaque)
@@ -1576,6 +1576,8 @@ static NotifierList suspend_notifiers =
NOTIFIER_LIST_INITIALIZER(suspend_notifiers);
static NotifierList wakeup_notifiers =
NOTIFIER_LIST_INITIALIZER(wakeup_notifiers);
+static NotifierList shutdown_notifiers =
+ NOTIFIER_LIST_INITIALIZER(shutdown_notifiers);
static uint32_t wakeup_reason_mask = ~(1 << QEMU_WAKEUP_REASON_NONE);
ShutdownCause qemu_shutdown_requested_get(void)
@@ -1675,7 +1677,7 @@ void qemu_system_reset(ShutdownCause reason)
qemu_devices_reset();
}
if (reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
- qapi_event_send_reset(shutdown_caused_by_guest(reason));
+ qapi_event_send_reset(shutdown_caused_by_guest(reason), reason);
}
cpu_synchronize_all_post_reset();
}
@@ -1751,11 +1753,13 @@ void qemu_register_suspend_notifier(Notifier *notifier)
notifier_list_add(&suspend_notifiers, notifier);
}
-void qemu_system_wakeup_request(WakeupReason reason)
+void qemu_system_wakeup_request(WakeupReason reason, Error **errp)
{
trace_system_wakeup_request(reason);
if (!runstate_check(RUN_STATE_SUSPENDED)) {
+ error_setg(errp,
+ "Unable to wake up: guest is not in suspended state");
return;
}
if (!(wakeup_reason_mask & (1 << reason))) {
@@ -1780,6 +1784,24 @@ void qemu_register_wakeup_notifier(Notifier *notifier)
notifier_list_add(&wakeup_notifiers, notifier);
}
+void qemu_register_wakeup_support(void)
+{
+ wakeup_suspend_enabled = true;
+}
+
+bool qemu_wakeup_suspend_enabled(void)
+{
+ return wakeup_suspend_enabled;
+}
+
+CurrentMachineParams *qmp_query_current_machine(Error **errp)
+{
+ CurrentMachineParams *params = g_malloc0(sizeof(*params));
+ params->wakeup_suspend_support = qemu_wakeup_suspend_enabled();
+
+ return params;
+}
+
void qemu_system_killed(int signal, pid_t pid)
{
shutdown_signal = signal;
@@ -1807,6 +1829,12 @@ static void qemu_system_powerdown(void)
notifier_list_notify(&powerdown_notifiers, NULL);
}
+static void qemu_system_shutdown(ShutdownCause cause)
+{
+ qapi_event_send_shutdown(shutdown_caused_by_guest(cause), cause);
+ notifier_list_notify(&shutdown_notifiers, &cause);
+}
+
void qemu_system_powerdown_request(void)
{
trace_qemu_system_powerdown_request();
@@ -1819,6 +1847,11 @@ void qemu_register_powerdown_notifier(Notifier *notifier)
notifier_list_add(&powerdown_notifiers, notifier);
}
+void qemu_register_shutdown_notifier(Notifier *notifier)
+{
+ notifier_list_add(&shutdown_notifiers, notifier);
+}
+
void qemu_system_debug_request(void)
{
debug_requested = 1;
@@ -1846,7 +1879,7 @@ static bool main_loop_should_exit(void)
request = qemu_shutdown_requested();
if (request) {
qemu_kill_report();
- qapi_event_send_shutdown(shutdown_caused_by_guest(request));
+ qemu_system_shutdown(request);
if (no_shutdown) {
vm_stop(RUN_STATE_SHUTDOWN);
} else {
@@ -2322,11 +2355,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
if (qemu_opt_get_bool(opts, "pretty", 0))
flags |= MONITOR_USE_PRETTY;
- /* OOB is off by default */
- if (qemu_opt_get_bool(opts, "x-oob", 0)) {
- flags |= MONITOR_USE_OOB;
- }
-
chardev = qemu_opt_get(opts, "chardev");
if (!chardev) {
error_report("chardev is required");
@@ -2936,8 +2964,6 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
g->driver = qemu_opt_get(opts, "driver");
g->property = qemu_opt_get(opts, "property");
g->value = qemu_opt_get(opts, "value");
- g->user_provided = true;
- g->errp = &error_fatal;
qdev_prop_register_global(g);
return 0;
}
@@ -2968,8 +2994,6 @@ static void user_register_global_props(void)
*/
static void register_global_properties(MachineState *ms)
{
- accel_register_compat_props(ms->accelerator);
- machine_register_compat_props(ms);
user_register_global_props();
}
@@ -3138,11 +3162,8 @@ int main(int argc, char **argv, char **envp)
Visitor *v;
BlockdevOptions_queue *bdo;
- v = qobject_input_visitor_new_str(optarg, "driver", &err);
- if (!v) {
- error_report_err(err);
- exit(1);
- }
+ v = qobject_input_visitor_new_str(optarg, "driver",
+ &error_fatal);
bdo = g_new(BlockdevOptions_queue, 1);
visit_type_BlockdevOptions(v, NULL, &bdo->bdo,
@@ -3835,13 +3856,6 @@ int main(int argc, char **argv, char **envp)
}
xen_domid = atoi(optarg);
break;
- case QEMU_OPTION_xen_create:
- if (!(xen_available())) {
- error_report("Option not supported for this target");
- exit(1);
- }
- xen_mode = XEN_CREATE;
- break;
case QEMU_OPTION_xen_attach:
if (!(xen_available())) {
error_report("Option not supported for this target");
@@ -4308,7 +4322,7 @@ int main(int argc, char **argv, char **envp)
qemu_opt_foreach(machine_opts, machine_set_property, current_machine,
&error_fatal);
- configure_accelerator(current_machine);
+ configure_accelerator(current_machine, argv[0]);
if (!qtest_enabled() && machine_class->deprecation_reason) {
error_report("Machine type '%s' is deprecated: %s",