summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml4
-rw-r--r--.gitlab-ci.d/containers.yml87
-rw-r--r--.gitlab-ci.yml124
-rw-r--r--MAINTAINERS84
-rw-r--r--Makefile2
-rw-r--r--accel/accel-common.c32
-rw-r--r--accel/tcg/tcg-runtime-gvec.c36
-rw-r--r--accel/tcg/translate-all.c11
-rw-r--r--backends/tpm/tpm_emulator.c34
-rw-r--r--block.c10
-rw-r--r--block/backup.c2
-rw-r--r--block/copy-on-read.c33
-rw-r--r--block/export/vhost-user-blk-server.c9
-rw-r--r--block/io.c11
-rw-r--r--block/meson.build1
-rw-r--r--block/mirror.c6
-rw-r--r--block/monitor/block-hmp-cmds.c31
-rw-r--r--block/qcow2.c1
-rw-r--r--block/rbd.c32
-rw-r--r--block/sheepdog.c3356
-rw-r--r--block/trace-events14
-rw-r--r--block/write-threshold.c91
-rw-r--r--bsd-user/main.c2
-rwxr-xr-xconfigure40
-rw-r--r--contrib/vhost-user-input/main.c8
-rw-r--r--cpu.c5
-rw-r--r--default-configs/devices/lm32-softmmu.mak12
-rw-r--r--default-configs/devices/moxie-softmmu.mak5
-rw-r--r--default-configs/devices/riscv64-softmmu.mak1
-rw-r--r--default-configs/devices/unicore32-softmmu.mak6
-rw-r--r--default-configs/targets/lm32-softmmu.mak2
-rw-r--r--default-configs/targets/moxie-softmmu.mak2
-rw-r--r--default-configs/targets/sparc64-linux-user.mak1
-rw-r--r--default-configs/targets/unicore32-softmmu.mak1
-rw-r--r--disas/lm32.c361
-rw-r--r--disas/meson.build2
-rw-r--r--disas/moxie.c360
-rw-r--r--docs/_templates/editpage.html5
-rw-r--r--docs/conf.py52
-rw-r--r--docs/devel/_templates/editpage.html5
-rw-r--r--docs/devel/qgraph.rst58
-rw-r--r--docs/interop/_templates/editpage.html5
-rw-r--r--docs/meson.build5
-rw-r--r--docs/specs/_templates/editpage.html5
-rw-r--r--docs/sphinx-static/theme_overrides.css161
-rw-r--r--docs/system/_templates/editpage.html5
-rw-r--r--docs/system/deprecated.rst33
-rw-r--r--docs/system/device-url-syntax.rst.inc18
-rw-r--r--docs/system/generic-loader.rst9
-rw-r--r--docs/system/qemu-block-drivers.rst.inc69
-rw-r--r--docs/system/removed-features.rst28
-rw-r--r--docs/system/riscv/shakti-c.rst82
-rw-r--r--docs/system/target-riscv.rst1
-rw-r--r--docs/tools/_templates/editpage.html5
-rw-r--r--docs/tools/qemu-img.rst31
-rw-r--r--docs/user/_templates/editpage.html5
-rw-r--r--fpu/softfloat-parts-addsub.c.inc62
-rw-r--r--fpu/softfloat-parts.c.inc817
-rw-r--r--fpu/softfloat-specialize.c.inc101
-rw-r--r--fpu/softfloat.c3625
-rw-r--r--hw/Kconfig4
-rw-r--r--hw/acpi/aml-build.c15
-rw-r--r--hw/arm/virt.c7
-rw-r--r--hw/audio/meson.build1
-rw-r--r--hw/audio/milkymist-ac97.c360
-rw-r--r--hw/audio/trace-events12
-rw-r--r--hw/avr/atmega.c2
-rw-r--r--hw/block/Kconfig5
-rw-r--r--hw/block/dataplane/virtio-blk.c36
-rw-r--r--hw/block/meson.build1
-rw-r--r--hw/block/nvme-dif.h63
-rw-r--r--hw/block/nvme-ns.h229
-rw-r--r--hw/block/nvme-subsys.h59
-rw-r--r--hw/block/nvme.h266
-rw-r--r--hw/block/pflash_cfi02.c10
-rw-r--r--hw/block/trace-events206
-rw-r--r--hw/block/vhost-user-blk.c85
-rw-r--r--hw/block/virtio-blk.c2
-rw-r--r--hw/block/xen-block.c14
-rw-r--r--hw/char/lm32_juart.c166
-rw-r--r--hw/char/lm32_uart.c314
-rw-r--r--hw/char/meson.build4
-rw-r--r--hw/char/milkymist-uart.c258
-rw-r--r--hw/char/shakti_uart.c185
-rw-r--r--hw/char/trace-events21
-rw-r--r--hw/core/machine.c1
-rw-r--r--hw/core/numa.c41
-rw-r--r--hw/display/Kconfig4
-rw-r--r--hw/display/edid-generate.c214
-rw-r--r--hw/display/meson.build21
-rw-r--r--hw/display/milkymist-tmu2.c551
-rw-r--r--hw/display/milkymist-vgafb.c360
-rw-r--r--hw/display/milkymist-vgafb_template.h74
-rw-r--r--hw/display/trace-events10
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vga.c2
-rw-r--r--hw/display/virtio-gpu-base.c6
-rw-r--r--hw/display/virtio-gpu-gl.c163
-rw-r--r--hw/display/virtio-gpu-pci-gl.c55
-rw-r--r--hw/display/virtio-gpu-virgl.c (renamed from hw/display/virtio-gpu-3d.c)7
-rw-r--r--hw/display/virtio-gpu.c218
-rw-r--r--hw/display/virtio-vga-gl.c47
-rw-r--r--hw/dma/meson.build1
-rw-r--r--hw/dma/puv3_dma.c119
-rw-r--r--hw/gpio/aspeed_gpio.c2
-rw-r--r--hw/gpio/meson.build1
-rw-r--r--hw/gpio/puv3_gpio.c154
-rw-r--r--hw/i2c/Kconfig4
-rw-r--r--hw/i2c/core.c55
-rw-r--r--hw/i2c/i2c_mux_pca954x.c290
-rw-r--r--hw/i2c/meson.build1
-rw-r--r--hw/i2c/trace-events5
-rw-r--r--hw/i386/acpi-build.c8
-rw-r--r--hw/i386/amd_iommu.c10
-rw-r--r--hw/i386/fw_cfg.c4
-rw-r--r--hw/i386/pc_piix.c1
-rw-r--r--hw/i386/xen/xen-hvm.c9
-rw-r--r--hw/i386/xen/xen-mapcache.c22
-rw-r--r--hw/input/meson.build1
-rw-r--r--hw/input/milkymist-softusb.c319
-rw-r--r--hw/input/trace-events7
-rw-r--r--hw/input/virtio-input-host.c5
-rw-r--r--hw/intc/ibex_plic.c20
-rw-r--r--hw/intc/lm32_pic.c195
-rw-r--r--hw/intc/meson.build2
-rw-r--r--hw/intc/puv3_intc.c147
-rw-r--r--hw/intc/trace-events9
-rw-r--r--hw/lm32/Kconfig18
-rw-r--r--hw/lm32/lm32.h48
-rw-r--r--hw/lm32/lm32_boards.c332
-rw-r--r--hw/lm32/lm32_hwsetup.h179
-rw-r--r--hw/lm32/meson.build6
-rw-r--r--hw/lm32/milkymist-hw.h133
-rw-r--r--hw/lm32/milkymist.c249
-rw-r--r--hw/mem/meson.build3
-rw-r--r--hw/mem/pc-dimm.c33
-rw-r--r--hw/meson.build4
-rw-r--r--hw/misc/meson.build4
-rw-r--r--hw/misc/milkymist-hpdmc.c172
-rw-r--r--hw/misc/milkymist-pfpu.c548
-rw-r--r--hw/misc/puv3_pm.c159
-rw-r--r--hw/misc/trace-events10
-rw-r--r--hw/moxie/Kconfig3
-rw-r--r--hw/moxie/meson.build4
-rw-r--r--hw/moxie/moxiesim.c155
-rw-r--r--hw/net/meson.build1
-rw-r--r--hw/net/milkymist-minimac2.c547
-rw-r--r--hw/net/trace-events12
-rw-r--r--hw/net/virtio-net.c2
-rw-r--r--hw/nvme/Kconfig4
-rw-r--r--hw/nvme/ctrl.c (renamed from hw/block/nvme.c)298
-rw-r--r--hw/nvme/dif.c (renamed from hw/block/nvme-dif.c)57
-rw-r--r--hw/nvme/meson.build1
-rw-r--r--hw/nvme/ns.c (renamed from hw/block/nvme-ns.c)106
-rw-r--r--hw/nvme/nvme.h547
-rw-r--r--hw/nvme/subsys.c (renamed from hw/block/nvme-subsys.c)12
-rw-r--r--hw/nvme/trace-events204
-rw-r--r--hw/nvme/trace.h1
-rw-r--r--hw/pci-host/meson.build2
-rw-r--r--hw/ppc/meson.build3
-rw-r--r--hw/ppc/pnv.c2
-rw-r--r--hw/ppc/spapr.c21
-rw-r--r--hw/ppc/spapr_caps.c59
-rw-r--r--hw/ppc/spapr_hcall.c634
-rw-r--r--hw/ppc/spapr_softmmu.c627
-rw-r--r--hw/remote/mpqemu-link.c2
-rw-r--r--hw/riscv/Kconfig11
-rw-r--r--hw/riscv/meson.build1
-rw-r--r--hw/riscv/opentitan.c10
-rw-r--r--hw/riscv/shakti_c.c181
-rw-r--r--hw/riscv/sifive_e.c2
-rw-r--r--hw/rtc/mc146818rtc.c42
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c56
-rw-r--r--hw/sd/meson.build1
-rw-r--r--hw/sd/milkymist-memcard.c335
-rw-r--r--hw/sd/trace-events4
-rw-r--r--hw/smbios/smbios.c124
-rw-r--r--hw/timer/etraxfs_timer.c14
-rw-r--r--hw/timer/lm32_timer.c249
-rw-r--r--hw/timer/meson.build3
-rw-r--r--hw/timer/milkymist-sysctl.c361
-rw-r--r--hw/timer/puv3_ost.c166
-rw-r--r--hw/timer/trace-events17
-rw-r--r--hw/tricore/meson.build1
-rw-r--r--hw/tricore/tricore_testboard.c8
-rw-r--r--hw/tricore/tricore_testdevice.c82
-rw-r--r--hw/unicore32/Kconfig5
-rw-r--r--hw/unicore32/meson.build5
-rw-r--r--hw/unicore32/puv3.c145
-rw-r--r--hw/usb/quirks-ftdi-ids.h6
-rw-r--r--hw/usb/quirks.h1
-rw-r--r--hw/virtio/vhost-user.c5
-rw-r--r--hw/virtio/vhost-vdpa.c4
-rw-r--r--hw/virtio/virtio-balloon.c4
-rw-r--r--hw/virtio/virtio-bus.c5
-rw-r--r--hw/virtio/virtio-mem.c3
-rw-r--r--hw/virtio/virtio-mmio.c11
-rw-r--r--hw/virtio/virtio.c2
-rw-r--r--include/block/block_int.h15
-rw-r--r--include/block/nvme.h12
-rw-r--r--include/block/write-threshold.h27
-rw-r--r--include/disas/dis-asm.h4
-rw-r--r--include/elf.h6
-rw-r--r--include/exec/cpu-common.h1
-rw-r--r--include/exec/gen-icount.h1
-rw-r--r--include/exec/memory.h10
-rw-r--r--include/exec/poison.h11
-rw-r--r--include/exec/ramblock.h10
-rw-r--r--include/exec/ramlist.h13
-rw-r--r--include/fpu/softfloat-macros.h215
-rw-r--r--include/fpu/softfloat.h7
-rw-r--r--include/hw/char/lm32_juart.h13
-rw-r--r--include/hw/char/shakti_uart.h74
-rw-r--r--include/hw/core/accel-cpu.h2
-rw-r--r--include/hw/core/cpu.h6
-rw-r--r--include/hw/display/edid.h12
-rw-r--r--include/hw/display/milkymist_tmu2.h42
-rw-r--r--include/hw/display/vga.h6
-rw-r--r--include/hw/elf_ops.h8
-rw-r--r--include/hw/firmware/smbios.h14
-rw-r--r--include/hw/i2c/i2c.h17
-rw-r--r--include/hw/i2c/i2c_mux_pca954x.h19
-rw-r--r--include/hw/lm32/lm32_pic.h10
-rw-r--r--include/hw/mem/pc-dimm.h5
-rw-r--r--include/hw/ppc/spapr.h7
-rw-r--r--include/hw/riscv/opentitan.h16
-rw-r--r--include/hw/riscv/shakti_c.h75
-rw-r--r--include/hw/tricore/tricore_testdevice.h38
-rw-r--r--include/hw/unicore32/puv3.h40
-rw-r--r--include/hw/virtio/vhost-vdpa.h2
-rw-r--r--include/hw/virtio/vhost.h2
-rw-r--r--include/hw/virtio/virtio-gpu.h34
-rw-r--r--include/hw/virtio/virtio-mmio.h5
-rw-r--r--include/hw/virtio/virtio.h2
-rw-r--r--include/hw/xen/xen_common.h6
-rw-r--r--include/migration/misc.h1
-rw-r--r--include/qemu/accel.h13
-rw-r--r--include/qemu/host-utils.h291
-rw-r--r--include/qemu/job.h2
-rw-r--r--include/qemu/main-loop.h18
-rw-r--r--include/sysemu/arch_init.h3
-rw-r--r--include/sysemu/hax.h4
-rw-r--r--include/sysemu/hvf.h4
-rw-r--r--include/sysemu/whpx.h4
-rw-r--r--include/tcg/tcg-op.h2
-rw-r--r--job.c2
-rw-r--r--linux-user/aarch64/signal.c6
-rw-r--r--linux-user/alpha/signal.c16
-rw-r--r--linux-user/alpha/target_signal.h1
-rw-r--r--linux-user/arm/cpu_loop.c125
-rw-r--r--linux-user/arm/signal.c9
-rw-r--r--linux-user/elfload.c107
-rw-r--r--linux-user/hexagon/signal.c6
-rw-r--r--linux-user/hppa/signal.c8
-rw-r--r--linux-user/i386/signal.c5
-rw-r--r--linux-user/m68k/signal.c5
-rw-r--r--linux-user/main.c7
-rw-r--r--linux-user/meson.build1
-rw-r--r--linux-user/microblaze/signal.c6
-rw-r--r--linux-user/mips/signal.c6
-rw-r--r--linux-user/nios2/signal.c8
-rw-r--r--linux-user/openrisc/signal.c5
-rw-r--r--linux-user/ppc/cpu_loop.c6
-rw-r--r--linux-user/ppc/signal.c4
-rw-r--r--linux-user/qemu.h3
-rw-r--r--linux-user/riscv/signal.c6
-rw-r--r--linux-user/s390x/signal.c258
-rw-r--r--linux-user/sh4/signal.c7
-rw-r--r--linux-user/signal-common.h1
-rw-r--r--linux-user/signal.c125
-rw-r--r--linux-user/sparc/signal.c535
-rw-r--r--linux-user/sparc/target_cpu.h9
-rw-r--r--linux-user/sparc/target_signal.h2
-rw-r--r--linux-user/sparc/target_structs.h34
-rw-r--r--linux-user/sparc/target_syscall.h42
-rw-r--r--linux-user/sparc64/cpu_loop.c20
-rw-r--r--linux-user/sparc64/meson.build5
-rw-r--r--linux-user/sparc64/signal.c19
-rw-r--r--linux-user/sparc64/sockbits.h1
-rw-r--r--linux-user/sparc64/syscall.tbl487
-rw-r--r--linux-user/sparc64/syscallhdr.sh32
-rw-r--r--linux-user/sparc64/target_cpu.h1
-rw-r--r--linux-user/sparc64/target_elf.h14
-rw-r--r--linux-user/sparc64/target_fcntl.h1
-rw-r--r--linux-user/sparc64/target_signal.h1
-rw-r--r--linux-user/sparc64/target_structs.h58
-rw-r--r--linux-user/sparc64/target_syscall.h35
-rw-r--r--linux-user/sparc64/termbits.h291
-rw-r--r--linux-user/strace.c21
-rw-r--r--linux-user/strace.list8
-rw-r--r--linux-user/syscall.c113
-rw-r--r--linux-user/syscall_defs.h29
-rw-r--r--linux-user/xtensa/signal.c6
-rw-r--r--meson.build6
-rw-r--r--migration/meson.build3
-rw-r--r--migration/migration.c53
-rw-r--r--migration/migration.h3
-rw-r--r--migration/multifd.c2
-rw-r--r--migration/postcopy-ram.c15
-rw-r--r--migration/ram.c246
-rw-r--r--migration/target.c25
-rw-r--r--monitor/hmp-cmds.c2
-rw-r--r--monitor/qmp.c40
-rw-r--r--pc-bios/s390-ccw.imgbin42608 -> 50936 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile8
-rw-r--r--pc-bios/s390-ccw/bootmap.c4
-rw-r--r--pc-bios/s390-ccw/helper.h2
-rw-r--r--pc-bios/s390-ccw/jump2ipl.c8
-rw-r--r--pc-bios/s390-ccw/menu.c8
-rw-r--r--pc-bios/s390-ccw/netboot.mak2
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h1
-rw-r--r--pc-bios/s390-ccw/virtio.c2
-rw-r--r--pc-bios/s390-netboot.imgbin67232 -> 79688 bytes
-rw-r--r--qapi/block-core.json93
-rw-r--r--qapi/machine.json6
-rw-r--r--qapi/migration.json6
-rw-r--r--qapi/misc-target.json2
-rw-r--r--qapi/qom.json4
-rw-r--r--qapi/transaction.json8
-rw-r--r--qemu-edid.c6
-rw-r--r--qemu-io-cmds.c8
-rw-r--r--qemu-io.c17
-rw-r--r--qemu-options.hx34
-rwxr-xr-xscripts/checkpatch.pl1
-rw-r--r--scripts/coverity-scan/COMPONENTS.md154
-rw-r--r--scripts/coverity-scan/model.c (renamed from scripts/coverity-model.c)0
-rw-r--r--softmmu/arch_init.c6
-rw-r--r--softmmu/physmem.c26
-rw-r--r--softmmu/vl.c1
-rw-r--r--target/avr/helper.c6
-rw-r--r--target/i386/cpu-internal.h70
-rw-r--r--target/i386/cpu-sysemu.c352
-rw-r--r--target/i386/cpu.c775
-rw-r--r--target/i386/cpu.h67
-rw-r--r--target/i386/gdbstub.c165
-rw-r--r--target/i386/hax/hax-mem.c5
-rw-r--r--target/i386/helper.c13
-rw-r--r--target/i386/helper.h48
-rw-r--r--target/i386/host-cpu.c204
-rw-r--r--target/i386/host-cpu.h19
-rw-r--r--target/i386/hvf/hvf-cpu.c68
-rw-r--r--target/i386/hvf/meson.build1
-rw-r--r--target/i386/kvm/kvm-cpu.c151
-rw-r--r--target/i386/kvm/kvm-cpu.h41
-rw-r--r--target/i386/kvm/kvm.c3
-rw-r--r--target/i386/kvm/meson.build7
-rw-r--r--target/i386/meson.build9
-rw-r--r--target/i386/sev.c18
-rw-r--r--target/i386/svm.h10
-rw-r--r--target/i386/tcg/bpt_helper.c278
-rw-r--r--target/i386/tcg/excp_helper.c591
-rw-r--r--target/i386/tcg/fpu_helper.c106
-rw-r--r--target/i386/tcg/helper-tcg.h13
-rw-r--r--target/i386/tcg/meson.build5
-rw-r--r--target/i386/tcg/misc_helper.c544
-rw-r--r--target/i386/tcg/seg_helper.c280
-rw-r--r--target/i386/tcg/seg_helper.h66
-rw-r--r--target/i386/tcg/sysemu/bpt_helper.c293
-rw-r--r--target/i386/tcg/sysemu/excp_helper.c471
-rw-r--r--target/i386/tcg/sysemu/fpu_helper.c57
-rw-r--r--target/i386/tcg/sysemu/meson.build10
-rw-r--r--target/i386/tcg/sysemu/misc_helper.c490
-rw-r--r--target/i386/tcg/sysemu/seg_helper.c154
-rw-r--r--target/i386/tcg/sysemu/smm_helper.c (renamed from target/i386/tcg/smm_helper.c)19
-rw-r--r--target/i386/tcg/sysemu/svm_helper.c (renamed from target/i386/tcg/svm_helper.c)105
-rw-r--r--target/i386/tcg/sysemu/tcg-cpu.c83
-rw-r--r--target/i386/tcg/tcg-cpu.c56
-rw-r--r--target/i386/tcg/tcg-cpu.h21
-rw-r--r--target/i386/tcg/translate.c892
-rw-r--r--target/i386/tcg/user/excp_helper.c39
-rw-r--r--target/i386/tcg/user/meson.build4
-rw-r--r--target/i386/tcg/user/seg_helper.c109
-rw-r--r--target/lm32/README45
-rw-r--r--target/lm32/TODO1
-rw-r--r--target/lm32/cpu-param.h17
-rw-r--r--target/lm32/cpu-qom.h48
-rw-r--r--target/lm32/cpu.c274
-rw-r--r--target/lm32/cpu.h262
-rw-r--r--target/lm32/gdbstub.c92
-rw-r--r--target/lm32/helper.c224
-rw-r--r--target/lm32/helper.h14
-rw-r--r--target/lm32/lm32-semi.c211
-rw-r--r--target/lm32/machine.c33
-rw-r--r--target/lm32/meson.build15
-rw-r--r--target/lm32/op_helper.c148
-rw-r--r--target/lm32/translate.c1237
-rw-r--r--target/meson.build3
-rw-r--r--target/mips/fpu_helper.h10
-rw-r--r--target/moxie/cpu-param.h17
-rw-r--r--target/moxie/cpu.c161
-rw-r--r--target/moxie/cpu.h123
-rw-r--r--target/moxie/helper.c120
-rw-r--r--target/moxie/helper.h5
-rw-r--r--target/moxie/machine.c19
-rw-r--r--target/moxie/machine.h1
-rw-r--r--target/moxie/meson.build14
-rw-r--r--target/moxie/mmu.c32
-rw-r--r--target/moxie/mmu.h19
-rw-r--r--target/moxie/translate.c892
-rw-r--r--target/ppc/arch_dump.c3
-rw-r--r--target/ppc/cpu.c47
-rw-r--r--target/ppc/cpu.h13
-rw-r--r--target/ppc/cpu_init.c (renamed from target/ppc/translate_init.c.inc)2034
-rw-r--r--target/ppc/gdbstub.c4
-rw-r--r--target/ppc/helper.h4
-rw-r--r--target/ppc/int_helper.c9
-rw-r--r--target/ppc/internal.h19
-rw-r--r--target/ppc/machine.c7
-rw-r--r--target/ppc/meson.build1
-rw-r--r--target/ppc/misc_helper.c10
-rw-r--r--target/ppc/mmu-hash32.c59
-rw-r--r--target/ppc/mmu-hash64.c136
-rw-r--r--target/ppc/mmu-hash64.h4
-rw-r--r--target/ppc/mmu-radix64.c123
-rw-r--r--target/ppc/mmu_helper.c325
-rw-r--r--target/ppc/spr_tcg.h136
-rw-r--r--target/ppc/translate.c1507
-rw-r--r--target/ppc/translate/vsx-impl.c.inc4
-rw-r--r--target/riscv/cpu.c26
-rw-r--r--target/riscv/cpu.h42
-rw-r--r--target/riscv/cpu_bits.h114
-rw-r--r--target/riscv/cpu_helper.c88
-rw-r--r--target/riscv/csr.c824
-rw-r--r--target/riscv/fpu_helper.c16
-rw-r--r--target/riscv/gdbstub.c8
-rw-r--r--target/riscv/helper.h18
-rw-r--r--target/riscv/insn16-32.decode28
-rw-r--r--target/riscv/insn16-64.decode36
-rw-r--r--target/riscv/insn16.decode30
-rw-r--r--target/riscv/insn32-64.decode88
-rw-r--r--target/riscv/insn32.decode67
-rw-r--r--target/riscv/insn_trans/trans_rva.c.inc14
-rw-r--r--target/riscv/insn_trans/trans_rvd.c.inc17
-rw-r--r--target/riscv/insn_trans/trans_rvf.c.inc6
-rw-r--r--target/riscv/insn_trans/trans_rvh.c.inc8
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc22
-rw-r--r--target/riscv/insn_trans/trans_rvm.c.inc12
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc39
-rw-r--r--target/riscv/machine.c8
-rw-r--r--target/riscv/meson.build13
-rw-r--r--target/riscv/monitor.c22
-rw-r--r--target/riscv/op_helper.c18
-rw-r--r--target/riscv/pmp.c218
-rw-r--r--target/riscv/pmp.h14
-rw-r--r--target/riscv/trace-events3
-rw-r--r--target/riscv/translate.c38
-rw-r--r--target/riscv/vector_helper.c18
-rw-r--r--target/sh4/helper.c7
-rw-r--r--target/unicore32/cpu-param.h17
-rw-r--r--target/unicore32/cpu-qom.h37
-rw-r--r--target/unicore32/cpu.c174
-rw-r--r--target/unicore32/cpu.h168
-rw-r--r--target/unicore32/helper.c183
-rw-r--r--target/unicore32/helper.h62
-rw-r--r--target/unicore32/meson.build14
-rw-r--r--target/unicore32/op_helper.c244
-rw-r--r--target/unicore32/softmmu.c280
-rw-r--r--target/unicore32/translate.c2083
-rw-r--r--target/unicore32/ucf64_helper.c324
-rw-r--r--tests/docker/Makefile.include29
-rwxr-xr-xtests/docker/docker.py78
-rw-r--r--tests/docker/dockerfiles/alpine.docker3
-rw-r--r--tests/docker/dockerfiles/centos8.docker1
-rw-r--r--tests/docker/dockerfiles/debian-hexagon-cross.docker45
-rwxr-xr-xtests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh141
-rw-r--r--tests/docker/dockerfiles/debian-powerpc-cross.docker12
-rw-r--r--tests/docker/dockerfiles/debian-powerpc-test-cross.docker17
-rw-r--r--tests/docker/dockerfiles/debian-ppc64-cross.docker11
-rw-r--r--tests/docker/dockerfiles/debian10.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-i386-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-win32-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-win64-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora.docker2
-rw-r--r--tests/docker/dockerfiles/opensuse-leap.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu1804.docker1
-rw-r--r--tests/docker/dockerfiles/ubuntu2004.docker1
-rw-r--r--tests/fp/fp-bench.c88
-rw-r--r--tests/fp/fp-test.c2
-rw-r--r--tests/fp/wrap.c.inc12
-rw-r--r--tests/migration/guestperf/comparison.py14
-rw-r--r--tests/migration/guestperf/engine.py16
-rw-r--r--tests/migration/guestperf/scenario.py12
-rw-r--r--tests/migration/guestperf/shell.py10
-rwxr-xr-xtests/qemu-iotests/0055
-rwxr-xr-xtests/qemu-iotests/0252
-rwxr-xr-xtests/qemu-iotests/2314
-rw-r--r--tests/qemu-iotests/231.out7
-rw-r--r--tests/qemu-iotests/240.out8
-rw-r--r--tests/qemu-iotests/245.out8
-rwxr-xr-xtests/qemu-iotests/2642
-rw-r--r--tests/qemu-iotests/295.out6
-rw-r--r--tests/qemu-iotests/296.out8
-rwxr-xr-xtests/qemu-iotests/check22
-rw-r--r--tests/qemu-iotests/common.rc4
-rw-r--r--tests/qemu-iotests/iotests.py145
-rw-r--r--tests/qemu-iotests/pylintrc3
-rw-r--r--tests/qemu-iotests/testenv.py22
-rw-r--r--tests/qemu-iotests/testrunner.py37
-rw-r--r--tests/qtest/ahci-test.c4
-rw-r--r--tests/qtest/boot-serial-test.c8
-rw-r--r--tests/qtest/ipmi-bt-test.c6
-rw-r--r--tests/qtest/ipmi-kcs-test.c3
-rw-r--r--tests/qtest/libqos/meson.build1
-rw-r--r--tests/qtest/libqos/qgraph.c2
-rw-r--r--tests/qtest/libqos/vhost-user-blk.c130
-rw-r--r--tests/qtest/libqos/vhost-user-blk.h48
-rw-r--r--tests/qtest/libqtest.c9
-rw-r--r--tests/qtest/machine-none-test.c3
-rw-r--r--tests/qtest/meson.build6
-rw-r--r--tests/qtest/migration-test.c75
-rw-r--r--tests/qtest/npcm7xx_pwm-test.c4
-rw-r--r--tests/qtest/rtc-test.c6
-rw-r--r--tests/qtest/tpm-util.c4
-rw-r--r--tests/qtest/vhost-user-blk-test.c989
-rw-r--r--tests/tcg/Makefile.qemu17
-rw-r--r--tests/tcg/Makefile.target5
-rw-r--r--tests/tcg/README6
-rwxr-xr-xtests/tcg/configure.sh207
-rw-r--r--tests/tcg/lm32/Makefile106
-rw-r--r--tests/tcg/lm32/crt.S84
-rw-r--r--tests/tcg/lm32/helper.S65
-rw-r--r--tests/tcg/lm32/linker.ld55
-rw-r--r--tests/tcg/lm32/macros.inc90
-rw-r--r--tests/tcg/lm32/test_add.S75
-rw-r--r--tests/tcg/lm32/test_addi.S56
-rw-r--r--tests/tcg/lm32/test_and.S45
-rw-r--r--tests/tcg/lm32/test_andhi.S35
-rw-r--r--tests/tcg/lm32/test_andi.S35
-rw-r--r--tests/tcg/lm32/test_b.S13
-rw-r--r--tests/tcg/lm32/test_be.S48
-rw-r--r--tests/tcg/lm32/test_bg.S78
-rw-r--r--tests/tcg/lm32/test_bge.S78
-rw-r--r--tests/tcg/lm32/test_bgeu.S78
-rw-r--r--tests/tcg/lm32/test_bgu.S78
-rw-r--r--tests/tcg/lm32/test_bi.S23
-rw-r--r--tests/tcg/lm32/test_bne.S48
-rw-r--r--tests/tcg/lm32/test_break.S20
-rw-r--r--tests/tcg/lm32/test_bret.S38
-rw-r--r--tests/tcg/lm32/test_call.S16
-rw-r--r--tests/tcg/lm32/test_calli.S15
-rw-r--r--tests/tcg/lm32/test_cmpe.S40
-rw-r--r--tests/tcg/lm32/test_cmpei.S35
-rw-r--r--tests/tcg/lm32/test_cmpg.S64
-rw-r--r--tests/tcg/lm32/test_cmpge.S64
-rw-r--r--tests/tcg/lm32/test_cmpgei.S70
-rw-r--r--tests/tcg/lm32/test_cmpgeu.S64
-rw-r--r--tests/tcg/lm32/test_cmpgeui.S70
-rw-r--r--tests/tcg/lm32/test_cmpgi.S70
-rw-r--r--tests/tcg/lm32/test_cmpgu.S64
-rw-r--r--tests/tcg/lm32/test_cmpgui.S70
-rw-r--r--tests/tcg/lm32/test_cmpne.S40
-rw-r--r--tests/tcg/lm32/test_cmpnei.S35
-rw-r--r--tests/tcg/lm32/test_divu.S29
-rw-r--r--tests/tcg/lm32/test_eret.S38
-rw-r--r--tests/tcg/lm32/test_lb.S49
-rw-r--r--tests/tcg/lm32/test_lbu.S49
-rw-r--r--tests/tcg/lm32/test_lh.S49
-rw-r--r--tests/tcg/lm32/test_lhu.S49
-rw-r--r--tests/tcg/lm32/test_lw.S32
-rw-r--r--tests/tcg/lm32/test_modu.S35
-rw-r--r--tests/tcg/lm32/test_mul.S70
-rw-r--r--tests/tcg/lm32/test_muli.S45
-rw-r--r--tests/tcg/lm32/test_nor.S51
-rw-r--r--tests/tcg/lm32/test_nori.S35
-rw-r--r--tests/tcg/lm32/test_or.S51
-rw-r--r--tests/tcg/lm32/test_orhi.S35
-rw-r--r--tests/tcg/lm32/test_ori.S35
-rw-r--r--tests/tcg/lm32/test_ret.S14
-rw-r--r--tests/tcg/lm32/test_sb.S32
-rw-r--r--tests/tcg/lm32/test_scall.S24
-rw-r--r--tests/tcg/lm32/test_sextb.S20
-rw-r--r--tests/tcg/lm32/test_sexth.S20
-rw-r--r--tests/tcg/lm32/test_sh.S32
-rw-r--r--tests/tcg/lm32/test_sl.S45
-rw-r--r--tests/tcg/lm32/test_sli.S30
-rw-r--r--tests/tcg/lm32/test_sr.S57
-rw-r--r--tests/tcg/lm32/test_sri.S40
-rw-r--r--tests/tcg/lm32/test_sru.S57
-rw-r--r--tests/tcg/lm32/test_srui.S40
-rw-r--r--tests/tcg/lm32/test_sub.S75
-rw-r--r--tests/tcg/lm32/test_sw.S38
-rw-r--r--tests/tcg/lm32/test_xnor.S51
-rw-r--r--tests/tcg/lm32/test_xnori.S35
-rw-r--r--tests/tcg/lm32/test_xor.S51
-rw-r--r--tests/tcg/lm32/test_xori.S35
-rw-r--r--tests/tcg/multiarch/system/memory.c1
-rw-r--r--tests/tcg/ppc64/Makefile.target13
-rw-r--r--tests/tcg/ppc64le/Makefile.target13
-rw-r--r--tests/tcg/ppc64le/byte_reverse.c21
-rw-r--r--tests/tcg/sparc64/Makefile.target7
-rw-r--r--tests/tcg/tricore/Makefile.softmmu-target26
-rw-r--r--tests/tcg/tricore/link.ld60
-rw-r--r--tests/tcg/tricore/macros.h129
-rw-r--r--tests/tcg/tricore/test_abs.S7
-rw-r--r--tests/tcg/tricore/test_bmerge.S8
-rw-r--r--tests/tcg/tricore/test_clz.S9
-rw-r--r--tests/tcg/tricore/test_dvstep.S15
-rw-r--r--tests/tcg/tricore/test_fadd.S16
-rw-r--r--tests/tcg/tricore/test_fmul.S8
-rw-r--r--tests/tcg/tricore/test_ftoi.S10
-rw-r--r--tests/tcg/tricore/test_madd.S11
-rw-r--r--tests/tcg/tricore/test_msub.S9
-rw-r--r--tests/tcg/tricore/test_muls.S9
-rw-r--r--tests/unit/test-write-threshold.c90
-rw-r--r--tools/virtiofsd/fuse_virtio.c4
-rw-r--r--util/compatfd.c8
-rw-r--r--util/cutils.c2
-rw-r--r--util/main-loop.c61
-rw-r--r--util/module.c7
-rw-r--r--util/qemu-option.c3
-rw-r--r--util/vfio-helpers.c41
612 files changed, 17990 insertions, 35768 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index f53c519447..f4bf49b704 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -67,7 +67,7 @@ windows_msys2_task:
CIRRUS_SHELL: powershell
MSYS: winsymlinks:nativestrict
MSYSTEM: MINGW64
- MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-01-05/msys2-base-x86_64-20210105.sfx.exe
+ MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-04-19/msys2-base-x86_64-20210419.sfx.exe
MSYS2_FINGERPRINT: 0
MSYS2_PACKAGES: "
diffutils git grep make pkg-config sed
@@ -130,7 +130,7 @@ windows_msys2_task:
taskkill /F /FI "MODULES eq msys-2.0.dll"
tasklist
C:\tools\msys64\usr\bin\bash.exe -lc "mv -f /etc/pacman.conf.pacnew /etc/pacman.conf || true"
- C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Suu --overwrite=*"
+ C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Syuu --overwrite=*"
Write-Output "Core install time taken: $((Get-Date).Subtract($start_time))"
$start_time = Get-Date
diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml
index 33e4046e23..765408ae27 100644
--- a/.gitlab-ci.d/containers.yml
+++ b/.gitlab-ci.d/containers.yml
@@ -1,4 +1,4 @@
-.container_job_template: &container_job_definition
+.container_job_template:
image: docker:stable
stage: containers
services:
@@ -22,230 +22,223 @@
- docker logout
amd64-alpine-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: alpine
amd64-centos7-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: centos7
amd64-centos8-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: centos8
amd64-debian10-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: debian10
amd64-debian11-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: debian11
alpha-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-alpha-cross
amd64-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-amd64-cross
amd64-debian-user-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-all-test-cross
amd64-debian-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-amd64
arm64-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-arm64-cross
arm64-test-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian11-container']
variables:
NAME: debian-arm64-test-cross
armel-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-armel-cross
armhf-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-armhf-cross
hppa-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-hppa-cross
m68k-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-m68k-cross
mips64-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips64-cross
mips64el-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips64el-cross
mips-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mips-cross
mipsel-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-mipsel-cross
-powerpc-debian-cross-container:
- <<: *container_job_definition
+powerpc-test-cross-container:
+ extends: .container_job_template
stage: containers-layer2
- needs: ['amd64-debian10-container']
- variables:
- NAME: debian-powerpc-cross
-
-ppc64-debian-cross-container:
- <<: *container_job_definition
- stage: containers-layer2
- needs: ['amd64-debian10-container']
+ needs: ['amd64-debian11-container']
variables:
- NAME: debian-ppc64-cross
+ NAME: debian-powerpc-test-cross
ppc64el-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-ppc64el-cross
riscv64-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-riscv64-cross
s390x-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-s390x-cross
sh4-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-sh4-cross
sparc64-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-sparc64-cross
tricore-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
stage: containers-layer2
needs: ['amd64-debian10-container']
variables:
NAME: debian-tricore-cross
xtensa-debian-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: debian-xtensa-cross
cris-fedora-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: fedora-cris-cross
amd64-fedora-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: fedora
i386-fedora-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: fedora-i386-cross
win32-fedora-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: fedora-win32-cross
win64-fedora-cross-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: fedora-win64-cross
amd64-ubuntu1804-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: ubuntu1804
amd64-ubuntu2004-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: ubuntu2004
amd64-ubuntu-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: ubuntu
amd64-opensuse-leap-container:
- <<: *container_job_definition
+ extends: .container_job_template
variables:
NAME: opensuse-leap
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dcb6317aac..f718b61fa7 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -13,7 +13,7 @@ include:
- local: '/.gitlab-ci.d/containers.yml'
- local: '/.gitlab-ci.d/crossbuilds.yml'
-.native_build_job_template: &native_build_job_definition
+.native_build_job_template:
stage: build
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
before_script:
@@ -41,7 +41,7 @@ include:
make -j"$JOBS" $MAKE_CHECK_ARGS ;
fi
-.native_test_job_template: &native_test_job_definition
+.native_test_job_template:
stage: test
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest
script:
@@ -83,13 +83,13 @@ include:
- du -chs ${CI_PROJECT_DIR}/avocado-cache
build-system-alpine:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
- job: amd64-alpine-container
variables:
IMAGE: alpine
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
- moxie-softmmu microblazeel-softmmu mips64el-softmmu
+ microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog
artifacts:
@@ -99,7 +99,7 @@ build-system-alpine:
- build
check-system-alpine:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-alpine
artifacts: true
@@ -108,7 +108,7 @@ check-system-alpine:
MAKE_CHECK_ARGS: check
acceptance-system-alpine:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-alpine
artifacts: true
@@ -118,14 +118,14 @@ acceptance-system-alpine:
<<: *acceptance_definition
build-system-ubuntu:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-ubuntu2004-container
variables:
IMAGE: ubuntu2004
CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system
TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu
- moxie-softmmu microblazeel-softmmu mips64el-softmmu
+ microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build
artifacts:
expire_in: 2 days
@@ -133,7 +133,7 @@ build-system-ubuntu:
- build
check-system-ubuntu:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-ubuntu
artifacts: true
@@ -142,7 +142,7 @@ check-system-ubuntu:
MAKE_CHECK_ARGS: check
acceptance-system-ubuntu:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-ubuntu
artifacts: true
@@ -152,7 +152,7 @@ acceptance-system-ubuntu:
<<: *acceptance_definition
build-system-debian:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-container
variables:
@@ -167,7 +167,7 @@ build-system-debian:
- build
check-system-debian:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-debian
artifacts: true
@@ -176,7 +176,7 @@ check-system-debian:
MAKE_CHECK_ARGS: check
acceptance-system-debian:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-debian
artifacts: true
@@ -186,7 +186,7 @@ acceptance-system-debian:
<<: *acceptance_definition
build-system-fedora:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-fedora-container
variables:
@@ -202,7 +202,7 @@ build-system-fedora:
- build
check-system-fedora:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-fedora
artifacts: true
@@ -211,7 +211,7 @@ check-system-fedora:
MAKE_CHECK_ARGS: check
acceptance-system-fedora:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-fedora
artifacts: true
@@ -221,7 +221,7 @@ acceptance-system-fedora:
<<: *acceptance_definition
build-system-centos:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos8-container
variables:
@@ -237,7 +237,7 @@ build-system-centos:
- build
check-system-centos:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-centos
artifacts: true
@@ -246,7 +246,7 @@ check-system-centos:
MAKE_CHECK_ARGS: check
acceptance-system-centos:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-centos
artifacts: true
@@ -256,7 +256,7 @@ acceptance-system-centos:
<<: *acceptance_definition
build-system-opensuse:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-opensuse-leap-container
variables:
@@ -270,7 +270,7 @@ build-system-opensuse:
- build
check-system-opensuse:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-opensuse
artifacts: true
@@ -279,7 +279,7 @@ check-system-opensuse:
MAKE_CHECK_ARGS: check
acceptance-system-opensuse:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-system-opensuse
artifacts: true
@@ -290,7 +290,7 @@ acceptance-system-opensuse:
build-disabled:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-fedora-container
variables:
@@ -342,7 +342,6 @@ build-disabled:
--disable-replication
--disable-sdl
--disable-seccomp
- --disable-sheepdog
--disable-slirp
--disable-smartcard
--disable-snappy
@@ -377,7 +376,7 @@ build-disabled:
# Also use a different coroutine implementation (which is only really of
# interest to KVM users, i.e. with TCG disabled)
build-tcg-disabled:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos8-container
variables:
@@ -400,7 +399,7 @@ build-tcg-disabled:
260 261 262 263 264 270 272 273 277 279
build-user:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -409,7 +408,7 @@ build-user:
MAKE_CHECK_ARGS: check-tcg
build-user-static:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -417,9 +416,20 @@ build-user-static:
CONFIGURE_ARGS: --disable-tools --disable-system --static
MAKE_CHECK_ARGS: check-tcg
+# Because the hexagon cross-compiler takes so long to build we don't rely
+# on the CI system to build it and hence this job has no dependency
+# declared. The image is manually uploaded.
+build-user-hexagon:
+ extends: .native_build_job_template
+ variables:
+ IMAGE: debian-hexagon-cross
+ TARGETS: hexagon-linux-user
+ CONFIGURE_ARGS: --disable-tools --disable-docs --enable-debug-tcg
+ MAKE_CHECK_ARGS: check-tcg
+
# Only build the softmmu targets we have check-tcg tests for
build-some-softmmu:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -432,7 +442,7 @@ build-some-softmmu:
# we skip sparc64-linux-user until it has been fixed somewhat
# we skip cris-linux-user as it doesn't use the common run loop
build-user-plugins:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -442,7 +452,7 @@ build-user-plugins:
timeout: 1h 30m
build-user-centos7:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos7-container
variables:
@@ -451,7 +461,7 @@ build-user-centos7:
MAKE_CHECK_ARGS: check-tcg
build-some-softmmu-plugins:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -461,7 +471,7 @@ build-some-softmmu-plugins:
MAKE_CHECK_ARGS: check-tcg
clang-system:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-fedora-container
variables:
@@ -473,7 +483,7 @@ clang-system:
MAKE_CHECK_ARGS: check-qtest check-tcg
clang-user:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
@@ -495,7 +505,7 @@ clang-user:
# Split in three sets of build/check/acceptance to limit the execution time of each
# job
build-cfi-aarch64:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
- job: amd64-fedora-container
variables:
@@ -513,7 +523,7 @@ build-cfi-aarch64:
- build
check-cfi-aarch64:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-aarch64
artifacts: true
@@ -522,7 +532,7 @@ check-cfi-aarch64:
MAKE_CHECK_ARGS: check
acceptance-cfi-aarch64:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-aarch64
artifacts: true
@@ -532,7 +542,7 @@ acceptance-cfi-aarch64:
<<: *acceptance_definition
build-cfi-ppc64-s390x:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
- job: amd64-fedora-container
variables:
@@ -550,7 +560,7 @@ build-cfi-ppc64-s390x:
- build
check-cfi-ppc64-s390x:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-ppc64-s390x
artifacts: true
@@ -559,7 +569,7 @@ check-cfi-ppc64-s390x:
MAKE_CHECK_ARGS: check
acceptance-cfi-ppc64-s390x:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-ppc64-s390x
artifacts: true
@@ -569,7 +579,7 @@ acceptance-cfi-ppc64-s390x:
<<: *acceptance_definition
build-cfi-x86_64:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
- job: amd64-fedora-container
variables:
@@ -587,7 +597,7 @@ build-cfi-x86_64:
- build
check-cfi-x86_64:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-x86_64
artifacts: true
@@ -596,7 +606,7 @@ check-cfi-x86_64:
MAKE_CHECK_ARGS: check
acceptance-cfi-x86_64:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-cfi-x86_64
artifacts: true
@@ -606,7 +616,7 @@ acceptance-cfi-x86_64:
<<: *acceptance_definition
tsan-build:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-ubuntu2004-container
variables:
@@ -618,14 +628,14 @@ tsan-build:
# These targets are on the way out
build-deprecated:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --disable-tools
MAKE_CHECK_ARGS: build-tcg
- TARGETS: ppc64abi32-linux-user lm32-softmmu unicore32-softmmu
+ TARGETS: ppc64abi32-linux-user
artifacts:
expire_in: 2 days
paths:
@@ -634,7 +644,7 @@ build-deprecated:
# We split the check-tcg step as test failures are expected but we still
# want to catch the build breaking.
check-deprecated:
- <<: *native_test_job_definition
+ extends: .native_test_job_template
needs:
- job: build-deprecated
artifacts: true
@@ -645,7 +655,7 @@ check-deprecated:
# gprof/gcov are GCC features
gprof-gcov:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-ubuntu2004-container
variables:
@@ -658,7 +668,7 @@ gprof-gcov:
- ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh
build-oss-fuzz:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-fedora-container
variables:
@@ -678,13 +688,13 @@ build-oss-fuzz:
- cd build-oss-fuzz && make check-qtest-i386 check-unit
build-tci:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-user-cross-container
variables:
IMAGE: debian-all-test-cross
script:
- - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64"
+ - TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64"
- mkdir build
- cd build
- ../configure --enable-tcg-interpreter
@@ -703,7 +713,7 @@ build-tci:
# Alternate coroutines implementations are only really of interest to KVM users
# However we can't test against KVM on Gitlab-CI so we can only run unit tests
build-coroutine-sigaltstack:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-ubuntu2004-container
variables:
@@ -717,7 +727,7 @@ build-coroutine-sigaltstack:
# These jobs test old gcrypt and nettle from RHEL7
# which had some API differences.
crypto-old-nettle:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos7-container
variables:
@@ -727,7 +737,7 @@ crypto-old-nettle:
MAKE_CHECK_ARGS: check
crypto-old-gcrypt:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos7-container
variables:
@@ -737,7 +747,7 @@ crypto-old-gcrypt:
MAKE_CHECK_ARGS: check
crypto-only-gnutls:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos7-container
variables:
@@ -749,7 +759,7 @@ crypto-only-gnutls:
# Check our reduced build configurations
build-without-default-devices:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-centos8-container
variables:
@@ -757,7 +767,7 @@ build-without-default-devices:
CONFIGURE_ARGS: --without-default-devices --disable-user
build-without-default-features:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-container
variables:
@@ -807,7 +817,7 @@ build-libvhost-user:
# No targets are built here, just tools, docs, and unit tests. This
# also feeds into the eventual documentation deployment steps later
build-tools-and-docs-debian:
- <<: *native_build_job_definition
+ extends: .native_build_job_template
needs:
job: amd64-debian-container
variables:
diff --git a/MAINTAINERS b/MAINTAINERS
index 06642d9799..75e0f2d750 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -197,6 +197,8 @@ F: linux-user/hexagon/
F: tests/tcg/hexagon/
F: disas/hexagon.c
F: default-configs/targets/hexagon-linux-user.mak
+F: docker/dockerfiles/debian-hexagon-cross.docker
+F: docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
HPPA (PA-RISC) TCG CPUs
M: Richard Henderson <richard.henderson@linaro.org>
@@ -207,19 +209,6 @@ F: disas/hppa.c
F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
-LM32 TCG CPUs
-R: Michael Walle <michael@walle.cc>
-S: Orphan
-F: target/lm32/
-F: disas/lm32.c
-F: hw/lm32/
-F: hw/*/lm32_*
-F: hw/*/milkymist-*
-F: include/hw/display/milkymist_tmu2.h
-F: include/hw/char/lm32_juart.h
-F: include/hw/lm32/
-F: tests/tcg/lm32/
-
M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu>
S: Maintained
@@ -258,14 +247,6 @@ MIPS TCG CPUs (nanoMIPS ISA)
S: Orphan
F: disas/nanomips.*
-Moxie TCG CPUs
-M: Anthony Green <green@moxielogic.com>
-S: Maintained
-F: target/moxie/
-F: disas/moxie.c
-F: hw/moxie/
-F: default-configs/*/moxie-softmmu.mak
-
NiosII TCG CPUs
M: Chris Wulff <crwulff@gmail.com>
M: Marek Vasut <marex@denx.de>
@@ -295,9 +276,8 @@ F: tests/acceptance/machine_ppc.py
RISC-V TCG CPUs
M: Palmer Dabbelt <palmer@dabbelt.com>
-M: Alistair Francis <Alistair.Francis@wdc.com>
-M: Sagar Karandikar <sagark@eecs.berkeley.edu>
-M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
+M: Alistair Francis <alistair.francis@wdc.com>
+M: Bin Meng <bin.meng@windriver.com>
L: qemu-riscv@nongnu.org
S: Supported
F: target/riscv/
@@ -339,19 +319,12 @@ F: hw/sparc64/
F: include/hw/sparc/sparc64.h
F: disas/sparc.c
-UniCore32 TCG CPUs
-M: Guan Xuetao <gxt@mprc.pku.edu.cn>
-S: Maintained
-F: target/unicore32/
-F: hw/unicore32/
-F: include/hw/unicore32/
-
X86 TCG CPUs
M: Paolo Bonzini <pbonzini@redhat.com>
M: Richard Henderson <richard.henderson@linaro.org>
M: Eduardo Habkost <ehabkost@redhat.com>
S: Maintained
-F: target/i386/
+F: target/i386/tcg/
F: tests/tcg/i386/
F: tests/tcg/x86_64/
F: hw/i386/
@@ -376,6 +349,7 @@ S: Maintained
F: target/tricore/
F: hw/tricore/
F: include/hw/tricore/
+F: tests/tcg/tricore/
Multiarch Linux User Tests
M: Alex Bennée <alex.bennee@linaro.org>
@@ -1089,18 +1063,6 @@ F: default-configs/*/hppa-softmmu.mak
F: hw/hppa/
F: pc-bios/hppa-firmware.img
-LM32 Machines
--------------
-EVR32 and uclinux BSP
-R: Michael Walle <michael@walle.cc>
-S: Orphan
-F: hw/lm32/lm32_boards.c
-
-milkymist
-R: Michael Walle <michael@walle.cc>
-S: Orphan
-F: hw/lm32/milkymist.c
-
M68K Machines
-------------
an5206
@@ -1415,6 +1377,15 @@ F: include/hw/misc/mchp_pfsoc_dmc.h
F: include/hw/misc/mchp_pfsoc_ioscb.h
F: include/hw/misc/mchp_pfsoc_sysreg.h
+Shakti C class SoC
+M: Vijai Kumar K <vijai@behindbytes.com>
+L: qemu-riscv@nongnu.org
+S: Supported
+F: hw/riscv/shakti_c.c
+F: hw/char/shakti_uart.c
+F: include/hw/riscv/shakti_c.h
+F: include/hw/char/shakti_uart.h
+
SiFive Machines
M: Alistair Francis <Alistair.Francis@wdc.com>
M: Bin Meng <bin.meng@windriver.com>
@@ -1541,14 +1512,6 @@ F: hw/s390x/s390-pci*
F: include/hw/s390x/s390-pci*
L: qemu-s390x@nongnu.org
-UniCore32 Machines
-------------------
-PKUnity-3 SoC initramfs-with-busybox
-M: Guan Xuetao <gxt@mprc.pku.edu.cn>
-S: Maintained
-F: hw/*/puv3*
-F: hw/unicore32/
-
X86 Machines
------------
PC
@@ -1996,7 +1959,7 @@ M: Keith Busch <kbusch@kernel.org>
M: Klaus Jensen <its@irrelevant.dk>
L: qemu-block@nongnu.org
S: Supported
-F: hw/block/nvme*
+F: hw/nvme/*
F: include/block/nvme.h
F: tests/qtest/nvme-test.c
F: docs/system/nvme.rst
@@ -2064,6 +2027,12 @@ S: Maintained
F: hw/net/tulip.c
F: hw/net/tulip.h
+pca954x
+M: Patrick Venture <venture@google.com>
+S: Maintained
+F: hw/i2c/i2c_mux_pca954x.c
+F: include/hw/i2c/i2c_mux_pca954x.h
+
Generic Loader
M: Alistair Francis <alistair@alistair23.me>
S: Maintained
@@ -2469,6 +2438,7 @@ F: ui/cocoa.m
Main loop
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
+F: include/exec/gen-icount.h
F: include/qemu/main-loop.h
F: include/sysemu/runstate.h
F: include/sysemu/runstate-action.h
@@ -3080,12 +3050,6 @@ L: qemu-block@nongnu.org
S: Supported
F: block/rbd.c
-Sheepdog
-M: Liu Yuan <namei.unix@gmail.com>
-L: qemu-block@nongnu.org
-S: Odd Fixes
-F: block/sheepdog.c
-
VHDX
M: Jeff Cody <codyprime@gmail.com>
L: qemu-block@nongnu.org
@@ -3284,6 +3248,8 @@ F: block/export/vhost-user-blk-server.c
F: block/export/vhost-user-blk-server.h
F: include/qemu/vhost-user-server.h
F: tests/qtest/libqos/vhost-user-blk.c
+F: tests/qtest/libqos/vhost-user-blk.h
+F: tests/qtest/vhost-user-blk-test.c
F: util/vhost-user-server.c
FUSE block device exports
diff --git a/Makefile b/Makefile
index bcbbec71a1..4cab10a2a4 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,7 @@ qemu-%.tar.bz2:
distclean: clean
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
- rm -f config-host.mak config-host.h*
+ rm -f config-host.mak config-host.h* config-poison.h
rm -f tests/tcg/config-*.mak
rm -f config-all-disas.mak config.status
rm -f roms/seabios/config.mak roms/vgabios/config.mak
diff --git a/accel/accel-common.c b/accel/accel-common.c
index 9901b0531c..cf07f78421 100644
--- a/accel/accel-common.c
+++ b/accel/accel-common.c
@@ -54,10 +54,23 @@ static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
CPUClass *cc = CPU_CLASS(klass);
AccelCPUClass *accel_cpu = opaque;
+ /*
+ * The first callback allows accel-cpu to run initializations
+ * for the CPU, customizing CPU behavior according to the accelerator.
+ *
+ * The second one allows the CPU to customize the accel-cpu
+ * behavior according to the CPU.
+ *
+ * The second is currently only used by TCG, to specialize the
+ * TCGCPUOps depending on the CPU type.
+ */
cc->accel_cpu = accel_cpu;
if (accel_cpu->cpu_class_init) {
accel_cpu->cpu_class_init(cc);
}
+ if (cc->init_accel_cpu) {
+ cc->init_accel_cpu(accel_cpu, cc);
+ }
}
/* initialize the arch-specific accel CpuClass interfaces */
@@ -89,6 +102,25 @@ void accel_init_interfaces(AccelClass *ac)
accel_init_cpu_interfaces(ac);
}
+void accel_cpu_instance_init(CPUState *cpu)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (cc->accel_cpu && cc->accel_cpu->cpu_instance_init) {
+ cc->accel_cpu->cpu_instance_init(cpu);
+ }
+}
+
+bool accel_cpu_realizefn(CPUState *cpu, Error **errp)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) {
+ return cc->accel_cpu->cpu_realizefn(cpu, errp);
+ }
+ return true;
+}
+
static const TypeInfo accel_cpu_type = {
.name = TYPE_ACCEL_CPU,
.parent = TYPE_OBJECT,
diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c
index 521da4a813..ac7d28c251 100644
--- a/accel/tcg/tcg-runtime-gvec.c
+++ b/accel/tcg/tcg-runtime-gvec.c
@@ -1073,9 +1073,8 @@ void HELPER(gvec_ssadd32)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
int32_t ai = *(int32_t *)(a + i);
int32_t bi = *(int32_t *)(b + i);
- int32_t di = ai + bi;
- if (((di ^ ai) &~ (ai ^ bi)) < 0) {
- /* Signed overflow. */
+ int32_t di;
+ if (sadd32_overflow(ai, bi, &di)) {
di = (di < 0 ? INT32_MAX : INT32_MIN);
}
*(int32_t *)(d + i) = di;
@@ -1091,9 +1090,8 @@ void HELPER(gvec_ssadd64)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
int64_t ai = *(int64_t *)(a + i);
int64_t bi = *(int64_t *)(b + i);
- int64_t di = ai + bi;
- if (((di ^ ai) &~ (ai ^ bi)) < 0) {
- /* Signed overflow. */
+ int64_t di;
+ if (sadd64_overflow(ai, bi, &di)) {
di = (di < 0 ? INT64_MAX : INT64_MIN);
}
*(int64_t *)(d + i) = di;
@@ -1143,9 +1141,8 @@ void HELPER(gvec_sssub32)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
int32_t ai = *(int32_t *)(a + i);
int32_t bi = *(int32_t *)(b + i);
- int32_t di = ai - bi;
- if (((di ^ ai) & (ai ^ bi)) < 0) {
- /* Signed overflow. */
+ int32_t di;
+ if (ssub32_overflow(ai, bi, &di)) {
di = (di < 0 ? INT32_MAX : INT32_MIN);
}
*(int32_t *)(d + i) = di;
@@ -1161,9 +1158,8 @@ void HELPER(gvec_sssub64)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
int64_t ai = *(int64_t *)(a + i);
int64_t bi = *(int64_t *)(b + i);
- int64_t di = ai - bi;
- if (((di ^ ai) & (ai ^ bi)) < 0) {
- /* Signed overflow. */
+ int64_t di;
+ if (ssub64_overflow(ai, bi, &di)) {
di = (di < 0 ? INT64_MAX : INT64_MIN);
}
*(int64_t *)(d + i) = di;
@@ -1209,8 +1205,8 @@ void HELPER(gvec_usadd32)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
uint32_t ai = *(uint32_t *)(a + i);
uint32_t bi = *(uint32_t *)(b + i);
- uint32_t di = ai + bi;
- if (di < ai) {
+ uint32_t di;
+ if (uadd32_overflow(ai, bi, &di)) {
di = UINT32_MAX;
}
*(uint32_t *)(d + i) = di;
@@ -1226,8 +1222,8 @@ void HELPER(gvec_usadd64)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
uint64_t ai = *(uint64_t *)(a + i);
uint64_t bi = *(uint64_t *)(b + i);
- uint64_t di = ai + bi;
- if (di < ai) {
+ uint64_t di;
+ if (uadd64_overflow(ai, bi, &di)) {
di = UINT64_MAX;
}
*(uint64_t *)(d + i) = di;
@@ -1273,8 +1269,8 @@ void HELPER(gvec_ussub32)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(uint32_t)) {
uint32_t ai = *(uint32_t *)(a + i);
uint32_t bi = *(uint32_t *)(b + i);
- uint32_t di = ai - bi;
- if (ai < bi) {
+ uint32_t di;
+ if (usub32_overflow(ai, bi, &di)) {
di = 0;
}
*(uint32_t *)(d + i) = di;
@@ -1290,8 +1286,8 @@ void HELPER(gvec_ussub64)(void *d, void *a, void *b, uint32_t desc)
for (i = 0; i < oprsz; i += sizeof(uint64_t)) {
uint64_t ai = *(uint64_t *)(a + i);
uint64_t bi = *(uint64_t *)(b + i);
- uint64_t di = ai - bi;
- if (ai < bi) {
+ uint64_t di;
+ if (usub64_overflow(ai, bi, &di)) {
di = 0;
}
*(uint64_t *)(d + i) = di;
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index ae7e873713..fbf8fc630b 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -2042,8 +2042,15 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
int i;
qemu_log(" data: [size=%d]\n", data_size);
for (i = 0; i < data_size / sizeof(tcg_target_ulong); i++) {
- qemu_log("0x%08" PRIxPTR ": .quad 0x%" TCG_PRIlx "\n",
- (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
+ if (sizeof(tcg_target_ulong) == 8) {
+ qemu_log("0x%08" PRIxPTR ": .quad 0x%016" TCG_PRIlx "\n",
+ (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
+ } else if (sizeof(tcg_target_ulong) == 4) {
+ qemu_log("0x%08" PRIxPTR ": .long 0x%08" TCG_PRIlx "\n",
+ (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]);
+ } else {
+ qemu_build_not_reached();
+ }
}
}
qemu_log("\n");
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index a012adc193..e5f1063ab6 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -30,6 +30,7 @@
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qemu/sockets.h"
+#include "qemu/lockable.h"
#include "io/channel-socket.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/tpm_util.h"
@@ -124,31 +125,26 @@ static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
uint32_t cmd_no = cpu_to_be32(cmd);
ssize_t n = sizeof(uint32_t) + msg_len_in;
uint8_t *buf = NULL;
- int ret = -1;
- qemu_mutex_lock(&tpm->mutex);
+ WITH_QEMU_LOCK_GUARD(&tpm->mutex) {
+ buf = g_alloca(n);
+ memcpy(buf, &cmd_no, sizeof(cmd_no));
+ memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
- buf = g_alloca(n);
- memcpy(buf, &cmd_no, sizeof(cmd_no));
- memcpy(buf + sizeof(cmd_no), msg, msg_len_in);
-
- n = qemu_chr_fe_write_all(dev, buf, n);
- if (n <= 0) {
- goto end;
- }
-
- if (msg_len_out != 0) {
- n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
+ n = qemu_chr_fe_write_all(dev, buf, n);
if (n <= 0) {
- goto end;
+ return -1;
}
- }
- ret = 0;
+ if (msg_len_out != 0) {
+ n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
+ if (n <= 0) {
+ return -1;
+ }
+ }
+ }
-end:
- qemu_mutex_unlock(&tpm->mutex);
- return ret;
+ return 0;
}
static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
diff --git a/block.c b/block.c
index 9ad725d205..0dc97281dc 100644
--- a/block.c
+++ b/block.c
@@ -400,7 +400,6 @@ BlockDriverState *bdrv_new(void)
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
QLIST_INIT(&bs->op_blockers[i]);
}
- notifier_with_return_list_init(&bs->before_write_notifiers);
qemu_co_mutex_init(&bs->reqs_lock);
qemu_mutex_init(&bs->dirty_bitmap_mutex);
bs->refcnt = 1;
@@ -2917,13 +2916,14 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
child_role, perm, shared_perm, opaque,
&child, tran, errp);
if (ret < 0) {
- bdrv_unref(child_bs);
- return NULL;
+ assert(child == NULL);
+ goto out;
}
ret = bdrv_refresh_perms(child_bs, errp);
- tran_finalize(tran, ret);
+out:
+ tran_finalize(tran, ret);
bdrv_unref(child_bs);
return child;
}
@@ -4050,7 +4050,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
ret = bdrv_flush(bs_entry->state.bs);
if (ret < 0) {
error_setg_errno(errp, -ret, "Error flushing drive");
- goto cleanup;
+ goto abort;
}
}
diff --git a/block/backup.c b/block/backup.c
index 6cf2f974aa..bd3614ce70 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -331,7 +331,7 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
}
}
-static void backup_cancel(Job *job)
+static void backup_cancel(Job *job, bool force)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
index 9cad9e1b8c..c428682272 100644
--- a/block/copy-on-read.c
+++ b/block/copy-on-read.c
@@ -29,7 +29,6 @@
typedef struct BDRVStateCOR {
- bool active;
BlockDriverState *bottom_bs;
bool chain_frozen;
} BDRVStateCOR;
@@ -89,7 +88,6 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags,
*/
bdrv_ref(bottom_bs);
}
- state->active = true;
state->bottom_bs = bottom_bs;
/*
@@ -112,17 +110,6 @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
- BDRVStateCOR *s = bs->opaque;
-
- if (!s->active) {
- /*
- * While the filter is being removed
- */
- *nperm = 0;
- *nshared = BLK_PERM_ALL;
- return;
- }
-
*nperm = perm & PERM_PASSTHROUGH;
*nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED;
@@ -280,32 +267,14 @@ static BlockDriver bdrv_copy_on_read = {
void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
{
- BdrvChild *child;
- BlockDriverState *bs;
BDRVStateCOR *s = cor_filter_bs->opaque;
- child = bdrv_filter_child(cor_filter_bs);
- if (!child) {
- return;
- }
- bs = child->bs;
-
- /* Retain the BDS until we complete the graph change. */
- bdrv_ref(bs);
- /* Hold a guest back from writing while permissions are being reset. */
- bdrv_drained_begin(bs);
- /* Drop permissions before the graph change. */
- s->active = false;
/* unfreeze, as otherwise bdrv_replace_node() will fail */
if (s->chain_frozen) {
s->chain_frozen = false;
bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
}
- bdrv_child_refresh_perms(cor_filter_bs, child, &error_abort);
- bdrv_replace_node(cor_filter_bs, bs, &error_abort);
-
- bdrv_drained_end(bs);
- bdrv_unref(bs);
+ bdrv_drop_filter(cor_filter_bs, &error_abort);
bdrv_unref(cor_filter_bs);
}
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
index fa06996d37..1862563336 100644
--- a/block/export/vhost-user-blk-server.c
+++ b/block/export/vhost-user-blk-server.c
@@ -70,9 +70,16 @@ static void vu_blk_req_complete(VuBlkReq *req)
static bool vu_blk_sect_range_ok(VuBlkExport *vexp, uint64_t sector,
size_t size)
{
- uint64_t nb_sectors = size >> BDRV_SECTOR_BITS;
+ uint64_t nb_sectors;
uint64_t total_sectors;
+ if (size % VIRTIO_BLK_SECTOR_SIZE) {
+ return false;
+ }
+
+ nb_sectors = size >> VIRTIO_BLK_SECTOR_BITS;
+
+ QEMU_BUILD_BUG_ON(BDRV_SECTOR_SIZE != VIRTIO_BLK_SECTOR_SIZE);
if (nb_sectors > BDRV_REQUEST_MAX_SECTORS) {
return false;
}
diff --git a/block/io.c b/block/io.c
index 35b6c56efc..1e826ba9e8 100644
--- a/block/io.c
+++ b/block/io.c
@@ -30,6 +30,7 @@
#include "block/blockjob_int.h"
#include "block/block_int.h"
#include "block/coroutines.h"
+#include "block/write-threshold.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -2008,8 +2009,8 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes,
} else {
assert(child->perm & BLK_PERM_WRITE);
}
- return notifier_with_return_list_notify(&bs->before_write_notifiers,
- req);
+ bdrv_write_threshold_check_write(bs, offset, bytes);
+ return 0;
case BDRV_TRACKED_TRUNCATE:
assert(child->perm & BLK_PERM_RESIZE);
return 0;
@@ -3164,12 +3165,6 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
return true;
}
-void bdrv_add_before_write_notifier(BlockDriverState *bs,
- NotifierWithReturn *notifier)
-{
- notifier_with_return_list_add(&bs->before_write_notifiers, notifier);
-}
-
void bdrv_io_plug(BlockDriverState *bs)
{
BdrvChild *child;
diff --git a/block/meson.build b/block/meson.build
index d21990ec95..e687c54dbc 100644
--- a/block/meson.build
+++ b/block/meson.build
@@ -64,7 +64,6 @@ block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
-block_ss.add(when: 'CONFIG_SHEEPDOG', if_true: files('sheepdog.c'))
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
block_ss.add(when: ['CONFIG_LINUX_IO_URING', linux_io_uring], if_true: files('io_uring.c'))
diff --git a/block/mirror.c b/block/mirror.c
index 840b8e8c15..019f6deaa5 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -1178,12 +1178,14 @@ static bool mirror_drained_poll(BlockJob *job)
return !!s->in_flight;
}
-static void mirror_cancel(Job *job)
+static void mirror_cancel(Job *job, bool force)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
BlockDriverState *target = blk_bs(s->target);
- bdrv_cancel_in_flight(target);
+ if (force || !job_is_ready(job)) {
+ bdrv_cancel_in_flight(target);
+ }
}
static const BlockJobDriver mirror_job_driver = {
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index ebf1033f31..3e6670c963 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -557,8 +557,10 @@ void hmp_eject(Monitor *mon, const QDict *qdict)
void hmp_qemu_io(Monitor *mon, const QDict *qdict)
{
- BlockBackend *blk;
+ BlockBackend *blk = NULL;
+ BlockDriverState *bs = NULL;
BlockBackend *local_blk = NULL;
+ AioContext *ctx = NULL;
bool qdev = qdict_get_try_bool(qdict, "qdev", false);
const char *device = qdict_get_str(qdict, "device");
const char *command = qdict_get_str(qdict, "command");
@@ -573,20 +575,24 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
} else {
blk = blk_by_name(device);
if (!blk) {
- BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
- if (bs) {
- blk = local_blk = blk_new(bdrv_get_aio_context(bs),
- 0, BLK_PERM_ALL);
- ret = blk_insert_bs(blk, bs, &err);
- if (ret < 0) {
- goto fail;
- }
- } else {
+ bs = bdrv_lookup_bs(NULL, device, &err);
+ if (!bs) {
goto fail;
}
}
}
+ ctx = blk ? blk_get_aio_context(blk) : bdrv_get_aio_context(bs);
+ aio_context_acquire(ctx);
+
+ if (bs) {
+ blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL);
+ ret = blk_insert_bs(blk, bs, &err);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
/*
* Notably absent: Proper permission management. This is sad, but it seems
* almost impossible to achieve without changing the semantics and thereby
@@ -616,6 +622,11 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
fail:
blk_unref(local_blk);
+
+ if (ctx) {
+ aio_context_release(ctx);
+ }
+
hmp_handle_error(mon, err);
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 9727ae8fe3..39b91ef940 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -5089,6 +5089,7 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
BDRVQcow2State *s = bs->opaque;
bdi->cluster_size = s->cluster_size;
bdi->vm_state_offset = qcow2_vm_state_offset(s);
+ bdi->is_dirty = s->incompatible_features & QCOW2_INCOMPAT_DIRTY;
return 0;
}
diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..26f64cce7c 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -113,21 +113,31 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
const char *keypairs, const char *secretid,
Error **errp);
+static char *qemu_rbd_strchr(char *src, char delim)
+{
+ char *p;
+
+ for (p = src; *p; ++p) {
+ if (*p == delim) {
+ return p;
+ }
+ if (*p == '\\' && p[1] != '\0') {
+ ++p;
+ }
+ }
+
+ return NULL;
+}
+
+
static char *qemu_rbd_next_tok(char *src, char delim, char **p)
{
char *end;
*p = NULL;
- for (end = src; *end; ++end) {
- if (*end == delim) {
- break;
- }
- if (*end == '\\' && end[1] != '\0') {
- end++;
- }
- }
- if (*end == delim) {
+ end = qemu_rbd_strchr(src, delim);
+ if (end) {
*p = end + 1;
*end = '\0';
}
@@ -171,7 +181,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
qemu_rbd_unescape(found_str);
qdict_put_str(options, "pool", found_str);
- if (strchr(p, '@')) {
+ if (qemu_rbd_strchr(p, '@')) {
image_name = qemu_rbd_next_tok(p, '@', &p);
found_str = qemu_rbd_next_tok(p, ':', &p);
@@ -181,7 +191,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
image_name = qemu_rbd_next_tok(p, ':', &p);
}
/* Check for namespace in the image_name */
- if (strchr(image_name, '/')) {
+ if (qemu_rbd_strchr(image_name, '/')) {
found_str = qemu_rbd_next_tok(image_name, '/', &image_name);
qemu_rbd_unescape(found_str);
qdict_put_str(options, "namespace", found_str);
diff --git a/block/sheepdog.c b/block/sheepdog.c
deleted file mode 100644
index a45c73826d..0000000000
--- a/block/sheepdog.c
+++ /dev/null
@@ -1,3356 +0,0 @@
-/*
- * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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-common.h"
-#include "qapi/error.h"
-#include "qapi/qapi-visit-sockets.h"
-#include "qapi/qapi-visit-block-core.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qobject-input-visitor.h"
-#include "qapi/qobject-output-visitor.h"
-#include "qemu/uri.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
-#include "qemu/module.h"
-#include "qemu/option.h"
-#include "qemu/sockets.h"
-#include "block/block_int.h"
-#include "block/qdict.h"
-#include "sysemu/block-backend.h"
-#include "qemu/bitops.h"
-#include "qemu/cutils.h"
-#include "trace.h"
-
-#define SD_PROTO_VER 0x01
-
-#define SD_DEFAULT_ADDR "localhost"
-#define SD_DEFAULT_PORT 7000
-
-#define SD_OP_CREATE_AND_WRITE_OBJ 0x01
-#define SD_OP_READ_OBJ 0x02
-#define SD_OP_WRITE_OBJ 0x03
-/* 0x04 is used internally by Sheepdog */
-
-#define SD_OP_NEW_VDI 0x11
-#define SD_OP_LOCK_VDI 0x12
-#define SD_OP_RELEASE_VDI 0x13
-#define SD_OP_GET_VDI_INFO 0x14
-#define SD_OP_READ_VDIS 0x15
-#define SD_OP_FLUSH_VDI 0x16
-#define SD_OP_DEL_VDI 0x17
-#define SD_OP_GET_CLUSTER_DEFAULT 0x18
-
-#define SD_FLAG_CMD_WRITE 0x01
-#define SD_FLAG_CMD_COW 0x02
-#define SD_FLAG_CMD_CACHE 0x04 /* Writeback mode for cache */
-#define SD_FLAG_CMD_DIRECT 0x08 /* Don't use cache */
-
-#define SD_RES_SUCCESS 0x00 /* Success */
-#define SD_RES_UNKNOWN 0x01 /* Unknown error */
-#define SD_RES_NO_OBJ 0x02 /* No object found */
-#define SD_RES_EIO 0x03 /* I/O error */
-#define SD_RES_VDI_EXIST 0x04 /* Vdi exists already */
-#define SD_RES_INVALID_PARMS 0x05 /* Invalid parameters */
-#define SD_RES_SYSTEM_ERROR 0x06 /* System error */
-#define SD_RES_VDI_LOCKED 0x07 /* Vdi is locked */
-#define SD_RES_NO_VDI 0x08 /* No vdi found */
-#define SD_RES_NO_BASE_VDI 0x09 /* No base vdi found */
-#define SD_RES_VDI_READ 0x0A /* Cannot read requested vdi */
-#define SD_RES_VDI_WRITE 0x0B /* Cannot write requested vdi */
-#define SD_RES_BASE_VDI_READ 0x0C /* Cannot read base vdi */
-#define SD_RES_BASE_VDI_WRITE 0x0D /* Cannot write base vdi */
-#define SD_RES_NO_TAG 0x0E /* Requested tag is not found */
-#define SD_RES_STARTUP 0x0F /* Sheepdog is on starting up */
-#define SD_RES_VDI_NOT_LOCKED 0x10 /* Vdi is not locked */
-#define SD_RES_SHUTDOWN 0x11 /* Sheepdog is shutting down */
-#define SD_RES_NO_MEM 0x12 /* Cannot allocate memory */
-#define SD_RES_FULL_VDI 0x13 /* we already have the maximum vdis */
-#define SD_RES_VER_MISMATCH 0x14 /* Protocol version mismatch */
-#define SD_RES_NO_SPACE 0x15 /* Server has no room for new objects */
-#define SD_RES_WAIT_FOR_FORMAT 0x16 /* Waiting for a format operation */
-#define SD_RES_WAIT_FOR_JOIN 0x17 /* Waiting for other nodes joining */
-#define SD_RES_JOIN_FAILED 0x18 /* Target node had failed to join sheepdog */
-#define SD_RES_HALT 0x19 /* Sheepdog is stopped serving IO request */
-#define SD_RES_READONLY 0x1A /* Object is read-only */
-
-/*
- * Object ID rules
- *
- * 0 - 19 (20 bits): data object space
- * 20 - 31 (12 bits): reserved data object space
- * 32 - 55 (24 bits): vdi object space
- * 56 - 59 ( 4 bits): reserved vdi object space
- * 60 - 63 ( 4 bits): object type identifier space
- */
-
-#define VDI_SPACE_SHIFT 32
-#define VDI_BIT (UINT64_C(1) << 63)
-#define VMSTATE_BIT (UINT64_C(1) << 62)
-#define MAX_DATA_OBJS (UINT64_C(1) << 20)
-#define MAX_CHILDREN 1024
-#define SD_MAX_VDI_LEN 256
-#define SD_MAX_VDI_TAG_LEN 256
-#define SD_NR_VDIS (1U << 24)
-#define SD_DATA_OBJ_SIZE (UINT64_C(1) << 22)
-#define SD_MAX_VDI_SIZE (SD_DATA_OBJ_SIZE * MAX_DATA_OBJS)
-#define SD_DEFAULT_BLOCK_SIZE_SHIFT 22
-/*
- * For erasure coding, we use at most SD_EC_MAX_STRIP for data strips and
- * (SD_EC_MAX_STRIP - 1) for parity strips
- *
- * SD_MAX_COPIES is sum of number of data strips and parity strips.
- */
-#define SD_EC_MAX_STRIP 16
-#define SD_MAX_COPIES (SD_EC_MAX_STRIP * 2 - 1)
-
-#define SD_INODE_SIZE (sizeof(SheepdogInode))
-#define CURRENT_VDI_ID 0
-
-#define LOCK_TYPE_NORMAL 0
-#define LOCK_TYPE_SHARED 1 /* for iSCSI multipath */
-
-typedef struct SheepdogReq {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint32_t opcode_specific[8];
-} SheepdogReq;
-
-typedef struct SheepdogRsp {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint32_t result;
- uint32_t opcode_specific[7];
-} SheepdogRsp;
-
-typedef struct SheepdogObjReq {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint64_t oid;
- uint64_t cow_oid;
- uint8_t copies;
- uint8_t copy_policy;
- uint8_t reserved[6];
- uint64_t offset;
-} SheepdogObjReq;
-
-typedef struct SheepdogObjRsp {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint32_t result;
- uint8_t copies;
- uint8_t copy_policy;
- uint8_t reserved[2];
- uint32_t pad[6];
-} SheepdogObjRsp;
-
-typedef struct SheepdogVdiReq {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint64_t vdi_size;
- uint32_t base_vdi_id;
- uint8_t copies;
- uint8_t copy_policy;
- uint8_t store_policy;
- uint8_t block_size_shift;
- uint32_t snapid;
- uint32_t type;
- uint32_t pad[2];
-} SheepdogVdiReq;
-
-typedef struct SheepdogVdiRsp {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint32_t result;
- uint32_t rsvd;
- uint32_t vdi_id;
- uint32_t pad[5];
-} SheepdogVdiRsp;
-
-typedef struct SheepdogClusterRsp {
- uint8_t proto_ver;
- uint8_t opcode;
- uint16_t flags;
- uint32_t epoch;
- uint32_t id;
- uint32_t data_length;
- uint32_t result;
- uint8_t nr_copies;
- uint8_t copy_policy;
- uint8_t block_size_shift;
- uint8_t __pad1;
- uint32_t __pad2[6];
-} SheepdogClusterRsp;
-
-typedef struct SheepdogInode {
- char name[SD_MAX_VDI_LEN];
- char tag[SD_MAX_VDI_TAG_LEN];
- uint64_t ctime;
- uint64_t snap_ctime;
- uint64_t vm_clock_nsec;
- uint64_t vdi_size;
- uint64_t vm_state_size;
- uint16_t copy_policy;
- uint8_t nr_copies;
- uint8_t block_size_shift;
- uint32_t snap_id;
- uint32_t vdi_id;
- uint32_t parent_vdi_id;
- uint32_t child_vdi_id[MAX_CHILDREN];
- uint32_t data_vdi_id[MAX_DATA_OBJS];
-} SheepdogInode;
-
-#define SD_INODE_HEADER_SIZE offsetof(SheepdogInode, data_vdi_id)
-
-/*
- * 64 bit FNV-1a non-zero initial basis
- */
-#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
-
-static void deprecation_warning(void)
-{
- static bool warned;
-
- if (!warned) {
- warn_report("the sheepdog block driver is deprecated");
- warned = true;
- }
-}
-
-/*
- * 64 bit Fowler/Noll/Vo FNV-1a hash code
- */
-static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
-{
- unsigned char *bp = buf;
- unsigned char *be = bp + len;
- while (bp < be) {
- hval ^= (uint64_t) *bp++;
- hval += (hval << 1) + (hval << 4) + (hval << 5) +
- (hval << 7) + (hval << 8) + (hval << 40);
- }
- return hval;
-}
-
-static inline bool is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
-{
- return inode->vdi_id == inode->data_vdi_id[idx];
-}
-
-static inline bool is_data_obj(uint64_t oid)
-{
- return !(VDI_BIT & oid);
-}
-
-static inline uint64_t data_oid_to_idx(uint64_t oid)
-{
- return oid & (MAX_DATA_OBJS - 1);
-}
-
-static inline uint32_t oid_to_vid(uint64_t oid)
-{
- return (oid & ~VDI_BIT) >> VDI_SPACE_SHIFT;
-}
-
-static inline uint64_t vid_to_vdi_oid(uint32_t vid)
-{
- return VDI_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT);
-}
-
-static inline uint64_t vid_to_vmstate_oid(uint32_t vid, uint32_t idx)
-{
- return VMSTATE_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT) | idx;
-}
-
-static inline uint64_t vid_to_data_oid(uint32_t vid, uint32_t idx)
-{
- return ((uint64_t)vid << VDI_SPACE_SHIFT) | idx;
-}
-
-static inline bool is_snapshot(struct SheepdogInode *inode)
-{
- return !!inode->snap_ctime;
-}
-
-static inline size_t count_data_objs(const struct SheepdogInode *inode)
-{
- return DIV_ROUND_UP(inode->vdi_size,
- (1UL << inode->block_size_shift));
-}
-
-typedef struct SheepdogAIOCB SheepdogAIOCB;
-typedef struct BDRVSheepdogState BDRVSheepdogState;
-
-typedef struct AIOReq {
- SheepdogAIOCB *aiocb;
- unsigned int iov_offset;
-
- uint64_t oid;
- uint64_t base_oid;
- uint64_t offset;
- unsigned int data_len;
- uint8_t flags;
- uint32_t id;
- bool create;
-
- QLIST_ENTRY(AIOReq) aio_siblings;
-} AIOReq;
-
-enum AIOCBState {
- AIOCB_WRITE_UDATA,
- AIOCB_READ_UDATA,
- AIOCB_FLUSH_CACHE,
- AIOCB_DISCARD_OBJ,
-};
-
-#define AIOCBOverlapping(x, y) \
- (!(x->max_affect_data_idx < y->min_affect_data_idx \
- || y->max_affect_data_idx < x->min_affect_data_idx))
-
-struct SheepdogAIOCB {
- BDRVSheepdogState *s;
-
- QEMUIOVector *qiov;
-
- int64_t sector_num;
- int nb_sectors;
-
- int ret;
- enum AIOCBState aiocb_type;
-
- Coroutine *coroutine;
- int nr_pending;
-
- uint32_t min_affect_data_idx;
- uint32_t max_affect_data_idx;
-
- /*
- * The difference between affect_data_idx and dirty_data_idx:
- * affect_data_idx represents range of index of all request types.
- * dirty_data_idx represents range of index updated by COW requests.
- * dirty_data_idx is used for updating an inode object.
- */
- uint32_t min_dirty_data_idx;
- uint32_t max_dirty_data_idx;
-
- QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings;
-};
-
-struct BDRVSheepdogState {
- BlockDriverState *bs;
- AioContext *aio_context;
-
- SheepdogInode inode;
-
- char name[SD_MAX_VDI_LEN];
- bool is_snapshot;
- uint32_t cache_flags;
- bool discard_supported;
-
- SocketAddress *addr;
- int fd;
-
- CoMutex lock;
- Coroutine *co_send;
- Coroutine *co_recv;
-
- uint32_t aioreq_seq_num;
-
- /* Every aio request must be linked to either of these queues. */
- QLIST_HEAD(, AIOReq) inflight_aio_head;
- QLIST_HEAD(, AIOReq) failed_aio_head;
-
- CoMutex queue_lock;
- CoQueue overlapping_queue;
- QLIST_HEAD(, SheepdogAIOCB) inflight_aiocb_head;
-};
-
-typedef struct BDRVSheepdogReopenState {
- int fd;
- int cache_flags;
-} BDRVSheepdogReopenState;
-
-static const char *sd_strerror(int err)
-{
- int i;
-
- static const struct {
- int err;
- const char *desc;
- } errors[] = {
- {SD_RES_SUCCESS, "Success"},
- {SD_RES_UNKNOWN, "Unknown error"},
- {SD_RES_NO_OBJ, "No object found"},
- {SD_RES_EIO, "I/O error"},
- {SD_RES_VDI_EXIST, "VDI exists already"},
- {SD_RES_INVALID_PARMS, "Invalid parameters"},
- {SD_RES_SYSTEM_ERROR, "System error"},
- {SD_RES_VDI_LOCKED, "VDI is already locked"},
- {SD_RES_NO_VDI, "No vdi found"},
- {SD_RES_NO_BASE_VDI, "No base VDI found"},
- {SD_RES_VDI_READ, "Failed read the requested VDI"},
- {SD_RES_VDI_WRITE, "Failed to write the requested VDI"},
- {SD_RES_BASE_VDI_READ, "Failed to read the base VDI"},
- {SD_RES_BASE_VDI_WRITE, "Failed to write the base VDI"},
- {SD_RES_NO_TAG, "Failed to find the requested tag"},
- {SD_RES_STARTUP, "The system is still booting"},
- {SD_RES_VDI_NOT_LOCKED, "VDI isn't locked"},
- {SD_RES_SHUTDOWN, "The system is shutting down"},
- {SD_RES_NO_MEM, "Out of memory on the server"},
- {SD_RES_FULL_VDI, "We already have the maximum vdis"},
- {SD_RES_VER_MISMATCH, "Protocol version mismatch"},
- {SD_RES_NO_SPACE, "Server has no space for new objects"},
- {SD_RES_WAIT_FOR_FORMAT, "Sheepdog is waiting for a format operation"},
- {SD_RES_WAIT_FOR_JOIN, "Sheepdog is waiting for other nodes joining"},
- {SD_RES_JOIN_FAILED, "Target node had failed to join sheepdog"},
- {SD_RES_HALT, "Sheepdog is stopped serving IO request"},
- {SD_RES_READONLY, "Object is read-only"},
- };
-
- for (i = 0; i < ARRAY_SIZE(errors); ++i) {
- if (errors[i].err == err) {
- return errors[i].desc;
- }
- }
-
- return "Invalid error code";
-}
-
-/*
- * Sheepdog I/O handling:
- *
- * 1. In sd_co_rw_vector, we send the I/O requests to the server and
- * link the requests to the inflight_list in the
- * BDRVSheepdogState. The function yields while waiting for
- * receiving the response.
- *
- * 2. We receive the response in aio_read_response, the fd handler to
- * the sheepdog connection. We switch back to sd_co_readv/sd_writev
- * after all the requests belonging to the AIOCB are finished. If
- * needed, sd_co_writev will send another requests for the vdi object.
- */
-
-static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
- uint64_t oid, unsigned int data_len,
- uint64_t offset, uint8_t flags, bool create,
- uint64_t base_oid, unsigned int iov_offset)
-{
- AIOReq *aio_req;
-
- aio_req = g_malloc(sizeof(*aio_req));
- aio_req->aiocb = acb;
- aio_req->iov_offset = iov_offset;
- aio_req->oid = oid;
- aio_req->base_oid = base_oid;
- aio_req->offset = offset;
- aio_req->data_len = data_len;
- aio_req->flags = flags;
- aio_req->id = s->aioreq_seq_num++;
- aio_req->create = create;
-
- acb->nr_pending++;
- return aio_req;
-}
-
-static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb)
-{
- SheepdogAIOCB *cb;
-
-retry:
- QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
- if (AIOCBOverlapping(acb, cb)) {
- qemu_co_queue_wait(&s->overlapping_queue, &s->queue_lock);
- goto retry;
- }
- }
-}
-
-static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
- QEMUIOVector *qiov, int64_t sector_num, int nb_sectors,
- int type)
-{
- uint32_t object_size;
-
- object_size = (UINT32_C(1) << s->inode.block_size_shift);
-
- acb->s = s;
-
- acb->qiov = qiov;
-
- acb->sector_num = sector_num;
- acb->nb_sectors = nb_sectors;
-
- acb->coroutine = qemu_coroutine_self();
- acb->ret = 0;
- acb->nr_pending = 0;
-
- acb->min_affect_data_idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size;
- acb->max_affect_data_idx = (acb->sector_num * BDRV_SECTOR_SIZE +
- acb->nb_sectors * BDRV_SECTOR_SIZE) / object_size;
-
- acb->min_dirty_data_idx = UINT32_MAX;
- acb->max_dirty_data_idx = 0;
- acb->aiocb_type = type;
-
- if (type == AIOCB_FLUSH_CACHE) {
- return;
- }
-
- qemu_co_mutex_lock(&s->queue_lock);
- wait_for_overlapping_aiocb(s, acb);
- QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings);
- qemu_co_mutex_unlock(&s->queue_lock);
-}
-
-static SocketAddress *sd_server_config(QDict *options, Error **errp)
-{
- QDict *server = NULL;
- Visitor *iv = NULL;
- SocketAddress *saddr = NULL;
-
- qdict_extract_subqdict(options, &server, "server.");
-
- iv = qobject_input_visitor_new_flat_confused(server, errp);
- if (!iv) {
- goto done;
- }
-
- if (!visit_type_SocketAddress(iv, NULL, &saddr, errp)) {
- goto done;
- }
-
-done:
- visit_free(iv);
- qobject_unref(server);
- return saddr;
-}
-
-/* Return -EIO in case of error, file descriptor on success */
-static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
-{
- int fd;
-
- fd = socket_connect(s->addr, errp);
-
- if (s->addr->type == SOCKET_ADDRESS_TYPE_INET && fd >= 0) {
- int ret = socket_set_nodelay(fd);
- if (ret < 0) {
- warn_report("can't set TCP_NODELAY: %s", strerror(errno));
- }
- }
-
- if (fd >= 0) {
- qemu_set_nonblock(fd);
- } else {
- fd = -EIO;
- }
-
- return fd;
-}
-
-/* Return 0 on success and -errno in case of error */
-static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
- unsigned int *wlen)
-{
- int ret;
-
- ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
- if (ret != sizeof(*hdr)) {
- error_report("failed to send a req, %s", strerror(errno));
- return -errno;
- }
-
- ret = qemu_co_send(sockfd, data, *wlen);
- if (ret != *wlen) {
- error_report("failed to send a req, %s", strerror(errno));
- return -errno;
- }
-
- return ret;
-}
-
-typedef struct SheepdogReqCo {
- int sockfd;
- BlockDriverState *bs;
- AioContext *aio_context;
- SheepdogReq *hdr;
- void *data;
- unsigned int *wlen;
- unsigned int *rlen;
- int ret;
- bool finished;
- Coroutine *co;
-} SheepdogReqCo;
-
-static void restart_co_req(void *opaque)
-{
- SheepdogReqCo *srco = opaque;
-
- aio_co_wake(srco->co);
-}
-
-static coroutine_fn void do_co_req(void *opaque)
-{
- int ret;
- SheepdogReqCo *srco = opaque;
- int sockfd = srco->sockfd;
- SheepdogReq *hdr = srco->hdr;
- void *data = srco->data;
- unsigned int *wlen = srco->wlen;
- unsigned int *rlen = srco->rlen;
-
- srco->co = qemu_coroutine_self();
- aio_set_fd_handler(srco->aio_context, sockfd, false,
- NULL, restart_co_req, NULL, srco);
-
- ret = send_co_req(sockfd, hdr, data, wlen);
- if (ret < 0) {
- goto out;
- }
-
- aio_set_fd_handler(srco->aio_context, sockfd, false,
- restart_co_req, NULL, NULL, srco);
-
- ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
- if (ret != sizeof(*hdr)) {
- error_report("failed to get a rsp, %s", strerror(errno));
- ret = -errno;
- goto out;
- }
-
- if (*rlen > hdr->data_length) {
- *rlen = hdr->data_length;
- }
-
- if (*rlen) {
- ret = qemu_co_recv(sockfd, data, *rlen);
- if (ret != *rlen) {
- error_report("failed to get the data, %s", strerror(errno));
- ret = -errno;
- goto out;
- }
- }
- ret = 0;
-out:
- /* there is at most one request for this sockfd, so it is safe to
- * set each handler to NULL. */
- aio_set_fd_handler(srco->aio_context, sockfd, false,
- NULL, NULL, NULL, NULL);
-
- srco->co = NULL;
- srco->ret = ret;
- /* Set srco->finished before reading bs->wakeup. */
- qatomic_mb_set(&srco->finished, true);
- if (srco->bs) {
- bdrv_wakeup(srco->bs);
- }
-}
-
-/*
- * Send the request to the sheep in a synchronous manner.
- *
- * Return 0 on success, -errno in case of error.
- */
-static int do_req(int sockfd, BlockDriverState *bs, SheepdogReq *hdr,
- void *data, unsigned int *wlen, unsigned int *rlen)
-{
- Coroutine *co;
- SheepdogReqCo srco = {
- .sockfd = sockfd,
- .aio_context = bs ? bdrv_get_aio_context(bs) : qemu_get_aio_context(),
- .bs = bs,
- .hdr = hdr,
- .data = data,
- .wlen = wlen,
- .rlen = rlen,
- .ret = 0,
- .finished = false,
- };
-
- if (qemu_in_coroutine()) {
- do_co_req(&srco);
- } else {
- co = qemu_coroutine_create(do_co_req, &srco);
- if (bs) {
- bdrv_coroutine_enter(bs, co);
- BDRV_POLL_WHILE(bs, !srco.finished);
- } else {
- qemu_coroutine_enter(co);
- while (!srco.finished) {
- aio_poll(qemu_get_aio_context(), true);
- }
- }
- }
-
- return srco.ret;
-}
-
-static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
- struct iovec *iov, int niov,
- enum AIOCBState aiocb_type);
-static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
-static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
-static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
-static void co_write_request(void *opaque);
-
-static coroutine_fn void reconnect_to_sdog(void *opaque)
-{
- BDRVSheepdogState *s = opaque;
- AIOReq *aio_req, *next;
-
- aio_set_fd_handler(s->aio_context, s->fd, false, NULL,
- NULL, NULL, NULL);
- close(s->fd);
- s->fd = -1;
-
- /* Wait for outstanding write requests to be completed. */
- while (s->co_send != NULL) {
- co_write_request(opaque);
- }
-
- /* Try to reconnect the sheepdog server every one second. */
- while (s->fd < 0) {
- Error *local_err = NULL;
- s->fd = get_sheep_fd(s, &local_err);
- if (s->fd < 0) {
- trace_sheepdog_reconnect_to_sdog();
- error_report_err(local_err);
- qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, NANOSECONDS_PER_SECOND);
- }
- };
-
- /*
- * Now we have to resend all the request in the inflight queue. However,
- * resend_aioreq() can yield and newly created requests can be added to the
- * inflight queue before the coroutine is resumed. To avoid mixing them, we
- * have to move all the inflight requests to the failed queue before
- * resend_aioreq() is called.
- */
- qemu_co_mutex_lock(&s->queue_lock);
- QLIST_FOREACH_SAFE(aio_req, &s->inflight_aio_head, aio_siblings, next) {
- QLIST_REMOVE(aio_req, aio_siblings);
- QLIST_INSERT_HEAD(&s->failed_aio_head, aio_req, aio_siblings);
- }
-
- /* Resend all the failed aio requests. */
- while (!QLIST_EMPTY(&s->failed_aio_head)) {
- aio_req = QLIST_FIRST(&s->failed_aio_head);
- QLIST_REMOVE(aio_req, aio_siblings);
- qemu_co_mutex_unlock(&s->queue_lock);
- resend_aioreq(s, aio_req);
- qemu_co_mutex_lock(&s->queue_lock);
- }
- qemu_co_mutex_unlock(&s->queue_lock);
-}
-
-/*
- * Receive responses of the I/O requests.
- *
- * This function is registered as a fd handler, and called from the
- * main loop when s->fd is ready for reading responses.
- */
-static void coroutine_fn aio_read_response(void *opaque)
-{
- SheepdogObjRsp rsp;
- BDRVSheepdogState *s = opaque;
- int fd = s->fd;
- int ret;
- AIOReq *aio_req = NULL;
- SheepdogAIOCB *acb;
- uint64_t idx;
-
- /* read a header */
- ret = qemu_co_recv(fd, &rsp, sizeof(rsp));
- if (ret != sizeof(rsp)) {
- error_report("failed to get the header, %s", strerror(errno));
- goto err;
- }
-
- /* find the right aio_req from the inflight aio list */
- QLIST_FOREACH(aio_req, &s->inflight_aio_head, aio_siblings) {
- if (aio_req->id == rsp.id) {
- break;
- }
- }
- if (!aio_req) {
- error_report("cannot find aio_req %x", rsp.id);
- goto err;
- }
-
- acb = aio_req->aiocb;
-
- switch (acb->aiocb_type) {
- case AIOCB_WRITE_UDATA:
- if (!is_data_obj(aio_req->oid)) {
- break;
- }
- idx = data_oid_to_idx(aio_req->oid);
-
- if (aio_req->create) {
- /*
- * If the object is newly created one, we need to update
- * the vdi object (metadata object). min_dirty_data_idx
- * and max_dirty_data_idx are changed to include updated
- * index between them.
- */
- if (rsp.result == SD_RES_SUCCESS) {
- s->inode.data_vdi_id[idx] = s->inode.vdi_id;
- acb->max_dirty_data_idx = MAX(idx, acb->max_dirty_data_idx);
- acb->min_dirty_data_idx = MIN(idx, acb->min_dirty_data_idx);
- }
- }
- break;
- case AIOCB_READ_UDATA:
- ret = qemu_co_recvv(fd, acb->qiov->iov, acb->qiov->niov,
- aio_req->iov_offset, rsp.data_length);
- if (ret != rsp.data_length) {
- error_report("failed to get the data, %s", strerror(errno));
- goto err;
- }
- break;
- case AIOCB_FLUSH_CACHE:
- if (rsp.result == SD_RES_INVALID_PARMS) {
- trace_sheepdog_aio_read_response();
- s->cache_flags = SD_FLAG_CMD_DIRECT;
- rsp.result = SD_RES_SUCCESS;
- }
- break;
- case AIOCB_DISCARD_OBJ:
- switch (rsp.result) {
- case SD_RES_INVALID_PARMS:
- error_report("server doesn't support discard command");
- rsp.result = SD_RES_SUCCESS;
- s->discard_supported = false;
- break;
- default:
- break;
- }
- }
-
- /* No more data for this aio_req (reload_inode below uses its own file
- * descriptor handler which doesn't use co_recv).
- */
- s->co_recv = NULL;
-
- qemu_co_mutex_lock(&s->queue_lock);
- QLIST_REMOVE(aio_req, aio_siblings);
- qemu_co_mutex_unlock(&s->queue_lock);
-
- switch (rsp.result) {
- case SD_RES_SUCCESS:
- break;
- case SD_RES_READONLY:
- if (s->inode.vdi_id == oid_to_vid(aio_req->oid)) {
- ret = reload_inode(s, 0, "");
- if (ret < 0) {
- goto err;
- }
- }
- if (is_data_obj(aio_req->oid)) {
- aio_req->oid = vid_to_data_oid(s->inode.vdi_id,
- data_oid_to_idx(aio_req->oid));
- } else {
- aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id);
- }
- resend_aioreq(s, aio_req);
- return;
- default:
- acb->ret = -EIO;
- error_report("%s", sd_strerror(rsp.result));
- break;
- }
-
- g_free(aio_req);
-
- if (!--acb->nr_pending) {
- /*
- * We've finished all requests which belong to the AIOCB, so
- * we can switch back to sd_co_readv/writev now.
- */
- aio_co_wake(acb->coroutine);
- }
-
- return;
-
-err:
- reconnect_to_sdog(opaque);
-}
-
-static void co_read_response(void *opaque)
-{
- BDRVSheepdogState *s = opaque;
-
- if (!s->co_recv) {
- s->co_recv = qemu_coroutine_create(aio_read_response, opaque);
- }
-
- aio_co_enter(s->aio_context, s->co_recv);
-}
-
-static void co_write_request(void *opaque)
-{
- BDRVSheepdogState *s = opaque;
-
- aio_co_wake(s->co_send);
-}
-
-/*
- * Return a socket descriptor to read/write objects.
- *
- * We cannot use this descriptor for other operations because
- * the block driver may be on waiting response from the server.
- */
-static int get_sheep_fd(BDRVSheepdogState *s, Error **errp)
-{
- int fd;
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- aio_set_fd_handler(s->aio_context, fd, false,
- co_read_response, NULL, NULL, s);
- return fd;
-}
-
-/*
- * Parse numeric snapshot ID in @str
- * If @str can't be parsed as number, return false.
- * Else, if the number is zero or too large, set *@snapid to zero and
- * return true.
- * Else, set *@snapid to the number and return true.
- */
-static bool sd_parse_snapid(const char *str, uint32_t *snapid)
-{
- unsigned long ul;
- int ret;
-
- ret = qemu_strtoul(str, NULL, 10, &ul);
- if (ret == -ERANGE) {
- ul = ret = 0;
- }
- if (ret) {
- return false;
- }
- if (ul > UINT32_MAX) {
- ul = 0;
- }
-
- *snapid = ul;
- return true;
-}
-
-static bool sd_parse_snapid_or_tag(const char *str,
- uint32_t *snapid, char tag[])
-{
- if (!sd_parse_snapid(str, snapid)) {
- *snapid = 0;
- if (g_strlcpy(tag, str, SD_MAX_VDI_TAG_LEN) >= SD_MAX_VDI_TAG_LEN) {
- return false;
- }
- } else if (!*snapid) {
- return false;
- } else {
- tag[0] = 0;
- }
- return true;
-}
-
-typedef struct {
- const char *path; /* non-null iff transport is tcp */
- const char *host; /* valid when transport is tcp */
- int port; /* valid when transport is tcp */
- char vdi[SD_MAX_VDI_LEN];
- char tag[SD_MAX_VDI_TAG_LEN];
- uint32_t snap_id;
- /* Remainder is only for sd_config_done() */
- URI *uri;
- QueryParams *qp;
-} SheepdogConfig;
-
-static void sd_config_done(SheepdogConfig *cfg)
-{
- if (cfg->qp) {
- query_params_free(cfg->qp);
- }
- uri_free(cfg->uri);
-}
-
-static void sd_parse_uri(SheepdogConfig *cfg, const char *filename,
- Error **errp)
-{
- Error *err = NULL;
- QueryParams *qp = NULL;
- bool is_unix;
- URI *uri;
-
- memset(cfg, 0, sizeof(*cfg));
-
- cfg->uri = uri = uri_parse(filename);
- if (!uri) {
- error_setg(&err, "invalid URI '%s'", filename);
- goto out;
- }
-
- /* transport */
- if (!g_strcmp0(uri->scheme, "sheepdog")) {
- is_unix = false;
- } else if (!g_strcmp0(uri->scheme, "sheepdog+tcp")) {
- is_unix = false;
- } else if (!g_strcmp0(uri->scheme, "sheepdog+unix")) {
- is_unix = true;
- } else {
- error_setg(&err, "URI scheme must be 'sheepdog', 'sheepdog+tcp',"
- " or 'sheepdog+unix'");
- goto out;
- }
-
- if (uri->path == NULL || !strcmp(uri->path, "/")) {
- error_setg(&err, "missing file path in URI");
- goto out;
- }
- if (g_strlcpy(cfg->vdi, uri->path + 1, SD_MAX_VDI_LEN)
- >= SD_MAX_VDI_LEN) {
- error_setg(&err, "VDI name is too long");
- goto out;
- }
-
- cfg->qp = qp = query_params_parse(uri->query);
-
- if (is_unix) {
- /* sheepdog+unix:///vdiname?socket=path */
- if (uri->server || uri->port) {
- error_setg(&err, "URI scheme %s doesn't accept a server address",
- uri->scheme);
- goto out;
- }
- if (!qp->n) {
- error_setg(&err,
- "URI scheme %s requires query parameter 'socket'",
- uri->scheme);
- goto out;
- }
- if (qp->n != 1 || strcmp(qp->p[0].name, "socket")) {
- error_setg(&err, "unexpected query parameters");
- goto out;
- }
- cfg->path = qp->p[0].value;
- } else {
- /* sheepdog[+tcp]://[host:port]/vdiname */
- if (qp->n) {
- error_setg(&err, "unexpected query parameters");
- goto out;
- }
- cfg->host = uri->server;
- cfg->port = uri->port;
- }
-
- /* snapshot tag */
- if (uri->fragment) {
- if (!sd_parse_snapid_or_tag(uri->fragment,
- &cfg->snap_id, cfg->tag)) {
- error_setg(&err, "'%s' is not a valid snapshot ID",
- uri->fragment);
- goto out;
- }
- } else {
- cfg->snap_id = CURRENT_VDI_ID; /* search current vdi */
- }
-
-out:
- if (err) {
- error_propagate(errp, err);
- sd_config_done(cfg);
- }
-}
-
-/*
- * Parse a filename (old syntax)
- *
- * filename must be one of the following formats:
- * 1. [vdiname]
- * 2. [vdiname]:[snapid]
- * 3. [vdiname]:[tag]
- * 4. [hostname]:[port]:[vdiname]
- * 5. [hostname]:[port]:[vdiname]:[snapid]
- * 6. [hostname]:[port]:[vdiname]:[tag]
- *
- * You can boot from the snapshot images by specifying `snapid` or
- * `tag'.
- *
- * You can run VMs outside the Sheepdog cluster by specifying
- * `hostname' and `port' (experimental).
- */
-static void parse_vdiname(SheepdogConfig *cfg, const char *filename,
- Error **errp)
-{
- Error *err = NULL;
- char *p, *q, *uri;
- const char *host_spec, *vdi_spec;
- int nr_sep;
-
- strstart(filename, "sheepdog:", &filename);
- p = q = g_strdup(filename);
-
- /* count the number of separators */
- nr_sep = 0;
- while (*p) {
- if (*p == ':') {
- nr_sep++;
- }
- p++;
- }
- p = q;
-
- /* use the first two tokens as host_spec. */
- if (nr_sep >= 2) {
- host_spec = p;
- p = strchr(p, ':');
- p++;
- p = strchr(p, ':');
- *p++ = '\0';
- } else {
- host_spec = "";
- }
-
- vdi_spec = p;
-
- p = strchr(vdi_spec, ':');
- if (p) {
- *p++ = '#';
- }
-
- uri = g_strdup_printf("sheepdog://%s/%s", host_spec, vdi_spec);
-
- /*
- * FIXME We to escape URI meta-characters, e.g. "x?y=z"
- * produces "sheepdog://x?y=z". Because of that ...
- */
- sd_parse_uri(cfg, uri, &err);
- if (err) {
- /*
- * ... this can fail, but the error message is misleading.
- * Replace it by the traditional useless one until the
- * escaping is fixed.
- */
- error_free(err);
- error_setg(errp, "Can't parse filename");
- }
-
- g_free(q);
- g_free(uri);
-}
-
-static void sd_parse_filename(const char *filename, QDict *options,
- Error **errp)
-{
- Error *err = NULL;
- SheepdogConfig cfg;
- char buf[32];
-
- if (strstr(filename, "://")) {
- sd_parse_uri(&cfg, filename, &err);
- } else {
- parse_vdiname(&cfg, filename, &err);
- }
- if (err) {
- error_propagate(errp, err);
- return;
- }
-
- if (cfg.path) {
- qdict_set_default_str(options, "server.path", cfg.path);
- qdict_set_default_str(options, "server.type", "unix");
- } else {
- qdict_set_default_str(options, "server.type", "inet");
- qdict_set_default_str(options, "server.host",
- cfg.host ?: SD_DEFAULT_ADDR);
- snprintf(buf, sizeof(buf), "%d", cfg.port ?: SD_DEFAULT_PORT);
- qdict_set_default_str(options, "server.port", buf);
- }
- qdict_set_default_str(options, "vdi", cfg.vdi);
- qdict_set_default_str(options, "tag", cfg.tag);
- if (cfg.snap_id) {
- snprintf(buf, sizeof(buf), "%d", cfg.snap_id);
- qdict_set_default_str(options, "snap-id", buf);
- }
-
- sd_config_done(&cfg);
-}
-
-static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
- uint32_t snapid, const char *tag, uint32_t *vid,
- bool lock, Error **errp)
-{
- int ret, fd;
- SheepdogVdiReq hdr;
- SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
- unsigned int wlen, rlen = 0;
- char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN] QEMU_NONSTRING;
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- /* This pair of strncpy calls ensures that the buffer is zero-filled,
- * which is desirable since we'll soon be sending those bytes, and
- * don't want the send_req to read uninitialized data.
- */
- strncpy(buf, filename, SD_MAX_VDI_LEN);
- strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN);
-
- memset(&hdr, 0, sizeof(hdr));
- if (lock) {
- hdr.opcode = SD_OP_LOCK_VDI;
- hdr.type = LOCK_TYPE_NORMAL;
- } else {
- hdr.opcode = SD_OP_GET_VDI_INFO;
- }
- wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
- hdr.proto_ver = SD_PROTO_VER;
- hdr.data_length = wlen;
- hdr.snapid = snapid;
- hdr.flags = SD_FLAG_CMD_WRITE;
-
- ret = do_req(fd, s->bs, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
- if (ret) {
- error_setg_errno(errp, -ret, "cannot get vdi info");
- goto out;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s",
- sd_strerror(rsp->result), filename, snapid, tag);
- if (rsp->result == SD_RES_NO_VDI) {
- ret = -ENOENT;
- } else if (rsp->result == SD_RES_VDI_LOCKED) {
- ret = -EBUSY;
- } else {
- ret = -EIO;
- }
- goto out;
- }
- *vid = rsp->vdi_id;
-
- ret = 0;
-out:
- closesocket(fd);
- return ret;
-}
-
-static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
- struct iovec *iov, int niov,
- enum AIOCBState aiocb_type)
-{
- int nr_copies = s->inode.nr_copies;
- SheepdogObjReq hdr;
- unsigned int wlen = 0;
- int ret;
- uint64_t oid = aio_req->oid;
- unsigned int datalen = aio_req->data_len;
- uint64_t offset = aio_req->offset;
- uint8_t flags = aio_req->flags;
- uint64_t old_oid = aio_req->base_oid;
- bool create = aio_req->create;
-
- qemu_co_mutex_lock(&s->queue_lock);
- QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
- qemu_co_mutex_unlock(&s->queue_lock);
-
- if (!nr_copies) {
- error_report("bug");
- }
-
- memset(&hdr, 0, sizeof(hdr));
-
- switch (aiocb_type) {
- case AIOCB_FLUSH_CACHE:
- hdr.opcode = SD_OP_FLUSH_VDI;
- break;
- case AIOCB_READ_UDATA:
- hdr.opcode = SD_OP_READ_OBJ;
- hdr.flags = flags;
- break;
- case AIOCB_WRITE_UDATA:
- if (create) {
- hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
- } else {
- hdr.opcode = SD_OP_WRITE_OBJ;
- }
- wlen = datalen;
- hdr.flags = SD_FLAG_CMD_WRITE | flags;
- break;
- case AIOCB_DISCARD_OBJ:
- hdr.opcode = SD_OP_WRITE_OBJ;
- hdr.flags = SD_FLAG_CMD_WRITE | flags;
- s->inode.data_vdi_id[data_oid_to_idx(oid)] = 0;
- offset = offsetof(SheepdogInode,
- data_vdi_id[data_oid_to_idx(oid)]);
- oid = vid_to_vdi_oid(s->inode.vdi_id);
- wlen = datalen = sizeof(uint32_t);
- break;
- }
-
- if (s->cache_flags) {
- hdr.flags |= s->cache_flags;
- }
-
- hdr.oid = oid;
- hdr.cow_oid = old_oid;
- hdr.copies = s->inode.nr_copies;
-
- hdr.data_length = datalen;
- hdr.offset = offset;
-
- hdr.id = aio_req->id;
-
- qemu_co_mutex_lock(&s->lock);
- s->co_send = qemu_coroutine_self();
- aio_set_fd_handler(s->aio_context, s->fd, false,
- co_read_response, co_write_request, NULL, s);
- socket_set_cork(s->fd, 1);
-
- /* send a header */
- ret = qemu_co_send(s->fd, &hdr, sizeof(hdr));
- if (ret != sizeof(hdr)) {
- error_report("failed to send a req, %s", strerror(errno));
- goto out;
- }
-
- if (wlen) {
- ret = qemu_co_sendv(s->fd, iov, niov, aio_req->iov_offset, wlen);
- if (ret != wlen) {
- error_report("failed to send a data, %s", strerror(errno));
- }
- }
-out:
- socket_set_cork(s->fd, 0);
- aio_set_fd_handler(s->aio_context, s->fd, false,
- co_read_response, NULL, NULL, s);
- s->co_send = NULL;
- qemu_co_mutex_unlock(&s->lock);
-}
-
-static int read_write_object(int fd, BlockDriverState *bs, char *buf,
- uint64_t oid, uint8_t copies,
- unsigned int datalen, uint64_t offset,
- bool write, bool create, uint32_t cache_flags)
-{
- SheepdogObjReq hdr;
- SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr;
- unsigned int wlen, rlen;
- int ret;
-
- memset(&hdr, 0, sizeof(hdr));
-
- if (write) {
- wlen = datalen;
- rlen = 0;
- hdr.flags = SD_FLAG_CMD_WRITE;
- if (create) {
- hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ;
- } else {
- hdr.opcode = SD_OP_WRITE_OBJ;
- }
- } else {
- wlen = 0;
- rlen = datalen;
- hdr.opcode = SD_OP_READ_OBJ;
- }
-
- hdr.flags |= cache_flags;
-
- hdr.oid = oid;
- hdr.data_length = datalen;
- hdr.offset = offset;
- hdr.copies = copies;
-
- ret = do_req(fd, bs, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
- if (ret) {
- error_report("failed to send a request to the sheep");
- return ret;
- }
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- return 0;
- default:
- error_report("%s", sd_strerror(rsp->result));
- return -EIO;
- }
-}
-
-static int read_object(int fd, BlockDriverState *bs, char *buf,
- uint64_t oid, uint8_t copies,
- unsigned int datalen, uint64_t offset,
- uint32_t cache_flags)
-{
- return read_write_object(fd, bs, buf, oid, copies,
- datalen, offset, false,
- false, cache_flags);
-}
-
-static int write_object(int fd, BlockDriverState *bs, char *buf,
- uint64_t oid, uint8_t copies,
- unsigned int datalen, uint64_t offset, bool create,
- uint32_t cache_flags)
-{
- return read_write_object(fd, bs, buf, oid, copies,
- datalen, offset, true,
- create, cache_flags);
-}
-
-/* update inode with the latest state */
-static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag)
-{
- Error *local_err = NULL;
- SheepdogInode *inode;
- int ret = 0, fd;
- uint32_t vid = 0;
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- return -EIO;
- }
-
- inode = g_malloc(SD_INODE_HEADER_SIZE);
-
- ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err);
- if (ret) {
- error_report_err(local_err);
- goto out;
- }
-
- ret = read_object(fd, s->bs, (char *)inode, vid_to_vdi_oid(vid),
- s->inode.nr_copies, SD_INODE_HEADER_SIZE, 0,
- s->cache_flags);
- if (ret < 0) {
- goto out;
- }
-
- if (inode->vdi_id != s->inode.vdi_id) {
- memcpy(&s->inode, inode, SD_INODE_HEADER_SIZE);
- }
-
-out:
- g_free(inode);
- closesocket(fd);
-
- return ret;
-}
-
-static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
-{
- SheepdogAIOCB *acb = aio_req->aiocb;
-
- aio_req->create = false;
-
- /* check whether this request becomes a CoW one */
- if (acb->aiocb_type == AIOCB_WRITE_UDATA && is_data_obj(aio_req->oid)) {
- int idx = data_oid_to_idx(aio_req->oid);
-
- if (is_data_obj_writable(&s->inode, idx)) {
- goto out;
- }
-
- if (s->inode.data_vdi_id[idx]) {
- aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx);
- aio_req->flags |= SD_FLAG_CMD_COW;
- }
- aio_req->create = true;
- }
-out:
- if (is_data_obj(aio_req->oid)) {
- add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
- acb->aiocb_type);
- } else {
- struct iovec iov;
- iov.iov_base = &s->inode;
- iov.iov_len = sizeof(s->inode);
- add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
- }
-}
-
-static void sd_detach_aio_context(BlockDriverState *bs)
-{
- BDRVSheepdogState *s = bs->opaque;
-
- aio_set_fd_handler(s->aio_context, s->fd, false, NULL,
- NULL, NULL, NULL);
-}
-
-static void sd_attach_aio_context(BlockDriverState *bs,
- AioContext *new_context)
-{
- BDRVSheepdogState *s = bs->opaque;
-
- s->aio_context = new_context;
- aio_set_fd_handler(new_context, s->fd, false,
- co_read_response, NULL, NULL, s);
-}
-
-static QemuOptsList runtime_opts = {
- .name = "sheepdog",
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
- .desc = {
- {
- .name = "vdi",
- .type = QEMU_OPT_STRING,
- },
- {
- .name = "snap-id",
- .type = QEMU_OPT_NUMBER,
- },
- {
- .name = "tag",
- .type = QEMU_OPT_STRING,
- },
- { /* end of list */ }
- },
-};
-
-static int sd_open(BlockDriverState *bs, QDict *options, int flags,
- Error **errp)
-{
- int ret, fd;
- uint32_t vid = 0;
- BDRVSheepdogState *s = bs->opaque;
- const char *vdi, *snap_id_str, *tag;
- uint64_t snap_id;
- char *buf = NULL;
- QemuOpts *opts;
-
- deprecation_warning();
-
- s->bs = bs;
- s->aio_context = bdrv_get_aio_context(bs);
-
- opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
- if (!qemu_opts_absorb_qdict(opts, options, errp)) {
- ret = -EINVAL;
- goto err_no_fd;
- }
-
- s->addr = sd_server_config(options, errp);
- if (!s->addr) {
- ret = -EINVAL;
- goto err_no_fd;
- }
-
- vdi = qemu_opt_get(opts, "vdi");
- snap_id_str = qemu_opt_get(opts, "snap-id");
- snap_id = qemu_opt_get_number(opts, "snap-id", CURRENT_VDI_ID);
- tag = qemu_opt_get(opts, "tag");
-
- if (!vdi) {
- error_setg(errp, "parameter 'vdi' is missing");
- ret = -EINVAL;
- goto err_no_fd;
- }
- if (strlen(vdi) >= SD_MAX_VDI_LEN) {
- error_setg(errp, "value of parameter 'vdi' is too long");
- ret = -EINVAL;
- goto err_no_fd;
- }
-
- if (snap_id > UINT32_MAX) {
- snap_id = 0;
- }
- if (snap_id_str && !snap_id) {
- error_setg(errp, "'snap-id=%s' is not a valid snapshot ID",
- snap_id_str);
- ret = -EINVAL;
- goto err_no_fd;
- }
-
- if (!tag) {
- tag = "";
- }
- if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) {
- error_setg(errp, "value of parameter 'tag' is too long");
- ret = -EINVAL;
- goto err_no_fd;
- }
-
- QLIST_INIT(&s->inflight_aio_head);
- QLIST_INIT(&s->failed_aio_head);
- QLIST_INIT(&s->inflight_aiocb_head);
-
- s->fd = get_sheep_fd(s, errp);
- if (s->fd < 0) {
- ret = s->fd;
- goto err_no_fd;
- }
-
- ret = find_vdi_name(s, vdi, (uint32_t)snap_id, tag, &vid, true, errp);
- if (ret) {
- goto err;
- }
-
- /*
- * QEMU block layer emulates writethrough cache as 'writeback + flush', so
- * we always set SD_FLAG_CMD_CACHE (writeback cache) as default.
- */
- s->cache_flags = SD_FLAG_CMD_CACHE;
- if (flags & BDRV_O_NOCACHE) {
- s->cache_flags = SD_FLAG_CMD_DIRECT;
- }
- s->discard_supported = true;
-
- if (snap_id || tag[0]) {
- trace_sheepdog_open(vid);
- s->is_snapshot = true;
- }
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- ret = fd;
- goto err;
- }
-
- buf = g_malloc(SD_INODE_SIZE);
- ret = read_object(fd, s->bs, buf, vid_to_vdi_oid(vid),
- 0, SD_INODE_SIZE, 0, s->cache_flags);
-
- closesocket(fd);
-
- if (ret) {
- error_setg(errp, "Can't read snapshot inode");
- goto err;
- }
-
- memcpy(&s->inode, buf, sizeof(s->inode));
-
- bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE;
- bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
- pstrcpy(s->name, sizeof(s->name), vdi);
- qemu_co_mutex_init(&s->lock);
- qemu_co_mutex_init(&s->queue_lock);
- qemu_co_queue_init(&s->overlapping_queue);
- qemu_opts_del(opts);
- g_free(buf);
- return 0;
-
-err:
- aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd,
- false, NULL, NULL, NULL, NULL);
- closesocket(s->fd);
-err_no_fd:
- qemu_opts_del(opts);
- g_free(buf);
- return ret;
-}
-
-static int sd_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue,
- Error **errp)
-{
- BDRVSheepdogState *s = state->bs->opaque;
- BDRVSheepdogReopenState *re_s;
- int ret = 0;
-
- re_s = state->opaque = g_new0(BDRVSheepdogReopenState, 1);
-
- re_s->cache_flags = SD_FLAG_CMD_CACHE;
- if (state->flags & BDRV_O_NOCACHE) {
- re_s->cache_flags = SD_FLAG_CMD_DIRECT;
- }
-
- re_s->fd = get_sheep_fd(s, errp);
- if (re_s->fd < 0) {
- ret = re_s->fd;
- return ret;
- }
-
- return ret;
-}
-
-static void sd_reopen_commit(BDRVReopenState *state)
-{
- BDRVSheepdogReopenState *re_s = state->opaque;
- BDRVSheepdogState *s = state->bs->opaque;
-
- if (s->fd) {
- aio_set_fd_handler(s->aio_context, s->fd, false,
- NULL, NULL, NULL, NULL);
- closesocket(s->fd);
- }
-
- s->fd = re_s->fd;
- s->cache_flags = re_s->cache_flags;
-
- g_free(state->opaque);
- state->opaque = NULL;
-
- return;
-}
-
-static void sd_reopen_abort(BDRVReopenState *state)
-{
- BDRVSheepdogReopenState *re_s = state->opaque;
- BDRVSheepdogState *s = state->bs->opaque;
-
- if (re_s == NULL) {
- return;
- }
-
- if (re_s->fd) {
- aio_set_fd_handler(s->aio_context, re_s->fd, false,
- NULL, NULL, NULL, NULL);
- closesocket(re_s->fd);
- }
-
- g_free(state->opaque);
- state->opaque = NULL;
-
- return;
-}
-
-static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
- Error **errp)
-{
- SheepdogVdiReq hdr;
- SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
- int fd, ret;
- unsigned int wlen, rlen = 0;
- char buf[SD_MAX_VDI_LEN];
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- /* FIXME: would it be better to fail (e.g., return -EIO) when filename
- * does not fit in buf? For now, just truncate and avoid buffer overrun.
- */
- memset(buf, 0, sizeof(buf));
- pstrcpy(buf, sizeof(buf), s->name);
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.opcode = SD_OP_NEW_VDI;
- hdr.base_vdi_id = s->inode.vdi_id;
-
- wlen = SD_MAX_VDI_LEN;
-
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.snapid = snapshot;
-
- hdr.data_length = wlen;
- hdr.vdi_size = s->inode.vdi_size;
- hdr.copy_policy = s->inode.copy_policy;
- hdr.copies = s->inode.nr_copies;
- hdr.block_size_shift = s->inode.block_size_shift;
-
- ret = do_req(fd, NULL, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
-
- closesocket(fd);
-
- if (ret) {
- error_setg_errno(errp, -ret, "create failed");
- return ret;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name);
- return -EIO;
- }
-
- if (vdi_id) {
- *vdi_id = rsp->vdi_id;
- }
-
- return 0;
-}
-
-static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size,
- Error **errp)
-{
- BlockBackend *blk = NULL;
- BDRVSheepdogState *base = bs->opaque;
- unsigned long buf_size;
- uint32_t idx, max_idx;
- uint32_t object_size;
- void *buf = NULL;
- int ret;
-
- blk = blk_new_with_bs(bs,
- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
- BLK_PERM_ALL, errp);
-
- if (!blk) {
- ret = -EPERM;
- goto out_with_err_set;
- }
-
- blk_set_allow_write_beyond_eof(blk, true);
-
- object_size = (UINT32_C(1) << base->inode.block_size_shift);
- buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
- buf = g_malloc0(buf_size);
-
- max_idx = DIV_ROUND_UP(new_size, buf_size);
-
- for (idx = old_size / buf_size; idx < max_idx; idx++) {
- /*
- * The created image can be a cloned image, so we need to read
- * a data from the source image.
- */
- ret = blk_pread(blk, idx * buf_size, buf, buf_size);
- if (ret < 0) {
- goto out;
- }
- ret = blk_pwrite(blk, idx * buf_size, buf, buf_size, 0);
- if (ret < 0) {
- goto out;
- }
- }
-
- ret = 0;
-out:
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Can't pre-allocate");
- }
-out_with_err_set:
- blk_unref(blk);
- g_free(buf);
-
- return ret;
-}
-
-static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
- Error **errp)
-{
- BlockDriverState *bs;
- Visitor *v;
- QObject *obj = NULL;
- QDict *qdict;
- int ret;
-
- v = qobject_output_visitor_new(&obj);
- visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &error_abort);
- visit_free(v);
-
- qdict = qobject_to(QDict, obj);
- qdict_flatten(qdict);
-
- qdict_put_str(qdict, "driver", "sheepdog");
-
- bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);
- if (bs == NULL) {
- ret = -EIO;
- goto fail;
- }
-
- ret = sd_prealloc(bs, 0, size, errp);
-fail:
- bdrv_unref(bs);
- qobject_unref(qdict);
- return ret;
-}
-
-static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
-{
- struct SheepdogInode *inode = &s->inode;
-
- switch (opt->type) {
- case SHEEPDOG_REDUNDANCY_TYPE_FULL:
- if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) {
- return -EINVAL;
- }
- inode->copy_policy = 0;
- inode->nr_copies = opt->u.full.copies;
- return 0;
-
- case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED:
- {
- int64_t copy = opt->u.erasure_coded.data_strips;
- int64_t parity = opt->u.erasure_coded.parity_strips;
-
- if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
- return -EINVAL;
- }
-
- if (parity >= SD_EC_MAX_STRIP || parity < 1) {
- return -EINVAL;
- }
-
- /*
- * 4 bits for parity and 4 bits for data.
- * We have to compress upper data bits because it can't represent 16
- */
- inode->copy_policy = ((copy / 2) << 4) + parity;
- inode->nr_copies = copy + parity;
- return 0;
- }
-
- default:
- g_assert_not_reached();
- }
-
- return -EINVAL;
-}
-
-/*
- * Sheepdog support two kinds of redundancy, full replication and erasure
- * coding.
- *
- * # create a fully replicated vdi with x copies
- * -o redundancy=x (1 <= x <= SD_MAX_COPIES)
- *
- * # create a erasure coded vdi with x data strips and y parity strips
- * -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
- */
-static SheepdogRedundancy *parse_redundancy_str(const char *opt)
-{
- SheepdogRedundancy *redundancy;
- const char *n1, *n2;
- long copy, parity;
- char p[10];
- int ret;
-
- pstrcpy(p, sizeof(p), opt);
- n1 = strtok(p, ":");
- n2 = strtok(NULL, ":");
-
- if (!n1) {
- return NULL;
- }
-
- ret = qemu_strtol(n1, NULL, 10, &copy);
- if (ret < 0) {
- return NULL;
- }
-
- redundancy = g_new0(SheepdogRedundancy, 1);
- if (!n2) {
- *redundancy = (SheepdogRedundancy) {
- .type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
- .u.full.copies = copy,
- };
- } else {
- ret = qemu_strtol(n2, NULL, 10, &parity);
- if (ret < 0) {
- g_free(redundancy);
- return NULL;
- }
-
- *redundancy = (SheepdogRedundancy) {
- .type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
- .u.erasure_coded = {
- .data_strips = copy,
- .parity_strips = parity,
- },
- };
- }
-
- return redundancy;
-}
-
-static int parse_block_size_shift(BDRVSheepdogState *s,
- BlockdevCreateOptionsSheepdog *opts)
-{
- struct SheepdogInode *inode = &s->inode;
- uint64_t object_size;
- int obj_order;
-
- if (opts->has_object_size) {
- object_size = opts->object_size;
-
- if ((object_size - 1) & object_size) { /* not a power of 2? */
- return -EINVAL;
- }
- obj_order = ctz32(object_size);
- if (obj_order < 20 || obj_order > 31) {
- return -EINVAL;
- }
- inode->block_size_shift = (uint8_t)obj_order;
- }
-
- return 0;
-}
-
-static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
-{
- BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
- int ret = 0;
- uint32_t vid = 0;
- char *backing_file = NULL;
- char *buf = NULL;
- BDRVSheepdogState *s;
- uint64_t max_vdi_size;
- bool prealloc = false;
-
- assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
-
- deprecation_warning();
-
- s = g_new0(BDRVSheepdogState, 1);
-
- /* Steal SocketAddress from QAPI, set NULL to prevent double free */
- s->addr = opts->location->server;
- opts->location->server = NULL;
-
- if (strlen(opts->location->vdi) >= sizeof(s->name)) {
- error_setg(errp, "'vdi' string too long");
- ret = -EINVAL;
- goto out;
- }
- pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
-
- s->inode.vdi_size = opts->size;
- backing_file = opts->backing_file;
-
- if (!opts->has_preallocation) {
- opts->preallocation = PREALLOC_MODE_OFF;
- }
- switch (opts->preallocation) {
- case PREALLOC_MODE_OFF:
- prealloc = false;
- break;
- case PREALLOC_MODE_FULL:
- prealloc = true;
- break;
- default:
- error_setg(errp, "Preallocation mode not supported for Sheepdog");
- ret = -EINVAL;
- goto out;
- }
-
- if (opts->has_redundancy) {
- ret = parse_redundancy(s, opts->redundancy);
- if (ret < 0) {
- error_setg(errp, "Invalid redundancy mode");
- goto out;
- }
- }
- ret = parse_block_size_shift(s, opts);
- if (ret < 0) {
- error_setg(errp, "Invalid object_size."
- " obect_size needs to be power of 2"
- " and be limited from 2^20 to 2^31");
- goto out;
- }
-
- if (opts->has_backing_file) {
- BlockBackend *blk;
- BDRVSheepdogState *base;
- BlockDriver *drv;
-
- /* Currently, only Sheepdog backing image is supported. */
- drv = bdrv_find_protocol(opts->backing_file, true, NULL);
- if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
- error_setg(errp, "backing_file must be a sheepdog image");
- ret = -EINVAL;
- goto out;
- }
-
- blk = blk_new_open(opts->backing_file, NULL, NULL,
- BDRV_O_PROTOCOL, errp);
- if (blk == NULL) {
- ret = -EIO;
- goto out;
- }
-
- base = blk_bs(blk)->opaque;
-
- if (!is_snapshot(&base->inode)) {
- error_setg(errp, "cannot clone from a non snapshot vdi");
- blk_unref(blk);
- ret = -EINVAL;
- goto out;
- }
- s->inode.vdi_id = base->inode.vdi_id;
- blk_unref(blk);
- }
-
- s->aio_context = qemu_get_aio_context();
-
- /* if block_size_shift is not specified, get cluster default value */
- if (s->inode.block_size_shift == 0) {
- SheepdogVdiReq hdr;
- SheepdogClusterRsp *rsp = (SheepdogClusterRsp *)&hdr;
- int fd;
- unsigned int wlen = 0, rlen = 0;
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- ret = fd;
- goto out;
- }
-
- memset(&hdr, 0, sizeof(hdr));
- hdr.opcode = SD_OP_GET_CLUSTER_DEFAULT;
- hdr.proto_ver = SD_PROTO_VER;
-
- ret = do_req(fd, NULL, (SheepdogReq *)&hdr,
- NULL, &wlen, &rlen);
- closesocket(fd);
- if (ret) {
- error_setg_errno(errp, -ret, "failed to get cluster default");
- goto out;
- }
- if (rsp->result == SD_RES_SUCCESS) {
- s->inode.block_size_shift = rsp->block_size_shift;
- } else {
- s->inode.block_size_shift = SD_DEFAULT_BLOCK_SIZE_SHIFT;
- }
- }
-
- max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
-
- if (s->inode.vdi_size > max_vdi_size) {
- error_setg(errp, "An image is too large."
- " The maximum image size is %"PRIu64 "GB",
- max_vdi_size / 1024 / 1024 / 1024);
- ret = -EINVAL;
- goto out;
- }
-
- ret = do_sd_create(s, &vid, 0, errp);
- if (ret) {
- goto out;
- }
-
- if (prealloc) {
- ret = sd_create_prealloc(opts->location, opts->size, errp);
- }
-out:
- g_free(backing_file);
- g_free(buf);
- g_free(s->addr);
- g_free(s);
- return ret;
-}
-
-static int coroutine_fn sd_co_create_opts(BlockDriver *drv,
- const char *filename,
- QemuOpts *opts,
- Error **errp)
-{
- BlockdevCreateOptions *create_options = NULL;
- QDict *qdict = NULL, *location_qdict;
- Visitor *v;
- char *redundancy = NULL;
- Error *local_err = NULL;
- int ret;
- char *backing_fmt = NULL;
-
- redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
- backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
-
- if (backing_fmt && strcmp(backing_fmt, "sheepdog") != 0) {
- error_setg(errp, "backing_file must be a sheepdog image");
- ret = -EINVAL;
- goto fail;
- }
-
- qdict = qemu_opts_to_qdict(opts, NULL);
- qdict_put_str(qdict, "driver", "sheepdog");
-
- location_qdict = qdict_new();
- qdict_put(qdict, "location", location_qdict);
-
- sd_parse_filename(filename, location_qdict, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- ret = -EINVAL;
- goto fail;
- }
-
- qdict_flatten(qdict);
-
- /* Change legacy command line options into QMP ones */
- static const QDictRenames opt_renames[] = {
- { BLOCK_OPT_BACKING_FILE, "backing-file" },
- { BLOCK_OPT_OBJECT_SIZE, "object-size" },
- { NULL, NULL },
- };
-
- if (!qdict_rename_keys(qdict, opt_renames, errp)) {
- ret = -EINVAL;
- goto fail;
- }
-
- /* Get the QAPI object */
- v = qobject_input_visitor_new_flat_confused(qdict, errp);
- if (!v) {
- ret = -EINVAL;
- goto fail;
- }
-
- visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp);
- visit_free(v);
- if (!create_options) {
- ret = -EINVAL;
- goto fail;
- }
-
- assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
- create_options->u.sheepdog.size =
- ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE);
-
- if (redundancy) {
- create_options->u.sheepdog.has_redundancy = true;
- create_options->u.sheepdog.redundancy =
- parse_redundancy_str(redundancy);
- if (create_options->u.sheepdog.redundancy == NULL) {
- error_setg(errp, "Invalid redundancy mode");
- ret = -EINVAL;
- goto fail;
- }
- }
-
- ret = sd_co_create(create_options, errp);
-fail:
- qapi_free_BlockdevCreateOptions(create_options);
- qobject_unref(qdict);
- g_free(redundancy);
- g_free(backing_fmt);
- return ret;
-}
-
-static void sd_close(BlockDriverState *bs)
-{
- Error *local_err = NULL;
- BDRVSheepdogState *s = bs->opaque;
- SheepdogVdiReq hdr;
- SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
- unsigned int wlen, rlen = 0;
- int fd, ret;
-
- trace_sheepdog_close(s->name);
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- return;
- }
-
- memset(&hdr, 0, sizeof(hdr));
-
- hdr.opcode = SD_OP_RELEASE_VDI;
- hdr.type = LOCK_TYPE_NORMAL;
- hdr.base_vdi_id = s->inode.vdi_id;
- wlen = strlen(s->name) + 1;
- hdr.data_length = wlen;
- hdr.flags = SD_FLAG_CMD_WRITE;
-
- ret = do_req(fd, s->bs, (SheepdogReq *)&hdr,
- s->name, &wlen, &rlen);
-
- closesocket(fd);
-
- if (!ret && rsp->result != SD_RES_SUCCESS &&
- rsp->result != SD_RES_VDI_NOT_LOCKED) {
- error_report("%s, %s", sd_strerror(rsp->result), s->name);
- }
-
- aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd,
- false, NULL, NULL, NULL, NULL);
- closesocket(s->fd);
- qapi_free_SocketAddress(s->addr);
-}
-
-static int64_t sd_getlength(BlockDriverState *bs)
-{
- BDRVSheepdogState *s = bs->opaque;
-
- return s->inode.vdi_size;
-}
-
-static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
- bool exact, PreallocMode prealloc,
- BdrvRequestFlags flags, Error **errp)
-{
- BDRVSheepdogState *s = bs->opaque;
- int ret, fd;
- unsigned int datalen;
- uint64_t max_vdi_size;
- int64_t old_size = s->inode.vdi_size;
-
- if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_FULL) {
- error_setg(errp, "Unsupported preallocation mode '%s'",
- PreallocMode_str(prealloc));
- return -ENOTSUP;
- }
-
- max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
- if (offset < old_size) {
- error_setg(errp, "shrinking is not supported");
- return -EINVAL;
- } else if (offset > max_vdi_size) {
- error_setg(errp, "too big image size");
- return -EINVAL;
- }
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- /* we don't need to update entire object */
- datalen = SD_INODE_HEADER_SIZE;
- s->inode.vdi_size = offset;
- ret = write_object(fd, s->bs, (char *)&s->inode,
- vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
- datalen, 0, false, s->cache_flags);
- close(fd);
-
- if (ret < 0) {
- error_setg_errno(errp, -ret, "failed to update an inode");
- return ret;
- }
-
- if (prealloc == PREALLOC_MODE_FULL) {
- ret = sd_prealloc(bs, old_size, offset, errp);
- if (ret < 0) {
- return ret;
- }
- }
-
- return 0;
-}
-
-/*
- * This function is called after writing data objects. If we need to
- * update metadata, this sends a write request to the vdi object.
- */
-static void coroutine_fn sd_write_done(SheepdogAIOCB *acb)
-{
- BDRVSheepdogState *s = acb->s;
- struct iovec iov;
- AIOReq *aio_req;
- uint32_t offset, data_len, mn, mx;
-
- mn = acb->min_dirty_data_idx;
- mx = acb->max_dirty_data_idx;
- if (mn <= mx) {
- /* we need to update the vdi object. */
- ++acb->nr_pending;
- offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) +
- mn * sizeof(s->inode.data_vdi_id[0]);
- data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]);
-
- acb->min_dirty_data_idx = UINT32_MAX;
- acb->max_dirty_data_idx = 0;
-
- iov.iov_base = &s->inode;
- iov.iov_len = sizeof(s->inode);
- aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
- data_len, offset, 0, false, 0, offset);
- add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
- if (--acb->nr_pending) {
- qemu_coroutine_yield();
- }
- }
-}
-
-/* Delete current working VDI on the snapshot chain */
-static bool sd_delete(BDRVSheepdogState *s)
-{
- Error *local_err = NULL;
- unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0;
- SheepdogVdiReq hdr = {
- .opcode = SD_OP_DEL_VDI,
- .base_vdi_id = s->inode.vdi_id,
- .data_length = wlen,
- .flags = SD_FLAG_CMD_WRITE,
- };
- SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
- int fd, ret;
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- return false;
- }
-
- ret = do_req(fd, s->bs, (SheepdogReq *)&hdr,
- s->name, &wlen, &rlen);
- closesocket(fd);
- if (ret) {
- return false;
- }
- switch (rsp->result) {
- case SD_RES_NO_VDI:
- error_report("%s was already deleted", s->name);
- /* fall through */
- case SD_RES_SUCCESS:
- break;
- default:
- error_report("%s, %s", sd_strerror(rsp->result), s->name);
- return false;
- }
-
- return true;
-}
-
-/*
- * Create a writable VDI from a snapshot
- */
-static int sd_create_branch(BDRVSheepdogState *s)
-{
- Error *local_err = NULL;
- int ret, fd;
- uint32_t vid;
- char *buf;
- bool deleted;
-
- trace_sheepdog_create_branch_snapshot(s->inode.vdi_id);
-
- buf = g_malloc(SD_INODE_SIZE);
-
- /*
- * Even If deletion fails, we will just create extra snapshot based on
- * the working VDI which was supposed to be deleted. So no need to
- * false bail out.
- */
- deleted = sd_delete(s);
- ret = do_sd_create(s, &vid, !deleted, &local_err);
- if (ret) {
- error_report_err(local_err);
- goto out;
- }
-
- trace_sheepdog_create_branch_created(vid);
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- ret = fd;
- goto out;
- }
-
- ret = read_object(fd, s->bs, buf, vid_to_vdi_oid(vid),
- s->inode.nr_copies, SD_INODE_SIZE, 0, s->cache_flags);
-
- closesocket(fd);
-
- if (ret < 0) {
- goto out;
- }
-
- memcpy(&s->inode, buf, sizeof(s->inode));
-
- s->is_snapshot = false;
- ret = 0;
- trace_sheepdog_create_branch_new(s->inode.vdi_id);
-
-out:
- g_free(buf);
-
- return ret;
-}
-
-/*
- * Send I/O requests to the server.
- *
- * This function sends requests to the server, links the requests to
- * the inflight_list in BDRVSheepdogState, and exits without
- * waiting the response. The responses are received in the
- * `aio_read_response' function which is called from the main loop as
- * a fd handler.
- *
- * Returns 1 when we need to wait a response, 0 when there is no sent
- * request and -errno in error cases.
- */
-static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb)
-{
- int ret = 0;
- unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE;
- unsigned long idx;
- uint32_t object_size;
- uint64_t oid;
- uint64_t offset;
- BDRVSheepdogState *s = acb->s;
- SheepdogInode *inode = &s->inode;
- AIOReq *aio_req;
-
- if (acb->aiocb_type == AIOCB_WRITE_UDATA && s->is_snapshot) {
- /*
- * In the case we open the snapshot VDI, Sheepdog creates the
- * writable VDI when we do a write operation first.
- */
- ret = sd_create_branch(s);
- if (ret) {
- acb->ret = -EIO;
- return;
- }
- }
-
- object_size = (UINT32_C(1) << inode->block_size_shift);
- idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size;
- offset = (acb->sector_num * BDRV_SECTOR_SIZE) % object_size;
-
- /*
- * Make sure we don't free the aiocb before we are done with all requests.
- * This additional reference is dropped at the end of this function.
- */
- acb->nr_pending++;
-
- while (done != total) {
- uint8_t flags = 0;
- uint64_t old_oid = 0;
- bool create = false;
-
- oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
-
- len = MIN(total - done, object_size - offset);
-
- switch (acb->aiocb_type) {
- case AIOCB_READ_UDATA:
- if (!inode->data_vdi_id[idx]) {
- qemu_iovec_memset(acb->qiov, done, 0, len);
- goto done;
- }
- break;
- case AIOCB_WRITE_UDATA:
- if (!inode->data_vdi_id[idx]) {
- create = true;
- } else if (!is_data_obj_writable(inode, idx)) {
- /* Copy-On-Write */
- create = true;
- old_oid = oid;
- flags = SD_FLAG_CMD_COW;
- }
- break;
- case AIOCB_DISCARD_OBJ:
- /*
- * We discard the object only when the whole object is
- * 1) allocated 2) trimmed. Otherwise, simply skip it.
- */
- if (len != object_size || inode->data_vdi_id[idx] == 0) {
- goto done;
- }
- break;
- default:
- break;
- }
-
- if (create) {
- trace_sheepdog_co_rw_vector_update(inode->vdi_id, oid,
- vid_to_data_oid(inode->data_vdi_id[idx], idx),
- idx);
- oid = vid_to_data_oid(inode->vdi_id, idx);
- trace_sheepdog_co_rw_vector_new(oid);
- }
-
- aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create,
- old_oid,
- acb->aiocb_type == AIOCB_DISCARD_OBJ ?
- 0 : done);
- add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
- acb->aiocb_type);
- done:
- offset = 0;
- idx++;
- done += len;
- }
- if (--acb->nr_pending) {
- qemu_coroutine_yield();
- }
-}
-
-static void sd_aio_complete(SheepdogAIOCB *acb)
-{
- BDRVSheepdogState *s;
- if (acb->aiocb_type == AIOCB_FLUSH_CACHE) {
- return;
- }
-
- s = acb->s;
- qemu_co_mutex_lock(&s->queue_lock);
- QLIST_REMOVE(acb, aiocb_siblings);
- qemu_co_queue_restart_all(&s->overlapping_queue);
- qemu_co_mutex_unlock(&s->queue_lock);
-}
-
-static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, QEMUIOVector *qiov,
- int flags)
-{
- SheepdogAIOCB acb;
- int ret;
- int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE;
- BDRVSheepdogState *s = bs->opaque;
-
- assert(!flags);
- if (offset > s->inode.vdi_size) {
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
- if (ret < 0) {
- return ret;
- }
- }
-
- sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_WRITE_UDATA);
- sd_co_rw_vector(&acb);
- sd_write_done(&acb);
- sd_aio_complete(&acb);
-
- return acb.ret;
-}
-
-static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, QEMUIOVector *qiov)
-{
- SheepdogAIOCB acb;
- BDRVSheepdogState *s = bs->opaque;
-
- sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_READ_UDATA);
- sd_co_rw_vector(&acb);
- sd_aio_complete(&acb);
-
- return acb.ret;
-}
-
-static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs)
-{
- BDRVSheepdogState *s = bs->opaque;
- SheepdogAIOCB acb;
- AIOReq *aio_req;
-
- if (s->cache_flags != SD_FLAG_CMD_CACHE) {
- return 0;
- }
-
- sd_aio_setup(&acb, s, NULL, 0, 0, AIOCB_FLUSH_CACHE);
-
- acb.nr_pending++;
- aio_req = alloc_aio_req(s, &acb, vid_to_vdi_oid(s->inode.vdi_id),
- 0, 0, 0, false, 0, 0);
- add_aio_request(s, aio_req, NULL, 0, acb.aiocb_type);
-
- if (--acb.nr_pending) {
- qemu_coroutine_yield();
- }
-
- sd_aio_complete(&acb);
- return acb.ret;
-}
-
-static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
-{
- Error *local_err = NULL;
- BDRVSheepdogState *s = bs->opaque;
- int ret, fd;
- uint32_t new_vid;
- SheepdogInode *inode;
- unsigned int datalen;
-
- trace_sheepdog_snapshot_create_info(sn_info->name, sn_info->id_str, s->name,
- sn_info->vm_state_size, s->is_snapshot);
-
- if (s->is_snapshot) {
- error_report("You can't create a snapshot of a snapshot VDI, "
- "%s (%" PRIu32 ").", s->name, s->inode.vdi_id);
-
- return -EINVAL;
- }
-
- trace_sheepdog_snapshot_create(sn_info->name, sn_info->id_str);
-
- s->inode.vm_state_size = sn_info->vm_state_size;
- s->inode.vm_clock_nsec = sn_info->vm_clock_nsec;
- /* It appears that inode.tag does not require a NUL terminator,
- * which means this use of strncpy is ok.
- */
- strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
- /* we don't need to update entire object */
- datalen = SD_INODE_HEADER_SIZE;
- inode = g_malloc(datalen);
-
- /* refresh inode. */
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- ret = fd;
- goto cleanup;
- }
-
- ret = write_object(fd, s->bs, (char *)&s->inode,
- vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
- datalen, 0, false, s->cache_flags);
- if (ret < 0) {
- error_report("failed to write snapshot's inode.");
- goto cleanup;
- }
-
- ret = do_sd_create(s, &new_vid, 1, &local_err);
- if (ret < 0) {
- error_reportf_err(local_err,
- "failed to create inode for snapshot: ");
- goto cleanup;
- }
-
- ret = read_object(fd, s->bs, (char *)inode,
- vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0,
- s->cache_flags);
-
- if (ret < 0) {
- error_report("failed to read new inode info. %s", strerror(errno));
- goto cleanup;
- }
-
- memcpy(&s->inode, inode, datalen);
- trace_sheepdog_snapshot_create_inode(s->inode.name, s->inode.snap_id,
- s->inode.vdi_id);
-
-cleanup:
- g_free(inode);
- closesocket(fd);
- return ret;
-}
-
-/*
- * We implement rollback(loadvm) operation to the specified snapshot by
- * 1) switch to the snapshot
- * 2) rely on sd_create_branch to delete working VDI and
- * 3) create a new working VDI based on the specified snapshot
- */
-static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
-{
- BDRVSheepdogState *s = bs->opaque;
- BDRVSheepdogState *old_s;
- char tag[SD_MAX_VDI_TAG_LEN];
- uint32_t snapid = 0;
- int ret;
-
- if (!sd_parse_snapid_or_tag(snapshot_id, &snapid, tag)) {
- return -EINVAL;
- }
-
- old_s = g_new(BDRVSheepdogState, 1);
-
- memcpy(old_s, s, sizeof(BDRVSheepdogState));
-
- ret = reload_inode(s, snapid, tag);
- if (ret) {
- goto out;
- }
-
- ret = sd_create_branch(s);
- if (ret) {
- goto out;
- }
-
- g_free(old_s);
-
- return 0;
-out:
- /* recover bdrv_sd_state */
- memcpy(s, old_s, sizeof(BDRVSheepdogState));
- g_free(old_s);
-
- error_report("failed to open. recover old bdrv_sd_state.");
-
- return ret;
-}
-
-#define NR_BATCHED_DISCARD 128
-
-static int remove_objects(BDRVSheepdogState *s, Error **errp)
-{
- int fd, i = 0, nr_objs = 0;
- int ret;
- SheepdogInode *inode = &s->inode;
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- nr_objs = count_data_objs(inode);
- while (i < nr_objs) {
- int start_idx, nr_filled_idx;
-
- while (i < nr_objs && !inode->data_vdi_id[i]) {
- i++;
- }
- start_idx = i;
-
- nr_filled_idx = 0;
- while (i < nr_objs && nr_filled_idx < NR_BATCHED_DISCARD) {
- if (inode->data_vdi_id[i]) {
- inode->data_vdi_id[i] = 0;
- nr_filled_idx++;
- }
-
- i++;
- }
-
- ret = write_object(fd, s->bs,
- (char *)&inode->data_vdi_id[start_idx],
- vid_to_vdi_oid(s->inode.vdi_id), inode->nr_copies,
- (i - start_idx) * sizeof(uint32_t),
- offsetof(struct SheepdogInode,
- data_vdi_id[start_idx]),
- false, s->cache_flags);
- if (ret < 0) {
- error_setg(errp, "Failed to discard snapshot inode");
- goto out;
- }
- }
-
- ret = 0;
-out:
- closesocket(fd);
- return ret;
-}
-
-static int sd_snapshot_delete(BlockDriverState *bs,
- const char *snapshot_id,
- const char *name,
- Error **errp)
-{
- /*
- * FIXME should delete the snapshot matching both @snapshot_id and
- * @name, but @name not used here
- */
- unsigned long snap_id = 0;
- char snap_tag[SD_MAX_VDI_TAG_LEN];
- int fd, ret;
- char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
- BDRVSheepdogState *s = bs->opaque;
- unsigned int wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN, rlen = 0;
- uint32_t vid;
- SheepdogVdiReq hdr = {
- .opcode = SD_OP_DEL_VDI,
- .data_length = wlen,
- .flags = SD_FLAG_CMD_WRITE,
- };
- SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr;
-
- ret = remove_objects(s, errp);
- if (ret) {
- return ret;
- }
-
- memset(buf, 0, sizeof(buf));
- memset(snap_tag, 0, sizeof(snap_tag));
- pstrcpy(buf, SD_MAX_VDI_LEN, s->name);
- /* TODO Use sd_parse_snapid() once this mess is cleaned up */
- ret = qemu_strtoul(snapshot_id, NULL, 10, &snap_id);
- if (ret || snap_id > UINT32_MAX) {
- /*
- * FIXME Since qemu_strtoul() returns -EINVAL when
- * @snapshot_id is null, @snapshot_id is mandatory. Correct
- * would be to require at least one of @snapshot_id and @name.
- */
- error_setg(errp, "Invalid snapshot ID: %s",
- snapshot_id ? snapshot_id : "<null>");
- return -EINVAL;
- }
-
- if (snap_id) {
- hdr.snapid = (uint32_t) snap_id;
- } else {
- /* FIXME I suspect we should use @name here */
- /* FIXME don't truncate silently */
- pstrcpy(snap_tag, sizeof(snap_tag), snapshot_id);
- pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, snap_tag);
- }
-
- ret = find_vdi_name(s, s->name, snap_id, snap_tag, &vid, true, errp);
- if (ret) {
- return ret;
- }
-
- fd = connect_to_sdog(s, errp);
- if (fd < 0) {
- return fd;
- }
-
- ret = do_req(fd, s->bs, (SheepdogReq *)&hdr,
- buf, &wlen, &rlen);
- closesocket(fd);
- if (ret) {
- error_setg_errno(errp, -ret, "Couldn't send request to server");
- return ret;
- }
-
- switch (rsp->result) {
- case SD_RES_NO_VDI:
- error_setg(errp, "Can't find the snapshot");
- return -ENOENT;
- case SD_RES_SUCCESS:
- break;
- default:
- error_setg(errp, "%s", sd_strerror(rsp->result));
- return -EIO;
- }
-
- return 0;
-}
-
-static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
-{
- Error *local_err = NULL;
- BDRVSheepdogState *s = bs->opaque;
- SheepdogReq req;
- int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long);
- QEMUSnapshotInfo *sn_tab = NULL;
- unsigned wlen, rlen;
- int found = 0;
- SheepdogInode *inode;
- unsigned long *vdi_inuse;
- unsigned int start_nr;
- uint64_t hval;
- uint32_t vid;
-
- vdi_inuse = g_malloc(max);
- inode = g_malloc(SD_INODE_HEADER_SIZE);
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- ret = fd;
- goto out;
- }
-
- rlen = max;
- wlen = 0;
-
- memset(&req, 0, sizeof(req));
-
- req.opcode = SD_OP_READ_VDIS;
- req.data_length = max;
-
- ret = do_req(fd, s->bs, &req, vdi_inuse, &wlen, &rlen);
-
- closesocket(fd);
- if (ret) {
- goto out;
- }
-
- sn_tab = g_new0(QEMUSnapshotInfo, nr);
-
- /* calculate a vdi id with hash function */
- hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT);
- start_nr = hval & (SD_NR_VDIS - 1);
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- ret = fd;
- goto out;
- }
-
- for (vid = start_nr; found < nr; vid = (vid + 1) % SD_NR_VDIS) {
- if (!test_bit(vid, vdi_inuse)) {
- break;
- }
-
- /* we don't need to read entire object */
- ret = read_object(fd, s->bs, (char *)inode,
- vid_to_vdi_oid(vid),
- 0, SD_INODE_HEADER_SIZE, 0,
- s->cache_flags);
-
- if (ret) {
- continue;
- }
-
- if (!strcmp(inode->name, s->name) && is_snapshot(inode)) {
- sn_tab[found].date_sec = inode->snap_ctime >> 32;
- sn_tab[found].date_nsec = inode->snap_ctime & 0xffffffff;
- sn_tab[found].vm_state_size = inode->vm_state_size;
- sn_tab[found].vm_clock_nsec = inode->vm_clock_nsec;
-
- snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
- "%" PRIu32, inode->snap_id);
- pstrcpy(sn_tab[found].name,
- MIN(sizeof(sn_tab[found].name), sizeof(inode->tag)),
- inode->tag);
- found++;
- }
- }
-
- closesocket(fd);
-out:
- *psn_tab = sn_tab;
-
- g_free(vdi_inuse);
- g_free(inode);
-
- if (ret < 0) {
- return ret;
- }
-
- return found;
-}
-
-static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
- int64_t pos, int size, int load)
-{
- Error *local_err = NULL;
- bool create;
- int fd, ret = 0, remaining = size;
- unsigned int data_len;
- uint64_t vmstate_oid;
- uint64_t offset;
- uint32_t vdi_index;
- uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id;
- uint32_t object_size = (UINT32_C(1) << s->inode.block_size_shift);
-
- fd = connect_to_sdog(s, &local_err);
- if (fd < 0) {
- error_report_err(local_err);
- return fd;
- }
-
- while (remaining) {
- vdi_index = pos / object_size;
- offset = pos % object_size;
-
- data_len = MIN(remaining, object_size - offset);
-
- vmstate_oid = vid_to_vmstate_oid(vdi_id, vdi_index);
-
- create = (offset == 0);
- if (load) {
- ret = read_object(fd, s->bs, (char *)data, vmstate_oid,
- s->inode.nr_copies, data_len, offset,
- s->cache_flags);
- } else {
- ret = write_object(fd, s->bs, (char *)data, vmstate_oid,
- s->inode.nr_copies, data_len, offset, create,
- s->cache_flags);
- }
-
- if (ret < 0) {
- error_report("failed to save vmstate %s", strerror(errno));
- goto cleanup;
- }
-
- pos += data_len;
- data += data_len;
- remaining -= data_len;
- }
- ret = size;
-cleanup:
- closesocket(fd);
- return ret;
-}
-
-static int sd_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t pos)
-{
- BDRVSheepdogState *s = bs->opaque;
- void *buf;
- int ret;
-
- buf = qemu_blockalign(bs, qiov->size);
- qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
- ret = do_load_save_vmstate(s, (uint8_t *) buf, pos, qiov->size, 0);
- qemu_vfree(buf);
-
- return ret;
-}
-
-static int sd_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
- int64_t pos)
-{
- BDRVSheepdogState *s = bs->opaque;
- void *buf;
- int ret;
-
- buf = qemu_blockalign(bs, qiov->size);
- ret = do_load_save_vmstate(s, buf, pos, qiov->size, 1);
- qemu_iovec_from_buf(qiov, 0, buf, qiov->size);
- qemu_vfree(buf);
-
- return ret;
-}
-
-
-static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset,
- int bytes)
-{
- SheepdogAIOCB acb;
- BDRVSheepdogState *s = bs->opaque;
- QEMUIOVector discard_iov;
- struct iovec iov;
- uint32_t zero = 0;
-
- if (!s->discard_supported) {
- return 0;
- }
-
- memset(&discard_iov, 0, sizeof(discard_iov));
- memset(&iov, 0, sizeof(iov));
- iov.iov_base = &zero;
- iov.iov_len = sizeof(zero);
- discard_iov.iov = &iov;
- discard_iov.niov = 1;
- if (!QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE)) {
- return -ENOTSUP;
- }
- sd_aio_setup(&acb, s, &discard_iov, offset >> BDRV_SECTOR_BITS,
- bytes >> BDRV_SECTOR_BITS, AIOCB_DISCARD_OBJ);
- sd_co_rw_vector(&acb);
- sd_aio_complete(&acb);
-
- return acb.ret;
-}
-
-static coroutine_fn int
-sd_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset,
- int64_t bytes, int64_t *pnum, int64_t *map,
- BlockDriverState **file)
-{
- BDRVSheepdogState *s = bs->opaque;
- SheepdogInode *inode = &s->inode;
- uint32_t object_size = (UINT32_C(1) << inode->block_size_shift);
- unsigned long start = offset / object_size,
- end = DIV_ROUND_UP(offset + bytes, object_size);
- unsigned long idx;
- *map = offset;
- int ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
-
- for (idx = start; idx < end; idx++) {
- if (inode->data_vdi_id[idx] == 0) {
- break;
- }
- }
- if (idx == start) {
- /* Get the longest length of unallocated sectors */
- ret = 0;
- for (idx = start + 1; idx < end; idx++) {
- if (inode->data_vdi_id[idx] != 0) {
- break;
- }
- }
- }
-
- *pnum = (idx - start) * object_size;
- if (*pnum > bytes) {
- *pnum = bytes;
- }
- if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) {
- *file = bs;
- }
- return ret;
-}
-
-static int64_t sd_get_allocated_file_size(BlockDriverState *bs)
-{
- BDRVSheepdogState *s = bs->opaque;
- SheepdogInode *inode = &s->inode;
- uint32_t object_size = (UINT32_C(1) << inode->block_size_shift);
- unsigned long i, last = DIV_ROUND_UP(inode->vdi_size, object_size);
- uint64_t size = 0;
-
- for (i = 0; i < last; i++) {
- if (inode->data_vdi_id[i] == 0) {
- continue;
- }
- size += object_size;
- }
- return size;
-}
-
-static QemuOptsList sd_create_opts = {
- .name = "sheepdog-create-opts",
- .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head),
- .desc = {
- {
- .name = BLOCK_OPT_SIZE,
- .type = QEMU_OPT_SIZE,
- .help = "Virtual disk size"
- },
- {
- .name = BLOCK_OPT_BACKING_FILE,
- .type = QEMU_OPT_STRING,
- .help = "File name of a base image"
- },
- {
- .name = BLOCK_OPT_BACKING_FMT,
- .type = QEMU_OPT_STRING,
- .help = "Must be 'sheepdog' if present",
- },
- {
- .name = BLOCK_OPT_PREALLOC,
- .type = QEMU_OPT_STRING,
- .help = "Preallocation mode (allowed values: off, full)"
- },
- {
- .name = BLOCK_OPT_REDUNDANCY,
- .type = QEMU_OPT_STRING,
- .help = "Redundancy of the image"
- },
- {
- .name = BLOCK_OPT_OBJECT_SIZE,
- .type = QEMU_OPT_SIZE,
- .help = "Object size of the image"
- },
- { /* end of list */ }
- }
-};
-
-static const char *const sd_strong_runtime_opts[] = {
- "vdi",
- "snap-id",
- "tag",
- "server.",
-
- NULL
-};
-
-static BlockDriver bdrv_sheepdog = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_co_create = sd_co_create,
- .bdrv_co_create_opts = sd_co_create_opts,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
- .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_co_truncate = sd_co_truncate,
-
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_block_status = sd_co_block_status,
-
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
-
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
-
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
-
- .create_opts = &sd_create_opts,
- .strong_runtime_opts = sd_strong_runtime_opts,
-};
-
-static BlockDriver bdrv_sheepdog_tcp = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog+tcp",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_co_create = sd_co_create,
- .bdrv_co_create_opts = sd_co_create_opts,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
- .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_co_truncate = sd_co_truncate,
-
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_block_status = sd_co_block_status,
-
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
-
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
-
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
-
- .create_opts = &sd_create_opts,
- .strong_runtime_opts = sd_strong_runtime_opts,
-};
-
-static BlockDriver bdrv_sheepdog_unix = {
- .format_name = "sheepdog",
- .protocol_name = "sheepdog+unix",
- .instance_size = sizeof(BDRVSheepdogState),
- .bdrv_parse_filename = sd_parse_filename,
- .bdrv_file_open = sd_open,
- .bdrv_reopen_prepare = sd_reopen_prepare,
- .bdrv_reopen_commit = sd_reopen_commit,
- .bdrv_reopen_abort = sd_reopen_abort,
- .bdrv_close = sd_close,
- .bdrv_co_create = sd_co_create,
- .bdrv_co_create_opts = sd_co_create_opts,
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
- .bdrv_getlength = sd_getlength,
- .bdrv_get_allocated_file_size = sd_get_allocated_file_size,
- .bdrv_co_truncate = sd_co_truncate,
-
- .bdrv_co_readv = sd_co_readv,
- .bdrv_co_writev = sd_co_writev,
- .bdrv_co_flush_to_disk = sd_co_flush_to_disk,
- .bdrv_co_pdiscard = sd_co_pdiscard,
- .bdrv_co_block_status = sd_co_block_status,
-
- .bdrv_snapshot_create = sd_snapshot_create,
- .bdrv_snapshot_goto = sd_snapshot_goto,
- .bdrv_snapshot_delete = sd_snapshot_delete,
- .bdrv_snapshot_list = sd_snapshot_list,
-
- .bdrv_save_vmstate = sd_save_vmstate,
- .bdrv_load_vmstate = sd_load_vmstate,
-
- .bdrv_detach_aio_context = sd_detach_aio_context,
- .bdrv_attach_aio_context = sd_attach_aio_context,
-
- .create_opts = &sd_create_opts,
- .strong_runtime_opts = sd_strong_runtime_opts,
-};
-
-static void bdrv_sheepdog_init(void)
-{
- bdrv_register(&bdrv_sheepdog);
- bdrv_register(&bdrv_sheepdog_tcp);
- bdrv_register(&bdrv_sheepdog_unix);
-}
-block_init(bdrv_sheepdog_init);
diff --git a/block/trace-events b/block/trace-events
index 1a12d634e2..31062ed437 100644
--- a/block/trace-events
+++ b/block/trace-events
@@ -207,19 +207,5 @@ file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
file_setup_cdrom(const char *partition) "Using %s as optical disc"
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
-# sheepdog.c
-sheepdog_reconnect_to_sdog(void) "Wait for connection to be established"
-sheepdog_aio_read_response(void) "disable cache since the server doesn't support it"
-sheepdog_open(uint32_t vid) "0x%" PRIx32 " snapshot inode was open"
-sheepdog_close(const char *name) "%s"
-sheepdog_create_branch_snapshot(uint32_t vdi) "0x%" PRIx32 " is snapshot"
-sheepdog_create_branch_created(uint32_t vdi) "0x%" PRIx32 " is created"
-sheepdog_create_branch_new(uint32_t vdi) "0x%" PRIx32 " was newly created"
-sheepdog_co_rw_vector_update(uint32_t vdi, uint64_t oid, uint64_t data, long idx) "update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld"
-sheepdog_co_rw_vector_new(uint64_t oid) "new oid 0x%" PRIx64
-sheepdog_snapshot_create_info(const char *sn_name, const char *id, const char *name, int64_t size, int is_snapshot) "sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " "is_snapshot %d"
-sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
-sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
-
# ssh.c
sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)"
diff --git a/block/write-threshold.c b/block/write-threshold.c
index 85b78dc2a9..35cafbc22d 100644
--- a/block/write-threshold.c
+++ b/block/write-threshold.c
@@ -12,9 +12,7 @@
#include "qemu/osdep.h"
#include "block/block_int.h"
-#include "qemu/coroutine.h"
#include "block/write-threshold.h"
-#include "qemu/notify.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-block-core.h"
#include "qapi/qapi-events-block-core.h"
@@ -24,82 +22,9 @@ uint64_t bdrv_write_threshold_get(const BlockDriverState *bs)
return bs->write_threshold_offset;
}
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs)
-{
- return bs->write_threshold_offset > 0;
-}
-
-static void write_threshold_disable(BlockDriverState *bs)
-{
- if (bdrv_write_threshold_is_set(bs)) {
- notifier_with_return_remove(&bs->write_threshold_notifier);
- bs->write_threshold_offset = 0;
- }
-}
-
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
- const BdrvTrackedRequest *req)
-{
- if (bdrv_write_threshold_is_set(bs)) {
- if (req->offset > bs->write_threshold_offset) {
- return (req->offset - bs->write_threshold_offset) + req->bytes;
- }
- if ((req->offset + req->bytes) > bs->write_threshold_offset) {
- return (req->offset + req->bytes) - bs->write_threshold_offset;
- }
- }
- return 0;
-}
-
-static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
- void *opaque)
-{
- BdrvTrackedRequest *req = opaque;
- BlockDriverState *bs = req->bs;
- uint64_t amount = 0;
-
- amount = bdrv_write_threshold_exceeded(bs, req);
- if (amount > 0) {
- qapi_event_send_block_write_threshold(
- bs->node_name,
- amount,
- bs->write_threshold_offset);
-
- /* autodisable to avoid flooding the monitor */
- write_threshold_disable(bs);
- }
-
- return 0; /* should always let other notifiers run */
-}
-
-static void write_threshold_register_notifier(BlockDriverState *bs)
-{
- bs->write_threshold_notifier.notify = before_write_notify;
- bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier);
-}
-
-static void write_threshold_update(BlockDriverState *bs,
- int64_t threshold_bytes)
-{
- bs->write_threshold_offset = threshold_bytes;
-}
-
void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes)
{
- if (bdrv_write_threshold_is_set(bs)) {
- if (threshold_bytes > 0) {
- write_threshold_update(bs, threshold_bytes);
- } else {
- write_threshold_disable(bs);
- }
- } else {
- if (threshold_bytes > 0) {
- /* avoid multiple registration */
- write_threshold_register_notifier(bs);
- write_threshold_update(bs, threshold_bytes);
- }
- /* discard bogus disable request */
- }
+ bs->write_threshold_offset = threshold_bytes;
}
void qmp_block_set_write_threshold(const char *node_name,
@@ -122,3 +47,17 @@ void qmp_block_set_write_threshold(const char *node_name,
aio_context_release(aio_context);
}
+
+void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset,
+ int64_t bytes)
+{
+ int64_t end = offset + bytes;
+ uint64_t wtr = bs->write_threshold_offset;
+
+ if (wtr > 0 && end > wtr) {
+ qapi_event_send_block_write_threshold(bs->node_name, end - wtr, wtr);
+
+ /* autodisable to avoid flooding the monitor */
+ bdrv_write_threshold_set(bs, 0);
+ }
+}
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 18f806b032..9d370bc8f6 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -795,8 +795,8 @@ int main(int argc, char **argv)
{
AccelClass *ac = ACCEL_GET_CLASS(current_accel());
- ac->init_machine(NULL);
accel_init_interfaces(ac);
+ ac->init_machine(NULL);
}
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
diff --git a/configure b/configure
index 54f8475444..9470fff09a 100755
--- a/configure
+++ b/configure
@@ -447,7 +447,6 @@ vdi=${default_feature:-yes}
vvfat=${default_feature:-yes}
qed=${default_feature:-yes}
parallels=${default_feature:-yes}
-sheepdog="no"
libxml2="$default_feature"
debug_mutex="no"
libpmem="$default_feature"
@@ -1478,10 +1477,6 @@ for opt do
;;
--enable-parallels) parallels="yes"
;;
- --disable-sheepdog) sheepdog="no"
- ;;
- --enable-sheepdog) sheepdog="yes"
- ;;
--disable-vhost-user) vhost_user="no"
;;
--enable-vhost-user) vhost_user="yes"
@@ -1656,7 +1651,7 @@ case "$cpu" in
# No special flags required for other host CPUs
esac
-eval "cross_cc_${cpu}=\$host_cc"
+eval "cross_cc_${cpu}=\$cc"
cross_cc_vars="$cross_cc_vars cross_cc_${cpu}"
QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
@@ -1668,7 +1663,7 @@ if [ "$ARCH" = "unknown" ]; then
fi
default_target_list=""
-deprecated_targets_list=ppc64abi32-linux-user,lm32-softmmu,unicore32-softmmu
+deprecated_targets_list=ppc64abi32-linux-user
deprecated_features=""
mak_wilds=""
@@ -1916,7 +1911,6 @@ disabled with --disable-FEATURE, default is enabled if available
vvfat vvfat image format support
qed qed image format support
parallels parallels image format support
- sheepdog sheepdog block driver support (deprecated)
crypto-afalg Linux AF_ALG crypto backend driver
capstone capstone disassembler support
debug-mutex mutex debugging support
@@ -3341,7 +3335,7 @@ if ! test "$gio" = "no"; then
gio_cflags=$($pkg_config --cflags gio-2.0)
gio_libs=$($pkg_config --libs gio-2.0)
gdbus_codegen=$($pkg_config --variable=gdbus_codegen gio-2.0)
- if [ ! -x "$gdbus_codegen" ]; then
+ if ! has "$gdbus_codegen"; then
gdbus_codegen=
fi
# Check that the libraries actually work -- Ubuntu 18.04 ships
@@ -3623,7 +3617,7 @@ case "$fdt" in
esac
##########################################
-# opengl probe (for sdl2, gtk, milkymist-tmu2)
+# opengl probe (for sdl2, gtk)
gbm="no"
if $pkg_config gbm; then
@@ -5440,9 +5434,16 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
fi
# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
+# or -march=z10 (which is the lowest architecture level that Clang supports)
if test "$cpu" = "s390x" ; then
write_c_skeleton
- if compile_prog "-march=z900" ""; then
+ compile_prog "-march=z900" ""
+ has_z900=$?
+ if [ $has_z900 = 0 ] || compile_prog "-march=z10" ""; then
+ if [ $has_z900 != 0 ]; then
+ echo "WARNING: Your compiler does not support the z900!"
+ echo " The s390-ccw bios will only work with guest CPUs >= z10."
+ fi
roms="$roms s390-ccw"
# SLOF is required for building the s390-ccw firmware on s390x,
# since it is using the libnet code from SLOF for network booting.
@@ -5704,6 +5705,8 @@ if test "$gio" = "yes" ; then
echo "CONFIG_GIO=y" >> $config_host_mak
echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak
echo "GIO_LIBS=$gio_libs" >> $config_host_mak
+fi
+if test "$gdbus_codegen" != "" ; then
echo "GDBUS_CODEGEN=$gdbus_codegen" >> $config_host_mak
fi
echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak
@@ -6099,10 +6102,6 @@ fi
if test "$parallels" = "yes" ; then
echo "CONFIG_PARALLELS=y" >> $config_host_mak
fi
-if test "$sheepdog" = "yes" ; then
- add_to deprecated_features "sheepdog"
- echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
-fi
if test "$have_mlockall" = "yes" ; then
echo "HAVE_MLOCKALL=y" >> $config_host_mak
fi
@@ -6165,6 +6164,7 @@ echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
echo "MESON=$meson" >> $config_host_mak
echo "NINJA=$ninja" >> $config_host_mak
echo "CC=$cc" >> $config_host_mak
+echo "HOST_CC=$host_cc" >> $config_host_mak
if $iasl -h > /dev/null 2>&1; then
echo "CONFIG_IASL=$iasl" >> $config_host_mak
fi
@@ -6277,14 +6277,13 @@ fi
# UNLINK is used to remove symlinks from older development versions
# that might get into the way when doing "git update" without doing
# a "make distclean" in between.
-DIRS="tests tests/tcg tests/tcg/lm32 tests/qapi-schema tests/qtest/libqos"
+DIRS="tests tests/tcg tests/qapi-schema tests/qtest/libqos"
DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph"
DIRS="$DIRS docs docs/interop fsdev scsi"
DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
DIRS="$DIRS roms/seabios"
DIRS="$DIRS contrib/plugins/"
LINKS="Makefile"
-LINKS="$LINKS tests/tcg/lm32/Makefile"
LINKS="$LINKS tests/tcg/Makefile.target"
LINKS="$LINKS pc-bios/optionrom/Makefile"
LINKS="$LINKS pc-bios/s390-ccw/Makefile"
@@ -6475,6 +6474,13 @@ if test -n "${deprecated_features}"; then
echo " features: ${deprecated_features}"
fi
+# Create list of config switches that should be poisoned in common code...
+# but filter out CONFIG_TCG and CONFIG_USER_ONLY which are special.
+sed -n -e '/CONFIG_TCG/d' -e '/CONFIG_USER_ONLY/d' \
+ -e '/^#define / { s///; s/ .*//; s/^/#pragma GCC poison /p; }' \
+ *-config-devices.h *-config-target.h | \
+ sort -u > config-poison.h
+
# Save the configure command line for later reuse.
cat <<EOD >config.status
#!/bin/sh
diff --git a/contrib/vhost-user-input/main.c b/contrib/vhost-user-input/main.c
index c15d18c33f..081230da54 100644
--- a/contrib/vhost-user-input/main.c
+++ b/contrib/vhost-user-input/main.c
@@ -6,12 +6,13 @@
#include "qemu/osdep.h"
-#include <linux/input.h>
+#include <sys/ioctl.h>
#include "qemu/iov.h"
#include "qemu/bswap.h"
#include "qemu/sockets.h"
#include "libvhost-user-glib.h"
+#include "standard-headers/linux/input.h"
#include "standard-headers/linux/virtio_input.h"
#include "qapi/error.h"
@@ -113,13 +114,16 @@ vi_evdev_watch(VuDev *dev, int condition, void *data)
static void vi_handle_status(VuInput *vi, virtio_input_event *event)
{
struct input_event evdev;
+ struct timeval tval;
int rc;
- if (gettimeofday(&evdev.time, NULL)) {
+ if (gettimeofday(&tval, NULL)) {
perror("vi_handle_status: gettimeofday");
return;
}
+ evdev.input_event_sec = tval.tv_sec;
+ evdev.input_event_usec = tval.tv_usec;
evdev.type = le16toh(event->type);
evdev.code = le16toh(event->code);
evdev.value = le32toh(event->value);
diff --git a/cpu.c b/cpu.c
index bfbe5a66f9..34a0484bf4 100644
--- a/cpu.c
+++ b/cpu.c
@@ -36,6 +36,7 @@
#include "sysemu/replay.h"
#include "exec/translate-all.h"
#include "exec/log.h"
+#include "hw/core/accel-cpu.h"
uintptr_t qemu_host_page_size;
intptr_t qemu_host_page_mask;
@@ -129,7 +130,9 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
CPUClass *cc = CPU_GET_CLASS(cpu);
cpu_list_add(cpu);
-
+ if (!accel_cpu_realizefn(cpu, errp)) {
+ return;
+ }
#ifdef CONFIG_TCG
/* NB: errp parameter is unused currently */
if (tcg_enabled()) {
diff --git a/default-configs/devices/lm32-softmmu.mak b/default-configs/devices/lm32-softmmu.mak
deleted file mode 100644
index 1bce3f6e8b..0000000000
--- a/default-configs/devices/lm32-softmmu.mak
+++ /dev/null
@@ -1,12 +0,0 @@
-# Default configuration for lm32-softmmu
-
-# Uncomment the following lines to disable these optional devices:
-#
-#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures
-
-CONFIG_SEMIHOSTING=y
-
-# Boards:
-#
-CONFIG_LM32_EVR=y
-CONFIG_MILKYMIST=y
diff --git a/default-configs/devices/moxie-softmmu.mak b/default-configs/devices/moxie-softmmu.mak
deleted file mode 100644
index bd50da3c58..0000000000
--- a/default-configs/devices/moxie-softmmu.mak
+++ /dev/null
@@ -1,5 +0,0 @@
-# Default configuration for moxie-softmmu
-
-# Boards:
-#
-CONFIG_MOXIESIM=y
diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak
index d5eec75f05..bc69301fa4 100644
--- a/default-configs/devices/riscv64-softmmu.mak
+++ b/default-configs/devices/riscv64-softmmu.mak
@@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y
CONFIG_SIFIVE_U=y
CONFIG_RISCV_VIRT=y
CONFIG_MICROCHIP_PFSOC=y
+CONFIG_SHAKTI_C=y
diff --git a/default-configs/devices/unicore32-softmmu.mak b/default-configs/devices/unicore32-softmmu.mak
deleted file mode 100644
index 899288e3d7..0000000000
--- a/default-configs/devices/unicore32-softmmu.mak
+++ /dev/null
@@ -1,6 +0,0 @@
-# Default configuration for unicore32-softmmu
-
-# Boards:
-#
-CONFIG_PUV3=y
-CONFIG_SEMIHOSTING=y
diff --git a/default-configs/targets/lm32-softmmu.mak b/default-configs/targets/lm32-softmmu.mak
deleted file mode 100644
index 55e7184a3d..0000000000
--- a/default-configs/targets/lm32-softmmu.mak
+++ /dev/null
@@ -1,2 +0,0 @@
-TARGET_ARCH=lm32
-TARGET_WORDS_BIGENDIAN=y
diff --git a/default-configs/targets/moxie-softmmu.mak b/default-configs/targets/moxie-softmmu.mak
deleted file mode 100644
index 183e6b0ebd..0000000000
--- a/default-configs/targets/moxie-softmmu.mak
+++ /dev/null
@@ -1,2 +0,0 @@
-TARGET_ARCH=moxie
-TARGET_WORDS_BIGENDIAN=y
diff --git a/default-configs/targets/sparc64-linux-user.mak b/default-configs/targets/sparc64-linux-user.mak
index 846924201a..9d23ab4a26 100644
--- a/default-configs/targets/sparc64-linux-user.mak
+++ b/default-configs/targets/sparc64-linux-user.mak
@@ -1,5 +1,6 @@
TARGET_ARCH=sparc64
TARGET_BASE_ARCH=sparc
+TARGET_ABI_DIR=sparc
TARGET_SYSTBL_ABI=common,64
TARGET_SYSTBL=syscall.tbl
TARGET_ALIGNED_ONLY=y
diff --git a/default-configs/targets/unicore32-softmmu.mak b/default-configs/targets/unicore32-softmmu.mak
deleted file mode 100644
index 57331e94fe..0000000000
--- a/default-configs/targets/unicore32-softmmu.mak
+++ /dev/null
@@ -1 +0,0 @@
-TARGET_ARCH=unicore32
diff --git a/disas/lm32.c b/disas/lm32.c
deleted file mode 100644
index 4fbb124534..0000000000
--- a/disas/lm32.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Simple LatticeMico32 disassembler.
- *
- * Copyright (c) 2012 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "disas/dis-asm.h"
-
-typedef enum {
- LM32_OP_SRUI = 0, LM32_OP_NORI, LM32_OP_MULI, LM32_OP_SH, LM32_OP_LB,
- LM32_OP_SRI, LM32_OP_XORI, LM32_OP_LH, LM32_OP_ANDI, LM32_OP_XNORI,
- LM32_OP_LW, LM32_OP_LHU, LM32_OP_SB, LM32_OP_ADDI, LM32_OP_ORI,
- LM32_OP_SLI, LM32_OP_LBU, LM32_OP_BE, LM32_OP_BG, LM32_OP_BGE,
- LM32_OP_BGEU, LM32_OP_BGU, LM32_OP_SW, LM32_OP_BNE, LM32_OP_ANDHI,
- LM32_OP_CMPEI, LM32_OP_CMPGI, LM32_OP_CMPGEI, LM32_OP_CMPGEUI,
- LM32_OP_CMPGUI, LM32_OP_ORHI, LM32_OP_CMPNEI, LM32_OP_SRU, LM32_OP_NOR,
- LM32_OP_MUL, LM32_OP_DIVU, LM32_OP_RCSR, LM32_OP_SR, LM32_OP_XOR,
- LM32_OP_ILL0, LM32_OP_AND, LM32_OP_XNOR, LM32_OP_ILL1, LM32_OP_SCALL,
- LM32_OP_SEXTB, LM32_OP_ADD, LM32_OP_OR, LM32_OP_SL, LM32_OP_B,
- LM32_OP_MODU, LM32_OP_SUB, LM32_OP_ILL2, LM32_OP_WCSR, LM32_OP_ILL3,
- LM32_OP_CALL, LM32_OP_SEXTH, LM32_OP_BI, LM32_OP_CMPE, LM32_OP_CMPG,
- LM32_OP_CMPGE, LM32_OP_CMPGEU, LM32_OP_CMPGU, LM32_OP_CALLI, LM32_OP_CMPNE,
-} Lm32Opcode;
-
-typedef enum {
- FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE,
- FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK,
-} Lm32OpcodeFmt;
-
-typedef enum {
- LM32_CSR_IE = 0, LM32_CSR_IM, LM32_CSR_IP, LM32_CSR_ICC, LM32_CSR_DCC,
- LM32_CSR_CC, LM32_CSR_CFG, LM32_CSR_EBA, LM32_CSR_DC, LM32_CSR_DEBA,
- LM32_CSR_CFG2, LM32_CSR_JTX = 0xe, LM32_CSR_JRX, LM32_CSR_BP0,
- LM32_CSR_BP1, LM32_CSR_BP2, LM32_CSR_BP3, LM32_CSR_WP0 = 0x18,
- LM32_CSR_WP1, LM32_CSR_WP2, LM32_CSR_WP3,
-} Lm32CsrNum;
-
-typedef struct {
- int csr;
- const char *name;
-} Lm32CsrInfo;
-
-static const Lm32CsrInfo lm32_csr_info[] = {
- {LM32_CSR_IE, "ie", },
- {LM32_CSR_IM, "im", },
- {LM32_CSR_IP, "ip", },
- {LM32_CSR_ICC, "icc", },
- {LM32_CSR_DCC, "dcc", },
- {LM32_CSR_CC, "cc", },
- {LM32_CSR_CFG, "cfg", },
- {LM32_CSR_EBA, "eba", },
- {LM32_CSR_DC, "dc", },
- {LM32_CSR_DEBA, "deba", },
- {LM32_CSR_CFG2, "cfg2", },
- {LM32_CSR_JTX, "jtx", },
- {LM32_CSR_JRX, "jrx", },
- {LM32_CSR_BP0, "bp0", },
- {LM32_CSR_BP1, "bp1", },
- {LM32_CSR_BP2, "bp2", },
- {LM32_CSR_BP3, "bp3", },
- {LM32_CSR_WP0, "wp0", },
- {LM32_CSR_WP1, "wp1", },
- {LM32_CSR_WP2, "wp2", },
- {LM32_CSR_WP3, "wp3", },
-};
-
-static const Lm32CsrInfo *find_csr_info(int csr)
-{
- const Lm32CsrInfo *info;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) {
- info = &lm32_csr_info[i];
- if (csr == info->csr) {
- return info;
- }
- }
-
- return NULL;
-}
-
-typedef struct {
- int reg;
- const char *name;
-} Lm32RegInfo;
-
-typedef enum {
- LM32_REG_R0 = 0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4,
- LM32_REG_R5, LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9,
- LM32_REG_R10, LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14,
- LM32_REG_R15, LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19,
- LM32_REG_R20, LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24,
- LM32_REG_R25, LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA,
- LM32_REG_EA, LM32_REG_BA,
-} Lm32RegNum;
-
-static const Lm32RegInfo lm32_reg_info[] = {
- {LM32_REG_R0, "r0", },
- {LM32_REG_R1, "r1", },
- {LM32_REG_R2, "r2", },
- {LM32_REG_R3, "r3", },
- {LM32_REG_R4, "r4", },
- {LM32_REG_R5, "r5", },
- {LM32_REG_R6, "r6", },
- {LM32_REG_R7, "r7", },
- {LM32_REG_R8, "r8", },
- {LM32_REG_R9, "r9", },
- {LM32_REG_R10, "r10", },
- {LM32_REG_R11, "r11", },
- {LM32_REG_R12, "r12", },
- {LM32_REG_R13, "r13", },
- {LM32_REG_R14, "r14", },
- {LM32_REG_R15, "r15", },
- {LM32_REG_R16, "r16", },
- {LM32_REG_R17, "r17", },
- {LM32_REG_R18, "r18", },
- {LM32_REG_R19, "r19", },
- {LM32_REG_R20, "r20", },
- {LM32_REG_R21, "r21", },
- {LM32_REG_R22, "r22", },
- {LM32_REG_R23, "r23", },
- {LM32_REG_R24, "r24", },
- {LM32_REG_R25, "r25", },
- {LM32_REG_GP, "gp", },
- {LM32_REG_FP, "fp", },
- {LM32_REG_SP, "sp", },
- {LM32_REG_RA, "ra", },
- {LM32_REG_EA, "ea", },
- {LM32_REG_BA, "ba", },
-};
-
-static const Lm32RegInfo *find_reg_info(int reg)
-{
- assert(ARRAY_SIZE(lm32_reg_info) == 32);
- return &lm32_reg_info[reg & 0x1f];
-}
-
-typedef struct {
- struct {
- uint32_t code;
- uint32_t mask;
- } op;
- const char *name;
- const char *args_fmt;
-} Lm32OpcodeInfo;
-
-static const Lm32OpcodeInfo lm32_opcode_info[] = {
- /* pseudo instructions */
- {{0x34000000, 0xffffffff}, "nop", NULL},
- {{0xac000002, 0xffffffff}, "break", NULL},
- {{0xac000003, 0xffffffff}, "scall", NULL},
- {{0xc3e00000, 0xffffffff}, "bret", NULL},
- {{0xc3c00000, 0xffffffff}, "eret", NULL},
- {{0xc3a00000, 0xffffffff}, "ret", NULL},
- {{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"},
- {{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"},
- {{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"},
- {{0x34000000, 0xffe00000}, "mvi", "%1, %s"},
-
-#define _O(op) {op << 26, 0x3f << 26}
- /* regular opcodes */
- {_O(LM32_OP_ADD), "add", "%2, %0, %1" },
- {_O(LM32_OP_ADDI), "addi", "%1, %0, %s" },
- {_O(LM32_OP_AND), "and", "%2, %0, %1" },
- {_O(LM32_OP_ANDHI), "andhi", "%1, %0, %u" },
- {_O(LM32_OP_ANDI), "andi", "%1, %0, %u" },
- {_O(LM32_OP_B), "b", "%0", },
- {_O(LM32_OP_BE), "be", "%1, %0, %r" },
- {_O(LM32_OP_BG), "bg", "%1, %0, %r" },
- {_O(LM32_OP_BGE), "bge", "%1, %0, %r" },
- {_O(LM32_OP_BGEU), "bgeu", "%1, %0, %r" },
- {_O(LM32_OP_BGU), "bgu", "%1, %0, %r" },
- {_O(LM32_OP_BI), "bi", "%R", },
- {_O(LM32_OP_BNE), "bne", "%1, %0, %r" },
- {_O(LM32_OP_CALL), "call", "%0", },
- {_O(LM32_OP_CALLI), "calli", "%R", },
- {_O(LM32_OP_CMPE), "cmpe", "%2, %0, %1" },
- {_O(LM32_OP_CMPEI), "cmpei", "%1, %0, %s" },
- {_O(LM32_OP_CMPG), "cmpg", "%2, %0, %1" },
- {_O(LM32_OP_CMPGE), "cmpge", "%2, %0, %1" },
- {_O(LM32_OP_CMPGEI), "cmpgei", "%1, %0, %s" },
- {_O(LM32_OP_CMPGEU), "cmpgeu", "%2, %0, %1" },
- {_O(LM32_OP_CMPGEUI), "cmpgeui", "%1, %0, %s" },
- {_O(LM32_OP_CMPGI), "cmpgi", "%1, %0, %s" },
- {_O(LM32_OP_CMPGU), "cmpgu", "%2, %0, %1" },
- {_O(LM32_OP_CMPGUI), "cmpgui", "%1, %0, %s" },
- {_O(LM32_OP_CMPNE), "cmpne", "%2, %0, %1" },
- {_O(LM32_OP_CMPNEI), "cmpnei", "%1, %0, %s" },
- {_O(LM32_OP_DIVU), "divu", "%2, %0, %1" },
- {_O(LM32_OP_LB), "lb", "%1, (%0+%s)" },
- {_O(LM32_OP_LBU), "lbu", "%1, (%0+%s)" },
- {_O(LM32_OP_LH), "lh", "%1, (%0+%s)" },
- {_O(LM32_OP_LHU), "lhu", "%1, (%0+%s)" },
- {_O(LM32_OP_LW), "lw", "%1, (%0+%s)" },
- {_O(LM32_OP_MODU), "modu", "%2, %0, %1" },
- {_O(LM32_OP_MULI), "muli", "%1, %0, %s" },
- {_O(LM32_OP_MUL), "mul", "%2, %0, %1" },
- {_O(LM32_OP_NORI), "nori", "%1, %0, %u" },
- {_O(LM32_OP_NOR), "nor", "%2, %0, %1" },
- {_O(LM32_OP_ORHI), "orhi", "%1, %0, %u" },
- {_O(LM32_OP_ORI), "ori", "%1, %0, %u" },
- {_O(LM32_OP_OR), "or", "%2, %0, %1" },
- {_O(LM32_OP_RCSR), "rcsr", "%2, %c", },
- {_O(LM32_OP_SB), "sb", "(%0+%s), %1" },
- {_O(LM32_OP_SEXTB), "sextb", "%2, %0", },
- {_O(LM32_OP_SEXTH), "sexth", "%2, %0", },
- {_O(LM32_OP_SH), "sh", "(%0+%s), %1" },
- {_O(LM32_OP_SLI), "sli", "%1, %0, %h" },
- {_O(LM32_OP_SL), "sl", "%2, %0, %1" },
- {_O(LM32_OP_SRI), "sri", "%1, %0, %h" },
- {_O(LM32_OP_SR), "sr", "%2, %0, %1" },
- {_O(LM32_OP_SRUI), "srui", "%1, %0, %d" },
- {_O(LM32_OP_SRU), "sru", "%2, %0, %s" },
- {_O(LM32_OP_SUB), "sub", "%2, %0, %s" },
- {_O(LM32_OP_SW), "sw", "(%0+%s), %1" },
- {_O(LM32_OP_WCSR), "wcsr", "%c, %1", },
- {_O(LM32_OP_XNORI), "xnori", "%1, %0, %u" },
- {_O(LM32_OP_XNOR), "xnor", "%2, %0, %1" },
- {_O(LM32_OP_XORI), "xori", "%1, %0, %u" },
- {_O(LM32_OP_XOR), "xor", "%2, %0, %1" },
-#undef _O
-};
-
-static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode)
-{
- const Lm32OpcodeInfo *info;
- int i;
- for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) {
- info = &lm32_opcode_info[i];
- if ((opcode & info->op.mask) == info->op.code) {
- return info;
- }
- }
-
- return NULL;
-}
-
-int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info)
-{
- fprintf_function fprintf_fn = info->fprintf_func;
- void *stream = info->stream;
- int rc;
- uint8_t insn[4];
- const Lm32OpcodeInfo *opc_info;
- uint32_t op;
- const char *args_fmt;
-
- rc = info->read_memory_func(memaddr, insn, 4, info);
- if (rc != 0) {
- info->memory_error_func(rc, memaddr, info);
- return -1;
- }
-
- fprintf_fn(stream, "%02x %02x %02x %02x ",
- insn[0], insn[1], insn[2], insn[3]);
-
- op = bfd_getb32(insn);
- opc_info = find_opcode_info(op);
- if (opc_info) {
- fprintf_fn(stream, "%-8s ", opc_info->name);
- args_fmt = opc_info->args_fmt;
- while (args_fmt && *args_fmt) {
- if (*args_fmt == '%') {
- switch (*(++args_fmt)) {
- case '0': {
- uint8_t r0;
- const char *r0_name;
- r0 = (op >> 21) & 0x1f;
- r0_name = find_reg_info(r0)->name;
- fprintf_fn(stream, "%s", r0_name);
- break;
- }
- case '1': {
- uint8_t r1;
- const char *r1_name;
- r1 = (op >> 16) & 0x1f;
- r1_name = find_reg_info(r1)->name;
- fprintf_fn(stream, "%s", r1_name);
- break;
- }
- case '2': {
- uint8_t r2;
- const char *r2_name;
- r2 = (op >> 11) & 0x1f;
- r2_name = find_reg_info(r2)->name;
- fprintf_fn(stream, "%s", r2_name);
- break;
- }
- case 'c': {
- uint8_t csr;
- const Lm32CsrInfo *info;
- csr = (op >> 21) & 0x1f;
- info = find_csr_info(csr);
- if (info) {
- fprintf_fn(stream, "%s", info->name);
- } else {
- fprintf_fn(stream, "0x%x", csr);
- }
- break;
- }
- case 'u': {
- uint16_t u16;
- u16 = op & 0xffff;
- fprintf_fn(stream, "0x%x", u16);
- break;
- }
- case 's': {
- int16_t s16;
- s16 = (int16_t)(op & 0xffff);
- fprintf_fn(stream, "%d", s16);
- break;
- }
- case 'r': {
- uint32_t rela;
- rela = memaddr + (((int16_t)(op & 0xffff)) << 2);
- fprintf_fn(stream, "%x", rela);
- break;
- }
- case 'R': {
- uint32_t rela;
- int32_t imm26;
- imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4;
- rela = memaddr + imm26;
- fprintf_fn(stream, "%x", rela);
- break;
- }
- case 'h': {
- uint8_t u5;
- u5 = (op & 0x1f);
- fprintf_fn(stream, "%d", u5);
- break;
- }
- default:
- break;
- }
- } else {
- fprintf_fn(stream, "%c", *args_fmt);
- }
- args_fmt++;
- }
- } else {
- fprintf_fn(stream, ".word 0x%x", op);
- }
-
- return 4;
-}
diff --git a/disas/meson.build b/disas/meson.build
index 4c8da01877..449f99e1de 100644
--- a/disas/meson.build
+++ b/disas/meson.build
@@ -9,11 +9,9 @@ common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c'))
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c'))
-common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c'))
common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c'))
common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c'))
common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c'))
-common_ss.add(when: 'CONFIG_MOXIE_DIS', if_true: files('moxie.c'))
common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp'))
common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c'))
common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c'))
diff --git a/disas/moxie.c b/disas/moxie.c
deleted file mode 100644
index e94ab4c33d..0000000000
--- a/disas/moxie.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/* Disassemble moxie instructions.
- Copyright (c) 2009 Free Software Foundation, 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"
-#define STATIC_TABLE
-#define DEFINE_TABLE
-
-#include "disas/dis-asm.h"
-
-static void *stream;
-
-/* Form 1 instructions come in different flavors:
-
- Some have no arguments (MOXIE_F1_NARG)
- Some only use the A operand (MOXIE_F1_A)
- Some use A and B registers (MOXIE_F1_AB)
- Some use A and consume a 4 byte immediate value (MOXIE_F1_A4)
- Some use just a 4 byte immediate value (MOXIE_F1_4)
- Some use just a 4 byte memory address (MOXIE_F1_M)
- Some use B and an indirect A (MOXIE_F1_AiB)
- Some use A and an indirect B (MOXIE_F1_ABi)
- Some consume a 4 byte immediate value and use X (MOXIE_F1_4A)
- Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4)
- Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4)
-
- Form 2 instructions also come in different flavors:
-
- Some have no arguments (MOXIE_F2_NARG)
- Some use the A register and an 8-bit value (MOXIE_F2_A8V)
-
- Form 3 instructions also come in different flavors:
-
- Some have no arguments (MOXIE_F3_NARG)
- Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */
-
-#define MOXIE_F1_NARG 0x100
-#define MOXIE_F1_A 0x101
-#define MOXIE_F1_AB 0x102
-/* #define MOXIE_F1_ABC 0x103 */
-#define MOXIE_F1_A4 0x104
-#define MOXIE_F1_4 0x105
-#define MOXIE_F1_AiB 0x106
-#define MOXIE_F1_ABi 0x107
-#define MOXIE_F1_4A 0x108
-#define MOXIE_F1_AiB4 0x109
-#define MOXIE_F1_ABi4 0x10a
-#define MOXIE_F1_M 0x10b
-
-#define MOXIE_F2_NARG 0x200
-#define MOXIE_F2_A8V 0x201
-
-#define MOXIE_F3_NARG 0x300
-#define MOXIE_F3_PCREL 0x301
-
-typedef struct moxie_opc_info_t {
- short opcode;
- unsigned itype;
- const char * name;
-} moxie_opc_info_t;
-
-extern const moxie_opc_info_t moxie_form1_opc_info[64];
-extern const moxie_opc_info_t moxie_form2_opc_info[4];
-extern const moxie_opc_info_t moxie_form3_opc_info[16];
-
-/* The moxie processor's 16-bit instructions come in two forms:
-
- FORM 1 instructions start with a 0 bit...
-
- 0oooooooaaaabbbb
- 0 F
-
- ooooooo - form 1 opcode number
- aaaa - operand A
- bbbb - operand B
-
- FORM 2 instructions start with bits "10"...
-
- 10ooaaaavvvvvvvv
- 0 F
-
- oo - form 2 opcode number
- aaaa - operand A
- vvvvvvvv - 8-bit immediate value
-
- FORM 3 instructions start with a bits "11"...
-
- 11oooovvvvvvvvvv
- 0 F
-
- oooo - form 3 opcode number
- vvvvvvvvvv - 10-bit immediate value. */
-
-const moxie_opc_info_t moxie_form1_opc_info[64] =
- {
- { 0x00, MOXIE_F1_NARG, "nop" },
- { 0x01, MOXIE_F1_A4, "ldi.l" },
- { 0x02, MOXIE_F1_AB, "mov" },
- { 0x03, MOXIE_F1_M, "jsra" },
- { 0x04, MOXIE_F1_NARG, "ret" },
- { 0x05, MOXIE_F1_AB, "add.l" },
- { 0x06, MOXIE_F1_AB, "push" },
- { 0x07, MOXIE_F1_AB, "pop" },
- { 0x08, MOXIE_F1_A4, "lda.l" },
- { 0x09, MOXIE_F1_4A, "sta.l" },
- { 0x0a, MOXIE_F1_ABi, "ld.l" },
- { 0x0b, MOXIE_F1_AiB, "st.l" },
- { 0x0c, MOXIE_F1_ABi4, "ldo.l" },
- { 0x0d, MOXIE_F1_AiB4, "sto.l" },
- { 0x0e, MOXIE_F1_AB, "cmp" },
- { 0x0f, MOXIE_F1_NARG, "bad" },
- { 0x10, MOXIE_F1_NARG, "bad" },
- { 0x11, MOXIE_F1_NARG, "bad" },
- { 0x12, MOXIE_F1_NARG, "bad" },
- { 0x13, MOXIE_F1_NARG, "bad" },
- { 0x14, MOXIE_F1_NARG, "bad" },
- { 0x15, MOXIE_F1_NARG, "bad" },
- { 0x16, MOXIE_F1_NARG, "bad" },
- { 0x17, MOXIE_F1_NARG, "bad" },
- { 0x18, MOXIE_F1_NARG, "bad" },
- { 0x19, MOXIE_F1_A, "jsr" },
- { 0x1a, MOXIE_F1_M, "jmpa" },
- { 0x1b, MOXIE_F1_A4, "ldi.b" },
- { 0x1c, MOXIE_F1_ABi, "ld.b" },
- { 0x1d, MOXIE_F1_A4, "lda.b" },
- { 0x1e, MOXIE_F1_AiB, "st.b" },
- { 0x1f, MOXIE_F1_4A, "sta.b" },
- { 0x20, MOXIE_F1_A4, "ldi.s" },
- { 0x21, MOXIE_F1_ABi, "ld.s" },
- { 0x22, MOXIE_F1_A4, "lda.s" },
- { 0x23, MOXIE_F1_AiB, "st.s" },
- { 0x24, MOXIE_F1_4A, "sta.s" },
- { 0x25, MOXIE_F1_A, "jmp" },
- { 0x26, MOXIE_F1_AB, "and" },
- { 0x27, MOXIE_F1_AB, "lshr" },
- { 0x28, MOXIE_F1_AB, "ashl" },
- { 0x29, MOXIE_F1_AB, "sub.l" },
- { 0x2a, MOXIE_F1_AB, "neg" },
- { 0x2b, MOXIE_F1_AB, "or" },
- { 0x2c, MOXIE_F1_AB, "not" },
- { 0x2d, MOXIE_F1_AB, "ashr" },
- { 0x2e, MOXIE_F1_AB, "xor" },
- { 0x2f, MOXIE_F1_AB, "mul.l" },
- { 0x30, MOXIE_F1_4, "swi" },
- { 0x31, MOXIE_F1_AB, "div.l" },
- { 0x32, MOXIE_F1_AB, "udiv.l" },
- { 0x33, MOXIE_F1_AB, "mod.l" },
- { 0x34, MOXIE_F1_AB, "umod.l" },
- { 0x35, MOXIE_F1_NARG, "brk" },
- { 0x36, MOXIE_F1_ABi4, "ldo.b" },
- { 0x37, MOXIE_F1_AiB4, "sto.b" },
- { 0x38, MOXIE_F1_ABi4, "ldo.s" },
- { 0x39, MOXIE_F1_AiB4, "sto.s" },
- { 0x3a, MOXIE_F1_NARG, "bad" },
- { 0x3b, MOXIE_F1_NARG, "bad" },
- { 0x3c, MOXIE_F1_NARG, "bad" },
- { 0x3d, MOXIE_F1_NARG, "bad" },
- { 0x3e, MOXIE_F1_NARG, "bad" },
- { 0x3f, MOXIE_F1_NARG, "bad" }
- };
-
-const moxie_opc_info_t moxie_form2_opc_info[4] =
- {
- { 0x00, MOXIE_F2_A8V, "inc" },
- { 0x01, MOXIE_F2_A8V, "dec" },
- { 0x02, MOXIE_F2_A8V, "gsr" },
- { 0x03, MOXIE_F2_A8V, "ssr" }
- };
-
-const moxie_opc_info_t moxie_form3_opc_info[16] =
- {
- { 0x00, MOXIE_F3_PCREL,"beq" },
- { 0x01, MOXIE_F3_PCREL,"bne" },
- { 0x02, MOXIE_F3_PCREL,"blt" },
- { 0x03, MOXIE_F3_PCREL,"bgt" },
- { 0x04, MOXIE_F3_PCREL,"bltu" },
- { 0x05, MOXIE_F3_PCREL,"bgtu" },
- { 0x06, MOXIE_F3_PCREL,"bge" },
- { 0x07, MOXIE_F3_PCREL,"ble" },
- { 0x08, MOXIE_F3_PCREL,"bgeu" },
- { 0x09, MOXIE_F3_PCREL,"bleu" },
- { 0x0a, MOXIE_F3_NARG, "bad" },
- { 0x0b, MOXIE_F3_NARG, "bad" },
- { 0x0c, MOXIE_F3_NARG, "bad" },
- { 0x0d, MOXIE_F3_NARG, "bad" },
- { 0x0e, MOXIE_F3_NARG, "bad" },
- { 0x0f, MOXIE_F3_NARG, "bad" }
- };
-
-/* Macros to extract operands from the instruction word. */
-#define OP_A(i) ((i >> 4) & 0xf)
-#define OP_B(i) (i & 0xf)
-#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
-
-static const char * reg_names[16] =
- { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5",
- "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
-
-int
-print_insn_moxie(bfd_vma addr, struct disassemble_info * info)
-{
- int length = 2;
- int status;
- stream = info->stream;
- const moxie_opc_info_t * opcode;
- bfd_byte buffer[4];
- unsigned short iword;
- fprintf_function fpr = info->fprintf_func;
-
- if ((status = info->read_memory_func(addr, buffer, 2, info)))
- goto fail;
- iword = (bfd_getb16(buffer) >> 16);
-
- /* Form 1 instructions have the high bit set to 0. */
- if ((iword & (1<<15)) == 0) {
- /* Extract the Form 1 opcode. */
- opcode = &moxie_form1_opc_info[iword >> 8];
- switch (opcode->itype) {
- case MOXIE_F1_NARG:
- fpr(stream, "%s", opcode->name);
- break;
- case MOXIE_F1_A:
- fpr(stream, "%s\t%s", opcode->name,
- reg_names[OP_A(iword)]);
- break;
- case MOXIE_F1_AB:
- fpr(stream, "%s\t%s, %s", opcode->name,
- reg_names[OP_A(iword)],
- reg_names[OP_B(iword)]);
- break;
- case MOXIE_F1_A4:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t%s, 0x%x", opcode->name,
- reg_names[OP_A(iword)], imm);
- length = 6;
- }
- break;
- case MOXIE_F1_4:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t0x%x", opcode->name, imm);
- length = 6;
- }
- break;
- case MOXIE_F1_M:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t", opcode->name);
- info->print_address_func((bfd_vma) imm, info);
- length = 6;
- }
- break;
- case MOXIE_F1_AiB:
- fpr (stream, "%s\t(%s), %s", opcode->name,
- reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
- break;
- case MOXIE_F1_ABi:
- fpr(stream, "%s\t%s, (%s)", opcode->name,
- reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
- break;
- case MOXIE_F1_4A:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t0x%x, %s",
- opcode->name, imm, reg_names[OP_A(iword)]);
- length = 6;
- }
- break;
- case MOXIE_F1_AiB4:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t0x%x(%s), %s", opcode->name,
- imm,
- reg_names[OP_A(iword)],
- reg_names[OP_B(iword)]);
- length = 6;
- }
- break;
- case MOXIE_F1_ABi4:
- {
- unsigned imm;
- if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
- goto fail;
- imm = bfd_getb32(buffer);
- fpr(stream, "%s\t%s, 0x%x(%s)",
- opcode->name,
- reg_names[OP_A(iword)],
- imm,
- reg_names[OP_B(iword)]);
- length = 6;
- }
- break;
- default:
- abort();
- }
- }
- else if ((iword & (1<<14)) == 0) {
- /* Extract the Form 2 opcode. */
- opcode = &moxie_form2_opc_info[(iword >> 12) & 3];
- switch (opcode->itype) {
- case MOXIE_F2_A8V:
- fpr(stream, "%s\t%s, 0x%x",
- opcode->name,
- reg_names[(iword >> 8) & 0xf],
- iword & ((1 << 8) - 1));
- break;
- case MOXIE_F2_NARG:
- fpr(stream, "%s", opcode->name);
- break;
- default:
- abort();
- }
- } else {
- /* Extract the Form 3 opcode. */
- opcode = &moxie_form3_opc_info[(iword >> 10) & 15];
- switch (opcode->itype) {
- case MOXIE_F3_PCREL:
- fpr(stream, "%s\t", opcode->name);
- info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2),
- info);
- break;
- default:
- abort();
- }
- }
-
- return length;
-
- fail:
- info->memory_error_func(status, addr, info);
- return -1;
-}
diff --git a/docs/_templates/editpage.html b/docs/_templates/editpage.html
deleted file mode 100644
index 4319b0f5ac..0000000000
--- a/docs/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/conf.py b/docs/conf.py
index 2ee6111872..00cf66ab54 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -29,6 +29,7 @@
import os
import sys
import sphinx
+from distutils.version import LooseVersion
from sphinx.errors import ConfigError
# Make Sphinx fail cleanly if using an old Python, rather than obscurely
@@ -150,38 +151,47 @@ with open(os.path.join(qemu_docdir, 'defs.rst.inc')) as f:
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
-html_theme = 'alabaster'
+try:
+ import sphinx_rtd_theme
+except ImportError:
+ raise ConfigError(
+ 'The Sphinx \'sphinx_rtd_theme\' HTML theme was not found.\n'
+ )
+
+html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-# We initialize this to empty here, so the per-manual conf.py can just
-# add individual key/value entries.
-html_theme_options = {
-}
+if LooseVersion(sphinx_rtd_theme.__version__) >= LooseVersion("0.4.3"):
+ html_theme_options = {
+ "style_nav_header_background": "#802400",
+ }
+
+html_logo = os.path.join(qemu_docdir, "../ui/icons/qemu_128x128.png")
+
+html_favicon = os.path.join(qemu_docdir, "../ui/icons/qemu_32x32.png")
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-# QEMU doesn't yet have any static files, so comment this out so we don't
-# get a warning about a missing directory.
-# If we do ever add this then it would probably be better to call the
-# subdirectory sphinx_static, as the Linux kernel does.
-# html_static_path = ['_static']
+html_static_path = [os.path.join(qemu_docdir, "sphinx-static")]
+
+html_css_files = [
+ 'theme_overrides.css',
+]
+
+html_context = {
+ "display_gitlab": True,
+ "gitlab_user": "qemu-project",
+ "gitlab_repo": "qemu",
+ "gitlab_version": "master",
+ "conf_py_path": "/docs/", # Path in the checkout to the docs root
+}
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
-#
-# This is required for the alabaster theme
-# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
-html_sidebars = {
- '**': [
- 'about.html',
- 'editpage.html',
- 'navigation.html',
- 'searchbox.html',
- ]
-}
+#html_sidebars = {}
# Don't copy the rST source files to the HTML output directory,
# and don't put links to the sources into the output HTML.
diff --git a/docs/devel/_templates/editpage.html b/docs/devel/_templates/editpage.html
deleted file mode 100644
index a86d22bca8..0000000000
--- a/docs/devel/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/devel/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/devel/qgraph.rst b/docs/devel/qgraph.rst
index a9aff167ad..318534d4b0 100644
--- a/docs/devel/qgraph.rst
+++ b/docs/devel/qgraph.rst
@@ -92,6 +92,64 @@ The basic framework steps are the following:
Depending on the QEMU binary used, only some drivers/machines will be
available and only test that are reached by them will be executed.
+Troubleshooting unavailable tests
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+If there is no path from an available machine to a test then that test will be
+unavailable and won't execute. This can happen if a test or driver did not set
+up its qgraph node correctly. It can also happen if the necessary machine type
+or device is missing from the QEMU binary because it was compiled out or
+otherwise.
+
+It is possible to troubleshoot unavailable tests by running::
+
+ $ QTEST_QEMU_BINARY=build/qemu-system-x86_64 build/tests/qtest/qos-test --verbose
+ # ALL QGRAPH EDGES: {
+ # src='virtio-net'
+ # |-> dest='virtio-net-tests/vhost-user/multiqueue' type=2 (node=0x559142109e30)
+ # |-> dest='virtio-net-tests/vhost-user/migrate' type=2 (node=0x559142109d00)
+ # src='virtio-net-pci'
+ # |-> dest='virtio-net' type=1 (node=0x55914210d740)
+ # src='pci-bus'
+ # |-> dest='virtio-net-pci' type=2 (node=0x55914210d880)
+ # src='pci-bus-pc'
+ # |-> dest='pci-bus' type=1 (node=0x559142103f40)
+ # src='i440FX-pcihost'
+ # |-> dest='pci-bus-pc' type=0 (node=0x55914210ac70)
+ # src='x86_64/pc'
+ # |-> dest='i440FX-pcihost' type=0 (node=0x5591421117f0)
+ # src=''
+ # |-> dest='x86_64/pc' type=0 (node=0x559142111600)
+ # |-> dest='arm/raspi2' type=0 (node=0x559142110740)
+ ...
+ # }
+ # ALL QGRAPH NODES: {
+ # name='virtio-net-tests/announce-self' type=3 cmd_line='(null)' [available]
+ # name='arm/raspi2' type=0 cmd_line='-M raspi2 ' [UNAVAILABLE]
+ ...
+ # }
+
+The ``virtio-net-tests/announce-self`` test is listed as "available" in the
+"ALL QGRAPH NODES" output. This means the test will execute. We can follow the
+qgraph path in the "ALL QGRAPH EDGES" output as follows: '' -> 'x86_64/pc' ->
+'i440FX-pcihost' -> 'pci-bus-pc' -> 'pci-bus' -> 'virtio-net-pci' ->
+'virtio-net'. The root of the qgraph is '' and the depth first search begins
+there.
+
+The ``arm/raspi`` machine node is listed as "UNAVAILABLE". Although it is
+reachable from the root via '' -> 'arm/raspi2' the node is unavailable because
+the QEMU binary did not list it when queried by the framework. This is expected
+because we used the ``qemu-system-x86_64`` binary which does not support ARM
+machine types.
+
+If a test is unexpectedly listed as "UNAVAILABLE", first check that the "ALL
+QGRAPH EDGES" output reports edge connectivity from the root ('') to the test.
+If there is no connectivity then the qgraph nodes were not set up correctly and
+the driver or test code is incorrect. If there is connectivity, check the
+availability of each node in the path in the "ALL QGRAPH NODES" output. The
+first unavailable node in the path is the reason why the test is unavailable.
+Typically this is because the QEMU binary lacks support for the necessary
+machine type or device.
+
Creating a new driver and its interface
"""""""""""""""""""""""""""""""""""""""""
diff --git a/docs/interop/_templates/editpage.html b/docs/interop/_templates/editpage.html
deleted file mode 100644
index 215e562681..0000000000
--- a/docs/interop/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/interop/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/meson.build b/docs/meson.build
index f84306ba7e..855e3916e9 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -27,10 +27,9 @@ if sphinx_build.found()
build_docs = (sphinx_build_test_out.returncode() == 0)
if not build_docs
- warning('@0@ is either too old or uses too old a Python version'
- .format(sphinx_build.full_path()))
+ warning('@0@: @1@'.format(sphinx_build.full_path(), sphinx_build_test_out.stderr()))
if get_option('docs').enabled()
- error('Install a Python 3 version of python-sphinx')
+ error('Install a Python 3 version of python-sphinx and the readthedoc theme')
endif
endif
endif
diff --git a/docs/specs/_templates/editpage.html b/docs/specs/_templates/editpage.html
deleted file mode 100644
index aaa468aa98..0000000000
--- a/docs/specs/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/specs/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/sphinx-static/theme_overrides.css b/docs/sphinx-static/theme_overrides.css
new file mode 100644
index 0000000000..c70ef95128
--- /dev/null
+++ b/docs/sphinx-static/theme_overrides.css
@@ -0,0 +1,161 @@
+/* -*- coding: utf-8; mode: css -*-
+ *
+ * Sphinx HTML theme customization: read the doc
+ * Based on Linux Documentation/sphinx-static/theme_overrides.css
+ */
+
+/* Improve contrast and increase size for easier reading. */
+
+body {
+ font-family: serif;
+ color: black;
+ font-size: 100%;
+}
+
+h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend {
+ font-family: sans-serif;
+}
+
+.rst-content dl:not(.docutils) dt {
+ border-top: none;
+ border-left: solid 3px #ccc;
+ background-color: #f0f0f0;
+ color: black;
+}
+
+.wy-nav-top {
+ background: #802400;
+}
+
+.wy-side-nav-search input[type="text"] {
+ border-color: #f60;
+}
+
+.wy-menu-vertical p.caption {
+ color: white;
+}
+
+.wy-menu-vertical li.current a {
+ color: #505050;
+}
+
+.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a {
+ color: #303030;
+}
+
+.fa-gitlab {
+ box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2), 0 3px 10px 0 rgba(0,0,0,0.19);
+ border-radius: 5px;
+}
+
+div[class^="highlight"] pre {
+ font-family: monospace;
+ color: black;
+ font-size: 100%;
+}
+
+.wy-menu-vertical {
+ font-family: sans-serif;
+}
+
+.c {
+ font-style: normal;
+}
+
+p {
+ font-size: 100%;
+}
+
+/* Interim: Code-blocks with line nos - lines and line numbers don't line up.
+ * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419
+ */
+
+div[class^="highlight"] pre {
+ line-height: normal;
+}
+.rst-content .highlight > pre {
+ line-height: normal;
+}
+
+/* Keep fields from being strangely far apart due to inheirited table CSS. */
+.rst-content table.field-list th.field-name {
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
+.rst-content table.field-list td.field-body {
+ padding-top: 1px;
+ padding-bottom: 1px;
+}
+
+@media screen {
+
+ /* content column
+ *
+ * RTD theme's default is 800px as max width for the content, but we have
+ * tables with tons of columns, which need the full width of the view-port.
+ */
+
+ .wy-nav-content{max-width: none; }
+
+ /* table:
+ *
+ * - Sequences of whitespace should collapse into a single whitespace.
+ * - make the overflow auto (scrollbar if needed)
+ * - align caption "left" ("center" is unsuitable on vast tables)
+ */
+
+ .wy-table-responsive table td { white-space: normal; }
+ .wy-table-responsive { overflow: auto; }
+ .rst-content table.docutils caption { text-align: left; font-size: 100%; }
+
+ /* captions:
+ *
+ * - captions should have 100% (not 85%) font size
+ * - hide the permalink symbol as long as link is not hovered
+ */
+
+ .toc-title {
+ font-size: 150%;
+ font-weight: bold;
+ }
+
+ caption, .wy-table caption, .rst-content table.field-list caption {
+ font-size: 100%;
+ }
+ caption a.headerlink { opacity: 0; }
+ caption a.headerlink:hover { opacity: 1; }
+
+ /* Menu selection and keystrokes */
+
+ span.menuselection {
+ color: blue;
+ font-family: "Courier New", Courier, monospace
+ }
+
+ code.kbd, code.kbd span {
+ color: white;
+ background-color: darkblue;
+ font-weight: bold;
+ font-family: "Courier New", Courier, monospace
+ }
+
+ /* fix bottom margin of lists items */
+
+ .rst-content .section ul li:last-child, .rst-content .section ul li p:last-child {
+ margin-bottom: 12px;
+ }
+
+ /* inline literal: drop the borderbox, padding and red color */
+
+ code, .rst-content tt, .rst-content code {
+ color: inherit;
+ border: none;
+ padding: unset;
+ background: inherit;
+ font-size: 85%;
+ }
+
+ .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal {
+ color: inherit;
+ }
+}
diff --git a/docs/system/_templates/editpage.html b/docs/system/_templates/editpage.html
deleted file mode 100644
index 6586b2e257..0000000000
--- a/docs/system/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/system/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index f9169077ae..abbf8243a3 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -198,30 +198,6 @@ from Linux upstream kernel, declare it deprecated.
System emulator CPUS
--------------------
-``moxie`` CPU (since 5.2.0)
-'''''''''''''''''''''''''''
-
-The ``moxie`` guest CPU support is deprecated and will be removed in
-a future version of QEMU. It's unclear whether anybody is still using
-CPU emulation in QEMU, and there are no test images available to make
-sure that the code is still working.
-
-``lm32`` CPUs (since 5.2.0)
-'''''''''''''''''''''''''''
-
-The ``lm32`` guest CPU support is deprecated and will be removed in
-a future version of QEMU. The only public user of this architecture
-was the milkymist project, which has been dead for years; there was
-never an upstream Linux port.
-
-``unicore32`` CPUs (since 5.2.0)
-''''''''''''''''''''''''''''''''
-
-The ``unicore32`` guest CPU support is deprecated and will be removed in
-a future version of QEMU. Support for this CPU was removed from the
-upstream Linux kernel, and there is no available upstream toolchain
-to build binaries for it.
-
``Icelake-Client`` CPU Model (since 5.2.0)
''''''''''''''''''''''''''''''''''''''''''
@@ -293,15 +269,6 @@ The above, converted to the current supported format::
json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"}
-``sheepdog`` driver (since 5.2.0)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``sheepdog`` block device driver is deprecated. The corresponding upstream
-server project is no longer actively maintained. Users are recommended to switch
-to an alternative distributed block device driver such as RBD. The
-``qemu-img convert`` command can be used to liberate existing data by moving
-it out of sheepdog volumes into an alternative storage backend.
-
linux-user mode CPUs
--------------------
diff --git a/docs/system/device-url-syntax.rst.inc b/docs/system/device-url-syntax.rst.inc
index 6f6ec8366b..d15a021508 100644
--- a/docs/system/device-url-syntax.rst.inc
+++ b/docs/system/device-url-syntax.rst.inc
@@ -85,24 +85,6 @@ These are specified using a special URL syntax.
Currently authentication must be done using ssh-agent. Other
authentication methods may be supported in future.
-``Sheepdog``
- Sheepdog is a distributed storage system for QEMU. QEMU supports
- using either local sheepdog devices or remote networked devices.
-
- Syntax for specifying a sheepdog device
-
- ::
-
- sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag]
-
- Example
-
- .. parsed-literal::
-
- |qemu_system| --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine
-
- See also https://sheepdog.github.io/sheepdog/.
-
``GlusterFS``
GlusterFS is a user space distributed file system. QEMU supports the
use of GlusterFS volumes for hosting VM disk images using TCP, Unix
diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst
index 6bf8a4eb48..531ddbc8e3 100644
--- a/docs/system/generic-loader.rst
+++ b/docs/system/generic-loader.rst
@@ -92,9 +92,12 @@ shown below:
specified in the executable format header. This option should only
be used for the boot image. This will also cause the image to be
written to the specified CPU's address space. If not specified, the
- default is CPU 0. <force-raw> - Setting force-raw=on forces the file
- to be treated as a raw image. This can be used to load supported
- executable formats as if they were raw.
+ default is CPU 0.
+
+``<force-raw>``
+ Setting 'force-raw=on' forces the file to be treated as a raw image.
+ This can be used to load supported executable formats as if they
+ were raw.
All values are parsed using the standard QemuOpts parsing. This allows the user
to specify any values in any format supported. By default the values
diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc
index 60a064b232..16225710eb 100644
--- a/docs/system/qemu-block-drivers.rst.inc
+++ b/docs/system/qemu-block-drivers.rst.inc
@@ -547,75 +547,6 @@ also available. Here are some example of the older syntax:
|qemu_system| linux2.img -hdb nbd:unix:/tmp/my_socket
|qemu_system| -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst
-
-
-Sheepdog disk images
-~~~~~~~~~~~~~~~~~~~~
-
-Sheepdog is a distributed storage system for QEMU. It provides highly
-available block level storage volumes that can be attached to
-QEMU-based virtual machines.
-
-You can create a Sheepdog disk image with the command:
-
-.. parsed-literal::
-
- qemu-img create sheepdog:///IMAGE SIZE
-
-where *IMAGE* is the Sheepdog image name and *SIZE* is its
-size.
-
-To import the existing *FILENAME* to Sheepdog, you can use a
-convert command.
-
-.. parsed-literal::
-
- qemu-img convert FILENAME sheepdog:///IMAGE
-
-You can boot from the Sheepdog disk image with the command:
-
-.. parsed-literal::
-
- |qemu_system| sheepdog:///IMAGE
-
-You can also create a snapshot of the Sheepdog image like qcow2.
-
-.. parsed-literal::
-
- qemu-img snapshot -c TAG sheepdog:///IMAGE
-
-where *TAG* is a tag name of the newly created snapshot.
-
-To boot from the Sheepdog snapshot, specify the tag name of the
-snapshot.
-
-.. parsed-literal::
-
- |qemu_system| sheepdog:///IMAGE#TAG
-
-You can create a cloned image from the existing snapshot.
-
-.. parsed-literal::
-
- qemu-img create -b sheepdog:///BASE#TAG sheepdog:///IMAGE
-
-where *BASE* is an image name of the source snapshot and *TAG*
-is its tag name.
-
-You can use an unix socket instead of an inet socket:
-
-.. parsed-literal::
-
- |qemu_system| sheepdog+unix:///IMAGE?socket=PATH
-
-If the Sheepdog daemon doesn't run on the local host, you need to
-specify one of the Sheepdog servers to connect to.
-
-.. parsed-literal::
-
- qemu-img create sheepdog://HOSTNAME:PORT/IMAGE SIZE
- |qemu_system| sheepdog://HOSTNAME:PORT/IMAGE
-
iSCSI LUNs
~~~~~~~~~~
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst
index c21e6fa5ee..5a462ac568 100644
--- a/docs/system/removed-features.rst
+++ b/docs/system/removed-features.rst
@@ -291,6 +291,27 @@ via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
The ``max-cpu-compat`` property of the ``pseries`` machine type should be used
instead.
+``moxie`` CPU (removed in 6.1)
+''''''''''''''''''''''''''''''
+
+Nobody was using this CPU emulation in QEMU, and there were no test images
+available to make sure that the code is still working, so it has been removed
+without replacement.
+
+``lm32`` CPUs (removed in 6.1.0)
+''''''''''''''''''''''''''''''''
+
+The only public user of this architecture was the milkymist project,
+which has been dead for years; there was never an upstream Linux
+port. Removed without replacement.
+
+``unicore32`` CPUs (since 6.1.0)
+''''''''''''''''''''''''''''''''
+
+Support for this CPU was removed from the upstream Linux kernel, and
+there is no available upstream toolchain to build binaries for it.
+Removed without replacement.
+
System emulator machines
------------------------
@@ -467,3 +488,10 @@ VXHS backend (removed in 5.1)
'''''''''''''''''''''''''''''
The VXHS code did not compile since v2.12.0. It was removed in 5.1.
+
+``sheepdog`` driver (removed in 6.0)
+''''''''''''''''''''''''''''''''''''
+
+The corresponding upstream server project is no longer maintained.
+Users are recommended to switch to an alternative distributed block
+device driver such as RBD.
diff --git a/docs/system/riscv/shakti-c.rst b/docs/system/riscv/shakti-c.rst
new file mode 100644
index 0000000000..a6035d42b0
--- /dev/null
+++ b/docs/system/riscv/shakti-c.rst
@@ -0,0 +1,82 @@
+Shakti C Reference Platform (``shakti_c``)
+==========================================
+
+Shakti C Reference Platform is a reference platform based on arty a7 100t
+for the Shakti SoC.
+
+Shakti SoC is a SoC based on the Shakti C-class processor core. Shakti C
+is a 64bit RV64GCSUN processor core.
+
+For more details on Shakti SoC, please see:
+https://gitlab.com/shaktiproject/cores/shakti-soc/-/blob/master/fpga/boards/artya7-100t/c-class/README.rst
+
+For more info on the Shakti C-class core, please see:
+https://c-class.readthedocs.io/en/latest/
+
+Supported devices
+-----------------
+
+The ``shakti_c`` machine supports the following devices:
+
+ * 1 C-class core
+ * Core Level Interruptor (CLINT)
+ * Platform-Level Interrupt Controller (PLIC)
+ * 1 UART
+
+Boot options
+------------
+
+The ``shakti_c`` machine can start using the standard -bios
+functionality for loading the baremetal application or opensbi.
+
+Boot the machine
+----------------
+
+Shakti SDK
+~~~~~~~~~~
+Shakti SDK can be used to generate the baremetal example UART applications.
+
+.. code-block:: bash
+
+ $ git clone https://gitlab.com/behindbytes/shakti-sdk.git
+ $ cd shakti-sdk
+ $ make software PROGRAM=loopback TARGET=artix7_100t
+
+Binary would be generated in:
+ software/examples/uart_applns/loopback/output/loopback.shakti
+
+You could also download the precompiled example applicatons using below
+commands.
+
+.. code-block:: bash
+
+ $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/sdk/shakti_sdk_qemu.zip
+ $ unzip shakti_sdk_qemu.zip
+
+Then we can run the UART example using:
+
+.. code-block:: bash
+
+ $ qemu-system-riscv64 -M shakti_c -nographic \
+ -bios path/to/shakti_sdk_qemu/loopback.shakti
+
+OpenSBI
+~~~~~~~
+We can also run OpenSBI with Test Payload.
+
+.. code-block:: bash
+
+ $ git clone https://github.com/riscv/opensbi.git -b v0.9
+ $ cd opensbi
+ $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/dts/shakti.dtb
+ $ export CROSS_COMPILE=riscv64-unknown-elf-
+ $ export FW_FDT_PATH=./shakti.dtb
+ $ make PLATFORM=generic
+
+fw_payload.elf would be generated in build/platform/generic/firmware/fw_payload.elf.
+Boot it using the below qemu command.
+
+.. code-block:: bash
+
+ $ qemu-system-riscv64 -M shakti_c -nographic \
+ -bios path/to/fw_payload.elf
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 8d5946fbbb..4b3c78382c 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -67,6 +67,7 @@ undocumented; you can get a complete list by running
:maxdepth: 1
riscv/microchip-icicle-kit
+ riscv/shakti-c
riscv/sifive_u
RISC-V CPU features
diff --git a/docs/tools/_templates/editpage.html b/docs/tools/_templates/editpage.html
deleted file mode 100644
index 2a9c8fc92b..0000000000
--- a/docs/tools/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/tools/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index c9efcfaefc..cfe1147879 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -866,6 +866,37 @@ Supported image file formats:
issue ``lsattr filename`` to check if the NOCOW flag is set or not
(Capital 'C' is NOCOW flag).
+ ``data_file``
+ Filename where all guest data will be stored. If this option is used,
+ the qcow2 file will only contain the image's metadata.
+
+ Note: Data loss will occur if the given filename already exists when
+ using this option with ``qemu-img create`` since ``qemu-img`` will create
+ the data file anew, overwriting the file's original contents. To simply
+ update the reference to point to the given pre-existing file, use
+ ``qemu-img amend``.
+
+ ``data_file_raw``
+ If this option is set to ``on``, QEMU will always keep the external data
+ file consistent as a standalone read-only raw image.
+
+ It does this by forwarding all write accesses to the qcow2 file through to
+ the raw data file, including their offsets. Therefore, data that is visible
+ on the qcow2 node (i.e., to the guest) at some offset is visible at the same
+ offset in the raw data file. This results in a read-only raw image. Writes
+ that bypass the qcow2 metadata may corrupt the qcow2 metadata because the
+ out-of-band writes may result in the metadata falling out of sync with the
+ raw image.
+
+ If this option is ``off``, QEMU will use the data file to store data in an
+ arbitrary manner. The file’s content will not make sense without the
+ accompanying qcow2 metadata. Where data is written will have no relation to
+ its offset as seen by the guest, and some writes (specifically zero writes)
+ may not be forwarded to the data file at all, but will only be handled by
+ modifying qcow2 metadata.
+
+ This option can only be enabled if ``data_file`` is set.
+
``Other``
QEMU also supports various other image file formats for
diff --git a/docs/user/_templates/editpage.html b/docs/user/_templates/editpage.html
deleted file mode 100644
index 1f5ee01e60..0000000000
--- a/docs/user/_templates/editpage.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="editpage">
- <ul>
- <li><a href="https://gitlab.com/qemu-project/qemu/-/blob/master/docs/user/{{pagename}}.rst">Page source</a></li>
- </ul>
-</div>
diff --git a/fpu/softfloat-parts-addsub.c.inc b/fpu/softfloat-parts-addsub.c.inc
new file mode 100644
index 0000000000..ae5c1017c5
--- /dev/null
+++ b/fpu/softfloat-parts-addsub.c.inc
@@ -0,0 +1,62 @@
+/*
+ * Floating point arithmetic implementation
+ *
+ * The code in this source file is derived from release 2a of the SoftFloat
+ * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and
+ * some later contributions) are provided under that license, as detailed below.
+ * It has subsequently been modified by contributors to the QEMU Project,
+ * so some portions are provided under:
+ * the SoftFloat-2a license
+ * the BSD license
+ * GPL-v2-or-later
+ *
+ * Any future contributions to this file after December 1st 2014 will be
+ * taken to be licensed under the Softfloat-2a license unless specifically
+ * indicated otherwise.
+ */
+
+static void partsN(add_normal)(FloatPartsN *a, FloatPartsN *b)
+{
+ int exp_diff = a->exp - b->exp;
+
+ if (exp_diff > 0) {
+ frac_shrjam(b, exp_diff);
+ } else if (exp_diff < 0) {
+ frac_shrjam(a, -exp_diff);
+ a->exp = b->exp;
+ }
+
+ if (frac_add(a, a, b)) {
+ frac_shrjam(a, 1);
+ a->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
+ a->exp += 1;
+ }
+}
+
+static bool partsN(sub_normal)(FloatPartsN *a, FloatPartsN *b)
+{
+ int exp_diff = a->exp - b->exp;
+ int shift;
+
+ if (exp_diff > 0) {
+ frac_shrjam(b, exp_diff);
+ frac_sub(a, a, b);
+ } else if (exp_diff < 0) {
+ a->exp = b->exp;
+ a->sign ^= 1;
+ frac_shrjam(a, -exp_diff);
+ frac_sub(a, b, a);
+ } else if (frac_sub(a, a, b)) {
+ /* Overflow means that A was less than B. */
+ frac_neg(a);
+ a->sign ^= 1;
+ }
+
+ shift = frac_normalize(a);
+ if (likely(shift < N)) {
+ a->exp -= shift;
+ return true;
+ }
+ a->cls = float_class_zero;
+ return false;
+}
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
new file mode 100644
index 0000000000..a897a5a743
--- /dev/null
+++ b/fpu/softfloat-parts.c.inc
@@ -0,0 +1,817 @@
+/*
+ * QEMU float support
+ *
+ * The code in this source file is derived from release 2a of the SoftFloat
+ * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and
+ * some later contributions) are provided under that license, as detailed below.
+ * It has subsequently been modified by contributors to the QEMU Project,
+ * so some portions are provided under:
+ * the SoftFloat-2a license
+ * the BSD license
+ * GPL-v2-or-later
+ *
+ * Any future contributions to this file after December 1st 2014 will be
+ * taken to be licensed under the Softfloat-2a license unless specifically
+ * indicated otherwise.
+ */
+
+static void partsN(return_nan)(FloatPartsN *a, float_status *s)
+{
+ switch (a->cls) {
+ case float_class_snan:
+ float_raise(float_flag_invalid, s);
+ if (s->default_nan_mode) {
+ parts_default_nan(a, s);
+ } else {
+ parts_silence_nan(a, s);
+ }
+ break;
+ case float_class_qnan:
+ if (s->default_nan_mode) {
+ parts_default_nan(a, s);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
+ float_status *s)
+{
+ if (is_snan(a->cls) || is_snan(b->cls)) {
+ float_raise(float_flag_invalid, s);
+ }
+
+ if (s->default_nan_mode) {
+ parts_default_nan(a, s);
+ } else {
+ int cmp = frac_cmp(a, b);
+ if (cmp == 0) {
+ cmp = a->sign < b->sign;
+ }
+
+ if (pickNaN(a->cls, b->cls, cmp > 0, s)) {
+ a = b;
+ }
+ if (is_snan(a->cls)) {
+ parts_silence_nan(a, s);
+ }
+ }
+ return a;
+}
+
+static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
+ FloatPartsN *c, float_status *s,
+ int ab_mask, int abc_mask)
+{
+ int which;
+
+ if (unlikely(abc_mask & float_cmask_snan)) {
+ float_raise(float_flag_invalid, s);
+ }
+
+ which = pickNaNMulAdd(a->cls, b->cls, c->cls,
+ ab_mask == float_cmask_infzero, s);
+
+ if (s->default_nan_mode || which == 3) {
+ /*
+ * Note that this check is after pickNaNMulAdd so that function
+ * has an opportunity to set the Invalid flag for infzero.
+ */
+ parts_default_nan(a, s);
+ return a;
+ }
+
+ switch (which) {
+ case 0:
+ break;
+ case 1:
+ a = b;
+ break;
+ case 2:
+ a = c;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ if (is_snan(a->cls)) {
+ parts_silence_nan(a, s);
+ }
+ return a;
+}
+
+/*
+ * Canonicalize the FloatParts structure. Determine the class,
+ * unbias the exponent, and normalize the fraction.
+ */
+static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
+ const FloatFmt *fmt)
+{
+ if (unlikely(p->exp == 0)) {
+ if (likely(frac_eqz(p))) {
+ p->cls = float_class_zero;
+ } else if (status->flush_inputs_to_zero) {
+ float_raise(float_flag_input_denormal, status);
+ p->cls = float_class_zero;
+ frac_clear(p);
+ } else {
+ int shift = frac_normalize(p);
+ p->cls = float_class_normal;
+ p->exp = fmt->frac_shift - fmt->exp_bias - shift + 1;
+ }
+ } else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
+ p->cls = float_class_normal;
+ p->exp -= fmt->exp_bias;
+ frac_shl(p, fmt->frac_shift);
+ p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
+ } else if (likely(frac_eqz(p))) {
+ p->cls = float_class_inf;
+ } else {
+ frac_shl(p, fmt->frac_shift);
+ p->cls = (parts_is_snan_frac(p->frac_hi, status)
+ ? float_class_snan : float_class_qnan);
+ }
+}
+
+/*
+ * Round and uncanonicalize a floating-point number by parts. There
+ * are FRAC_SHIFT bits that may require rounding at the bottom of the
+ * fraction; these bits will be removed. The exponent will be biased
+ * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0].
+ */
+static void partsN(uncanon)(FloatPartsN *p, float_status *s,
+ const FloatFmt *fmt)
+{
+ const int exp_max = fmt->exp_max;
+ const int frac_shift = fmt->frac_shift;
+ const uint64_t frac_lsb = fmt->frac_lsb;
+ const uint64_t frac_lsbm1 = fmt->frac_lsbm1;
+ const uint64_t round_mask = fmt->round_mask;
+ const uint64_t roundeven_mask = fmt->roundeven_mask;
+ uint64_t inc;
+ bool overflow_norm;
+ int exp, flags = 0;
+
+ if (unlikely(p->cls != float_class_normal)) {
+ switch (p->cls) {
+ case float_class_zero:
+ p->exp = 0;
+ frac_clear(p);
+ return;
+ case float_class_inf:
+ g_assert(!fmt->arm_althp);
+ p->exp = fmt->exp_max;
+ frac_clear(p);
+ return;
+ case float_class_qnan:
+ case float_class_snan:
+ g_assert(!fmt->arm_althp);
+ p->exp = fmt->exp_max;
+ frac_shr(p, fmt->frac_shift);
+ return;
+ default:
+ break;
+ }
+ g_assert_not_reached();
+ }
+
+ switch (s->float_rounding_mode) {
+ case float_round_nearest_even:
+ overflow_norm = false;
+ inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
+ break;
+ case float_round_ties_away:
+ overflow_norm = false;
+ inc = frac_lsbm1;
+ break;
+ case float_round_to_zero:
+ overflow_norm = true;
+ inc = 0;
+ break;
+ case float_round_up:
+ inc = p->sign ? 0 : round_mask;
+ overflow_norm = p->sign;
+ break;
+ case float_round_down:
+ inc = p->sign ? round_mask : 0;
+ overflow_norm = !p->sign;
+ break;
+ case float_round_to_odd:
+ overflow_norm = true;
+ inc = p->frac_lo & frac_lsb ? 0 : round_mask;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ exp = p->exp + fmt->exp_bias;
+ if (likely(exp > 0)) {
+ if (p->frac_lo & round_mask) {
+ flags |= float_flag_inexact;
+ if (frac_addi(p, p, inc)) {
+ frac_shr(p, 1);
+ p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
+ exp++;
+ }
+ }
+ frac_shr(p, frac_shift);
+
+ if (fmt->arm_althp) {
+ /* ARM Alt HP eschews Inf and NaN for a wider exponent. */
+ if (unlikely(exp > exp_max)) {
+ /* Overflow. Return the maximum normal. */
+ flags = float_flag_invalid;
+ exp = exp_max;
+ frac_allones(p);
+ }
+ } else if (unlikely(exp >= exp_max)) {
+ flags |= float_flag_overflow | float_flag_inexact;
+ if (overflow_norm) {
+ exp = exp_max - 1;
+ frac_allones(p);
+ } else {
+ p->cls = float_class_inf;
+ exp = exp_max;
+ frac_clear(p);
+ }
+ }
+ } else if (s->flush_to_zero) {
+ flags |= float_flag_output_denormal;
+ p->cls = float_class_zero;
+ exp = 0;
+ frac_clear(p);
+ } else {
+ bool is_tiny = s->tininess_before_rounding || exp < 0;
+
+ if (!is_tiny) {
+ FloatPartsN discard;
+ is_tiny = !frac_addi(&discard, p, inc);
+ }
+
+ frac_shrjam(p, 1 - exp);
+
+ if (p->frac_lo & round_mask) {
+ /* Need to recompute round-to-even/round-to-odd. */
+ switch (s->float_rounding_mode) {
+ case float_round_nearest_even:
+ inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1
+ ? frac_lsbm1 : 0);
+ break;
+ case float_round_to_odd:
+ inc = p->frac_lo & frac_lsb ? 0 : round_mask;
+ break;
+ default:
+ break;
+ }
+ flags |= float_flag_inexact;
+ frac_addi(p, p, inc);
+ }
+
+ exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0;
+ frac_shr(p, frac_shift);
+
+ if (is_tiny && (flags & float_flag_inexact)) {
+ flags |= float_flag_underflow;
+ }
+ if (exp == 0 && frac_eqz(p)) {
+ p->cls = float_class_zero;
+ }
+ }
+ p->exp = exp;
+ float_raise(flags, s);
+}
+
+/*
+ * Returns the result of adding or subtracting the values of the
+ * floating-point values `a' and `b'. The operation is performed
+ * according to the IEC/IEEE Standard for Binary Floating-Point
+ * Arithmetic.
+ */
+static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b,
+ float_status *s, bool subtract)
+{
+ bool b_sign = b->sign ^ subtract;
+ int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+
+ if (a->sign != b_sign) {
+ /* Subtraction */
+ if (likely(ab_mask == float_cmask_normal)) {
+ if (parts_sub_normal(a, b)) {
+ return a;
+ }
+ /* Subtract was exact, fall through to set sign. */
+ ab_mask = float_cmask_zero;
+ }
+
+ if (ab_mask == float_cmask_zero) {
+ a->sign = s->float_rounding_mode == float_round_down;
+ return a;
+ }
+
+ if (unlikely(ab_mask & float_cmask_anynan)) {
+ goto p_nan;
+ }
+
+ if (ab_mask & float_cmask_inf) {
+ if (a->cls != float_class_inf) {
+ /* N - Inf */
+ goto return_b;
+ }
+ if (b->cls != float_class_inf) {
+ /* Inf - N */
+ return a;
+ }
+ /* Inf - Inf */
+ float_raise(float_flag_invalid, s);
+ parts_default_nan(a, s);
+ return a;
+ }
+ } else {
+ /* Addition */
+ if (likely(ab_mask == float_cmask_normal)) {
+ parts_add_normal(a, b);
+ return a;
+ }
+
+ if (ab_mask == float_cmask_zero) {
+ return a;
+ }
+
+ if (unlikely(ab_mask & float_cmask_anynan)) {
+ goto p_nan;
+ }
+
+ if (ab_mask & float_cmask_inf) {
+ a->cls = float_class_inf;
+ return a;
+ }
+ }
+
+ if (b->cls == float_class_zero) {
+ g_assert(a->cls == float_class_normal);
+ return a;
+ }
+
+ g_assert(a->cls == float_class_zero);
+ g_assert(b->cls == float_class_normal);
+ return_b:
+ b->sign = b_sign;
+ return b;
+
+ p_nan:
+ return parts_pick_nan(a, b, s);
+}
+
+/*
+ * Returns the result of multiplying the floating-point values `a' and
+ * `b'. The operation is performed according to the IEC/IEEE Standard
+ * for Binary Floating-Point Arithmetic.
+ */
+static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b,
+ float_status *s)
+{
+ int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+ bool sign = a->sign ^ b->sign;
+
+ if (likely(ab_mask == float_cmask_normal)) {
+ FloatPartsW tmp;
+
+ frac_mulw(&tmp, a, b);
+ frac_truncjam(a, &tmp);
+
+ a->exp += b->exp + 1;
+ if (!(a->frac_hi & DECOMPOSED_IMPLICIT_BIT)) {
+ frac_add(a, a, a);
+ a->exp -= 1;
+ }
+
+ a->sign = sign;
+ return a;
+ }
+
+ /* Inf * Zero == NaN */
+ if (unlikely(ab_mask == float_cmask_infzero)) {
+ float_raise(float_flag_invalid, s);
+ parts_default_nan(a, s);
+ return a;
+ }
+
+ if (unlikely(ab_mask & float_cmask_anynan)) {
+ return parts_pick_nan(a, b, s);
+ }
+
+ /* Multiply by 0 or Inf */
+ if (ab_mask & float_cmask_inf) {
+ a->cls = float_class_inf;
+ a->sign = sign;
+ return a;
+ }
+
+ g_assert(ab_mask & float_cmask_zero);
+ a->cls = float_class_zero;
+ a->sign = sign;
+ return a;
+}
+
+/*
+ * Returns the result of multiplying the floating-point values `a' and
+ * `b' then adding 'c', with no intermediate rounding step after the
+ * multiplication. The operation is performed according to the
+ * IEC/IEEE Standard for Binary Floating-Point Arithmetic 754-2008.
+ * The flags argument allows the caller to select negation of the
+ * addend, the intermediate product, or the final result. (The
+ * difference between this and having the caller do a separate
+ * negation is that negating externally will flip the sign bit on NaNs.)
+ *
+ * Requires A and C extracted into a double-sized structure to provide the
+ * extra space for the widening multiply.
+ */
+static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b,
+ FloatPartsN *c, int flags, float_status *s)
+{
+ int ab_mask, abc_mask;
+ FloatPartsW p_widen, c_widen;
+
+ ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+ abc_mask = float_cmask(c->cls) | ab_mask;
+
+ /*
+ * It is implementation-defined whether the cases of (0,inf,qnan)
+ * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
+ * they return if they do), so we have to hand this information
+ * off to the target-specific pick-a-NaN routine.
+ */
+ if (unlikely(abc_mask & float_cmask_anynan)) {
+ return parts_pick_nan_muladd(a, b, c, s, ab_mask, abc_mask);
+ }
+
+ if (flags & float_muladd_negate_c) {
+ c->sign ^= 1;
+ }
+
+ /* Compute the sign of the product into A. */
+ a->sign ^= b->sign;
+ if (flags & float_muladd_negate_product) {
+ a->sign ^= 1;
+ }
+
+ if (unlikely(ab_mask != float_cmask_normal)) {
+ if (unlikely(ab_mask == float_cmask_infzero)) {
+ goto d_nan;
+ }
+
+ if (ab_mask & float_cmask_inf) {
+ if (c->cls == float_class_inf && a->sign != c->sign) {
+ goto d_nan;
+ }
+ goto return_inf;
+ }
+
+ g_assert(ab_mask & float_cmask_zero);
+ if (c->cls == float_class_normal) {
+ *a = *c;
+ goto return_normal;
+ }
+ if (c->cls == float_class_zero) {
+ if (a->sign != c->sign) {
+ goto return_sub_zero;
+ }
+ goto return_zero;
+ }
+ g_assert(c->cls == float_class_inf);
+ }
+
+ if (unlikely(c->cls == float_class_inf)) {
+ a->sign = c->sign;
+ goto return_inf;
+ }
+
+ /* Perform the multiplication step. */
+ p_widen.sign = a->sign;
+ p_widen.exp = a->exp + b->exp + 1;
+ frac_mulw(&p_widen, a, b);
+ if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) {
+ frac_add(&p_widen, &p_widen, &p_widen);
+ p_widen.exp -= 1;
+ }
+
+ /* Perform the addition step. */
+ if (c->cls != float_class_zero) {
+ /* Zero-extend C to less significant bits. */
+ frac_widen(&c_widen, c);
+ c_widen.exp = c->exp;
+
+ if (a->sign == c->sign) {
+ parts_add_normal(&p_widen, &c_widen);
+ } else if (!parts_sub_normal(&p_widen, &c_widen)) {
+ goto return_sub_zero;
+ }
+ }
+
+ /* Narrow with sticky bit, for proper rounding later. */
+ frac_truncjam(a, &p_widen);
+ a->sign = p_widen.sign;
+ a->exp = p_widen.exp;
+
+ return_normal:
+ if (flags & float_muladd_halve_result) {
+ a->exp -= 1;
+ }
+ finish_sign:
+ if (flags & float_muladd_negate_result) {
+ a->sign ^= 1;
+ }
+ return a;
+
+ return_sub_zero:
+ a->sign = s->float_rounding_mode == float_round_down;
+ return_zero:
+ a->cls = float_class_zero;
+ goto finish_sign;
+
+ return_inf:
+ a->cls = float_class_inf;
+ goto finish_sign;
+
+ d_nan:
+ float_raise(float_flag_invalid, s);
+ parts_default_nan(a, s);
+ return a;
+}
+
+/*
+ * Returns the result of dividing the floating-point value `a' by the
+ * corresponding value `b'. The operation is performed according to
+ * the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+ */
+static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b,
+ float_status *s)
+{
+ int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+ bool sign = a->sign ^ b->sign;
+
+ if (likely(ab_mask == float_cmask_normal)) {
+ a->sign = sign;
+ a->exp -= b->exp + frac_div(a, b);
+ return a;
+ }
+
+ /* 0/0 or Inf/Inf => NaN */
+ if (unlikely(ab_mask == float_cmask_zero) ||
+ unlikely(ab_mask == float_cmask_inf)) {
+ float_raise(float_flag_invalid, s);
+ parts_default_nan(a, s);
+ return a;
+ }
+
+ /* All the NaN cases */
+ if (unlikely(ab_mask & float_cmask_anynan)) {
+ return parts_pick_nan(a, b, s);
+ }
+
+ a->sign = sign;
+
+ /* Inf / X */
+ if (a->cls == float_class_inf) {
+ return a;
+ }
+
+ /* 0 / X */
+ if (a->cls == float_class_zero) {
+ return a;
+ }
+
+ /* X / Inf */
+ if (b->cls == float_class_inf) {
+ a->cls = float_class_zero;
+ return a;
+ }
+
+ /* X / 0 => Inf */
+ g_assert(b->cls == float_class_zero);
+ float_raise(float_flag_divbyzero, s);
+ a->cls = float_class_inf;
+ return a;
+}
+
+/*
+ * Rounds the floating-point value `a' to an integer, and returns the
+ * result as a floating-point value. The operation is performed
+ * according to the IEC/IEEE Standard for Binary Floating-Point
+ * Arithmetic.
+ *
+ * parts_round_to_int_normal is an internal helper function for
+ * normal numbers only, returning true for inexact but not directly
+ * raising float_flag_inexact.
+ */
+static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode,
+ int scale, int frac_size)
+{
+ uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc;
+ int shift_adj;
+
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
+ a->exp += scale;
+
+ if (a->exp < 0) {
+ bool one;
+
+ /* All fractional */
+ switch (rmode) {
+ case float_round_nearest_even:
+ one = false;
+ if (a->exp == -1) {
+ FloatPartsN tmp;
+ /* Shift left one, discarding DECOMPOSED_IMPLICIT_BIT */
+ frac_add(&tmp, a, a);
+ /* Anything remaining means frac > 0.5. */
+ one = !frac_eqz(&tmp);
+ }
+ break;
+ case float_round_ties_away:
+ one = a->exp == -1;
+ break;
+ case float_round_to_zero:
+ one = false;
+ break;
+ case float_round_up:
+ one = !a->sign;
+ break;
+ case float_round_down:
+ one = a->sign;
+ break;
+ case float_round_to_odd:
+ one = true;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ frac_clear(a);
+ a->exp = 0;
+ if (one) {
+ a->frac_hi = DECOMPOSED_IMPLICIT_BIT;
+ } else {
+ a->cls = float_class_zero;
+ }
+ return true;
+ }
+
+ if (a->exp >= frac_size) {
+ /* All integral */
+ return false;
+ }
+
+ if (N > 64 && a->exp < N - 64) {
+ /*
+ * Rounding is not in the low word -- shift lsb to bit 2,
+ * which leaves room for sticky and rounding bit.
+ */
+ shift_adj = (N - 1) - (a->exp + 2);
+ frac_shrjam(a, shift_adj);
+ frac_lsb = 1 << 2;
+ } else {
+ shift_adj = 0;
+ frac_lsb = DECOMPOSED_IMPLICIT_BIT >> (a->exp & 63);
+ }
+
+ frac_lsbm1 = frac_lsb >> 1;
+ rnd_mask = frac_lsb - 1;
+ rnd_even_mask = rnd_mask | frac_lsb;
+
+ if (!(a->frac_lo & rnd_mask)) {
+ /* Fractional bits already clear, undo the shift above. */
+ frac_shl(a, shift_adj);
+ return false;
+ }
+
+ switch (rmode) {
+ case float_round_nearest_even:
+ inc = ((a->frac_lo & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
+ break;
+ case float_round_ties_away:
+ inc = frac_lsbm1;
+ break;
+ case float_round_to_zero:
+ inc = 0;
+ break;
+ case float_round_up:
+ inc = a->sign ? 0 : rnd_mask;
+ break;
+ case float_round_down:
+ inc = a->sign ? rnd_mask : 0;
+ break;
+ case float_round_to_odd:
+ inc = a->frac_lo & frac_lsb ? 0 : rnd_mask;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (shift_adj == 0) {
+ if (frac_addi(a, a, inc)) {
+ frac_shr(a, 1);
+ a->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
+ a->exp++;
+ }
+ a->frac_lo &= ~rnd_mask;
+ } else {
+ frac_addi(a, a, inc);
+ a->frac_lo &= ~rnd_mask;
+ /* Be careful shifting back, not to overflow */
+ frac_shl(a, shift_adj - 1);
+ if (a->frac_hi & DECOMPOSED_IMPLICIT_BIT) {
+ a->exp++;
+ } else {
+ frac_add(a, a, a);
+ }
+ }
+ return true;
+}
+
+static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode,
+ int scale, float_status *s,
+ const FloatFmt *fmt)
+{
+ switch (a->cls) {
+ case float_class_qnan:
+ case float_class_snan:
+ parts_return_nan(a, s);
+ break;
+ case float_class_zero:
+ case float_class_inf:
+ break;
+ case float_class_normal:
+ if (parts_round_to_int_normal(a, rmode, scale, fmt->frac_size)) {
+ float_raise(float_flag_inexact, s);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+/*
+ * Returns the result of converting the floating-point value `a' to
+ * the two's complement integer format. The conversion is performed
+ * according to the IEC/IEEE Standard for Binary Floating-Point
+ * Arithmetic---which means in particular that the conversion is
+ * rounded according to the current rounding mode. If `a' is a NaN,
+ * the largest positive integer is returned. Otherwise, if the
+ * conversion overflows, the largest integer with the same sign as `a'
+ * is returned.
+*/
+static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode,
+ int scale, int64_t min, int64_t max,
+ float_status *s)
+{
+ int flags = 0;
+ uint64_t r;
+
+ switch (p->cls) {
+ case float_class_snan:
+ case float_class_qnan:
+ flags = float_flag_invalid;
+ r = max;
+ break;
+
+ case float_class_inf:
+ flags = float_flag_invalid;
+ r = p->sign ? min : max;
+ break;
+
+ case float_class_zero:
+ return 0;
+
+ case float_class_normal:
+ /* TODO: N - 2 is frac_size for rounding; could use input fmt. */
+ if (parts_round_to_int_normal(p, rmode, scale, N - 2)) {
+ flags = float_flag_inexact;
+ }
+
+ if (p->exp <= DECOMPOSED_BINARY_POINT) {
+ r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp);
+ } else {
+ r = UINT64_MAX;
+ }
+ if (p->sign) {
+ if (r <= -(uint64_t)min) {
+ r = -r;
+ } else {
+ flags = float_flag_invalid;
+ r = min;
+ }
+ } else if (r > max) {
+ flags = float_flag_invalid;
+ r = max;
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+
+ float_raise(flags, s);
+ return r;
+}
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
index 9ea318f3e2..c895733e79 100644
--- a/fpu/softfloat-specialize.c.inc
+++ b/fpu/softfloat-specialize.c.inc
@@ -103,7 +103,7 @@ static inline bool snan_bit_is_one(float_status *status)
{
#if defined(TARGET_MIPS)
return status->snan_bit_is_one;
-#elif defined(TARGET_HPPA) || defined(TARGET_UNICORE32) || defined(TARGET_SH4)
+#elif defined(TARGET_HPPA) || defined(TARGET_SH4)
return 1;
#else
return 0;
@@ -129,7 +129,7 @@ static bool parts_is_snan_frac(uint64_t frac, float_status *status)
| The pattern for a default generated deconstructed floating-point NaN.
*----------------------------------------------------------------------------*/
-static FloatParts parts_default_nan(float_status *status)
+static void parts64_default_nan(FloatParts64 *p, float_status *status)
{
bool sign = 0;
uint64_t frac;
@@ -149,11 +149,10 @@ static FloatParts parts_default_nan(float_status *status)
sign = 1;
frac = ~0ULL;
#else
- /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
- * S390, SH4, TriCore, and Xtensa. I cannot find documentation
- * for Unicore32; the choice from the original commit is unchanged.
- * Our other supported targets, CRIS, LM32, Moxie, Nios2, and Tile,
- * do not have floating-point.
+ /*
+ * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
+ * S390, SH4, TriCore, and Xtensa. Our other supported targets,
+ * CRIS, Nios2, and Tile, do not have floating-point.
*/
if (snan_bit_is_one(status)) {
/* set all bits other than msb */
@@ -164,7 +163,7 @@ static FloatParts parts_default_nan(float_status *status)
}
#endif
- return (FloatParts) {
+ *p = (FloatParts64) {
.cls = float_class_qnan,
.sign = sign,
.exp = INT_MAX,
@@ -172,26 +171,55 @@ static FloatParts parts_default_nan(float_status *status)
};
}
+static void parts128_default_nan(FloatParts128 *p, float_status *status)
+{
+ /*
+ * Extrapolate from the choices made by parts64_default_nan to fill
+ * in the quad-floating format. If the low bit is set, assume we
+ * want to set all non-snan bits.
+ */
+ FloatParts64 p64;
+ parts64_default_nan(&p64, status);
+
+ *p = (FloatParts128) {
+ .cls = float_class_qnan,
+ .sign = p64.sign,
+ .exp = INT_MAX,
+ .frac_hi = p64.frac,
+ .frac_lo = -(p64.frac & 1)
+ };
+}
+
/*----------------------------------------------------------------------------
| Returns a quiet NaN from a signalling NaN for the deconstructed
| floating-point parts.
*----------------------------------------------------------------------------*/
-static FloatParts parts_silence_nan(FloatParts a, float_status *status)
+static uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status)
{
g_assert(!no_signaling_nans(status));
-#if defined(TARGET_HPPA)
- a.frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1));
- a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2);
-#else
+ g_assert(!status->default_nan_mode);
+
+ /* The only snan_bit_is_one target without default_nan_mode is HPPA. */
if (snan_bit_is_one(status)) {
- return parts_default_nan(status);
+ frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1));
+ frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2);
} else {
- a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1);
+ frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1);
}
-#endif
- a.cls = float_class_qnan;
- return a;
+ return frac;
+}
+
+static void parts64_silence_nan(FloatParts64 *p, float_status *status)
+{
+ p->frac = parts_silence_nan_frac(p->frac, status);
+ p->cls = float_class_qnan;
+}
+
+static void parts128_silence_nan(FloatParts128 *p, float_status *status)
+{
+ p->frac_hi = parts_silence_nan_frac(p->frac_hi, status);
+ p->cls = float_class_qnan;
}
/*----------------------------------------------------------------------------
@@ -229,18 +257,6 @@ const floatx80 floatx80_infinity
= make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
/*----------------------------------------------------------------------------
-| Raises the exceptions specified by `flags'. Floating-point traps can be
-| defined here if desired. It is currently not possible for such a trap
-| to substitute a result value. If traps are not implemented, this routine
-| should be simply `float_exception_flags |= flags;'.
-*----------------------------------------------------------------------------*/
-
-void float_raise(uint8_t flags, float_status *status)
-{
- status->float_exception_flags |= flags;
-}
-
-/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
@@ -627,6 +643,12 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
} else {
return 1;
}
+#elif defined(TARGET_RISCV)
+ /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
+ if (infzero) {
+ float_raise(float_flag_invalid, status);
+ }
+ return 3; /* default NaN */
#elif defined(TARGET_XTENSA)
/*
* For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns
@@ -1066,25 +1088,6 @@ bool float128_is_signaling_nan(float128 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Returns a quiet NaN from a signalling NaN for the quadruple-precision
-| floating point value `a'.
-*----------------------------------------------------------------------------*/
-
-float128 float128_silence_nan(float128 a, float_status *status)
-{
- if (no_signaling_nans(status)) {
- g_assert_not_reached();
- } else {
- if (snan_bit_is_one(status)) {
- return float128_default_nan(status);
- } else {
- a.high |= UINT64_C(0x0000800000000000);
- return a;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 67cfa0fd82..0dc2203477 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -132,7 +132,7 @@ this code that are retained.
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; \
+ float_raise(float_flag_input_denormal, s); \
} \
}
@@ -360,7 +360,7 @@ float32_gen2(float32 xa, float32 xb, float_status *s,
ur.h = hard(ua.h, ub.h);
if (unlikely(f32_is_inf(ur))) {
- s->float_exception_flags |= float_flag_overflow;
+ float_raise(float_flag_overflow, s);
} else if (unlikely(fabsf(ur.h) <= FLT_MIN) && post(ua, ub)) {
goto soft;
}
@@ -391,7 +391,7 @@ float64_gen2(float64 xa, float64 xb, float_status *s,
ur.h = hard(ua.h, ub.h);
if (unlikely(f64_is_inf(ur))) {
- s->float_exception_flags |= float_flag_overflow;
+ float_raise(float_flag_overflow, s);
} else if (unlikely(fabs(ur.h) <= DBL_MIN) && post(ua, ub)) {
goto soft;
}
@@ -469,6 +469,20 @@ typedef enum __attribute__ ((__packed__)) {
float_class_snan,
} FloatClass;
+#define float_cmask(bit) (1u << (bit))
+
+enum {
+ float_cmask_zero = float_cmask(float_class_zero),
+ float_cmask_normal = float_cmask(float_class_normal),
+ float_cmask_inf = float_cmask(float_class_inf),
+ float_cmask_qnan = float_cmask(float_class_qnan),
+ float_cmask_snan = float_cmask(float_class_snan),
+
+ float_cmask_infzero = float_cmask_zero | float_cmask_inf,
+ float_cmask_anynan = float_cmask_qnan | float_cmask_snan,
+};
+
+
/* Simple helpers for checking if, or what kind of, NaN we have */
static inline __attribute__((unused)) bool is_nan(FloatClass c)
{
@@ -486,26 +500,52 @@ static inline __attribute__((unused)) bool is_qnan(FloatClass c)
}
/*
- * Structure holding all of the decomposed parts of a float. The
- * exponent is unbiased and the fraction is normalized. All
- * calculations are done with a 64 bit fraction and then rounded as
- * appropriate for the final format.
+ * Structure holding all of the decomposed parts of a float.
+ * The exponent is unbiased and the fraction is normalized.
*
- * Thanks to the packed FloatClass a decent compiler should be able to
- * fit the whole structure into registers and avoid using the stack
- * for parameter passing.
+ * The fraction words are stored in big-endian word ordering,
+ * so that truncation from a larger format to a smaller format
+ * can be done simply by ignoring subsequent elements.
*/
typedef struct {
- uint64_t frac;
- int32_t exp;
FloatClass cls;
bool sign;
-} FloatParts;
+ int32_t exp;
+ union {
+ /* Routines that know the structure may reference the singular name. */
+ uint64_t frac;
+ /*
+ * Routines expanded with multiple structures reference "hi" and "lo"
+ * depending on the operation. In FloatParts64, "hi" and "lo" are
+ * both the same word and aliased here.
+ */
+ uint64_t frac_hi;
+ uint64_t frac_lo;
+ };
+} FloatParts64;
-#define DECOMPOSED_BINARY_POINT (64 - 2)
+typedef struct {
+ FloatClass cls;
+ bool sign;
+ int32_t exp;
+ uint64_t frac_hi;
+ uint64_t frac_lo;
+} FloatParts128;
+
+typedef struct {
+ FloatClass cls;
+ bool sign;
+ int32_t exp;
+ uint64_t frac_hi;
+ uint64_t frac_hm; /* high-middle */
+ uint64_t frac_lm; /* low-middle */
+ uint64_t frac_lo;
+} FloatParts256;
+
+/* These apply to the most significant word of each FloatPartsN. */
+#define DECOMPOSED_BINARY_POINT 63
#define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT)
-#define DECOMPOSED_OVERFLOW_BIT (DECOMPOSED_IMPLICIT_BIT << 1)
/* Structure holding all of the relevant parameters for a format.
* exp_size: the size of the exponent field
@@ -539,11 +579,11 @@ typedef struct {
.exp_bias = ((1 << E) - 1) >> 1, \
.exp_max = (1 << E) - 1, \
.frac_size = F, \
- .frac_shift = DECOMPOSED_BINARY_POINT - F, \
- .frac_lsb = 1ull << (DECOMPOSED_BINARY_POINT - F), \
- .frac_lsbm1 = 1ull << ((DECOMPOSED_BINARY_POINT - F) - 1), \
- .round_mask = (1ull << (DECOMPOSED_BINARY_POINT - F)) - 1, \
- .roundeven_mask = (2ull << (DECOMPOSED_BINARY_POINT - F)) - 1
+ .frac_shift = (-F - 1) & 63, \
+ .frac_lsb = 1ull << ((-F - 1) & 63), \
+ .frac_lsbm1 = 1ull << ((-F - 2) & 63), \
+ .round_mask = (1ull << ((-F - 1) & 63)) - 1, \
+ .roundeven_mask = (2ull << ((-F - 1) & 63)) - 1
static const FloatFmt float16_params = {
FLOAT_PARAMS(5, 10)
@@ -566,65 +606,101 @@ static const FloatFmt float64_params = {
FLOAT_PARAMS(11, 52)
};
+static const FloatFmt float128_params = {
+ FLOAT_PARAMS(15, 112)
+};
+
/* Unpack a float to parts, but do not canonicalize. */
-static inline FloatParts unpack_raw(FloatFmt fmt, uint64_t raw)
+static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw)
{
- const int sign_pos = fmt.frac_size + fmt.exp_size;
+ const int f_size = fmt->frac_size;
+ const int e_size = fmt->exp_size;
- return (FloatParts) {
+ *r = (FloatParts64) {
.cls = float_class_unclassified,
- .sign = extract64(raw, sign_pos, 1),
- .exp = extract64(raw, fmt.frac_size, fmt.exp_size),
- .frac = extract64(raw, 0, fmt.frac_size),
+ .sign = extract64(raw, f_size + e_size, 1),
+ .exp = extract64(raw, f_size, e_size),
+ .frac = extract64(raw, 0, f_size)
};
}
-static inline FloatParts float16_unpack_raw(float16 f)
+static inline void float16_unpack_raw(FloatParts64 *p, float16 f)
{
- return unpack_raw(float16_params, f);
+ unpack_raw64(p, &float16_params, f);
}
-static inline FloatParts bfloat16_unpack_raw(bfloat16 f)
+static inline void bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f)
{
- return unpack_raw(bfloat16_params, f);
+ unpack_raw64(p, &bfloat16_params, f);
}
-static inline FloatParts float32_unpack_raw(float32 f)
+static inline void float32_unpack_raw(FloatParts64 *p, float32 f)
{
- return unpack_raw(float32_params, f);
+ unpack_raw64(p, &float32_params, f);
}
-static inline FloatParts float64_unpack_raw(float64 f)
+static inline void float64_unpack_raw(FloatParts64 *p, float64 f)
{
- return unpack_raw(float64_params, f);
+ unpack_raw64(p, &float64_params, f);
+}
+
+static void float128_unpack_raw(FloatParts128 *p, float128 f)
+{
+ const int f_size = float128_params.frac_size - 64;
+ const int e_size = float128_params.exp_size;
+
+ *p = (FloatParts128) {
+ .cls = float_class_unclassified,
+ .sign = extract64(f.high, f_size + e_size, 1),
+ .exp = extract64(f.high, f_size, e_size),
+ .frac_hi = extract64(f.high, 0, f_size),
+ .frac_lo = f.low,
+ };
}
/* Pack a float from parts, but do not canonicalize. */
-static inline uint64_t pack_raw(FloatFmt fmt, FloatParts p)
+static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt)
+{
+ const int f_size = fmt->frac_size;
+ const int e_size = fmt->exp_size;
+ uint64_t ret;
+
+ ret = (uint64_t)p->sign << (f_size + e_size);
+ ret = deposit64(ret, f_size, e_size, p->exp);
+ ret = deposit64(ret, 0, f_size, p->frac);
+ return ret;
+}
+
+static inline float16 float16_pack_raw(const FloatParts64 *p)
{
- const int sign_pos = fmt.frac_size + fmt.exp_size;
- uint64_t ret = deposit64(p.frac, fmt.frac_size, fmt.exp_size, p.exp);
- return deposit64(ret, sign_pos, 1, p.sign);
+ return make_float16(pack_raw64(p, &float16_params));
}
-static inline float16 float16_pack_raw(FloatParts p)
+static inline bfloat16 bfloat16_pack_raw(const FloatParts64 *p)
{
- return make_float16(pack_raw(float16_params, p));
+ return pack_raw64(p, &bfloat16_params);
}
-static inline bfloat16 bfloat16_pack_raw(FloatParts p)
+static inline float32 float32_pack_raw(const FloatParts64 *p)
{
- return pack_raw(bfloat16_params, p);
+ return make_float32(pack_raw64(p, &float32_params));
}
-static inline float32 float32_pack_raw(FloatParts p)
+static inline float64 float64_pack_raw(const FloatParts64 *p)
{
- return make_float32(pack_raw(float32_params, p));
+ return make_float64(pack_raw64(p, &float64_params));
}
-static inline float64 float64_pack_raw(FloatParts p)
+static float128 float128_pack_raw(const FloatParts128 *p)
{
- return make_float64(pack_raw(float64_params, p));
+ const int f_size = float128_params.frac_size - 64;
+ const int e_size = float128_params.exp_size;
+ uint64_t hi;
+
+ hi = (uint64_t)p->sign << (f_size + e_size);
+ hi = deposit64(hi, f_size, e_size, p->exp);
+ hi = deposit64(hi, 0, f_size, p->frac_hi);
+ return make_float128(hi, p->frac_lo);
}
/*----------------------------------------------------------------------------
@@ -637,474 +713,807 @@ static inline float64 float64_pack_raw(FloatParts p)
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.c.inc"
-/* Canonicalize EXP and FRAC, setting CLS. */
-static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
- float_status *status)
+#define PARTS_GENERIC_64_128(NAME, P) \
+ QEMU_GENERIC(P, (FloatParts128 *, parts128_##NAME), parts64_##NAME)
+
+#define PARTS_GENERIC_64_128_256(NAME, P) \
+ QEMU_GENERIC(P, (FloatParts256 *, parts256_##NAME), \
+ (FloatParts128 *, parts128_##NAME), parts64_##NAME)
+
+#define parts_default_nan(P, S) PARTS_GENERIC_64_128(default_nan, P)(P, S)
+#define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S)
+
+static void parts64_return_nan(FloatParts64 *a, float_status *s);
+static void parts128_return_nan(FloatParts128 *a, float_status *s);
+
+#define parts_return_nan(P, S) PARTS_GENERIC_64_128(return_nan, P)(P, S)
+
+static FloatParts64 *parts64_pick_nan(FloatParts64 *a, FloatParts64 *b,
+ float_status *s);
+static FloatParts128 *parts128_pick_nan(FloatParts128 *a, FloatParts128 *b,
+ float_status *s);
+
+#define parts_pick_nan(A, B, S) PARTS_GENERIC_64_128(pick_nan, A)(A, B, S)
+
+static FloatParts64 *parts64_pick_nan_muladd(FloatParts64 *a, FloatParts64 *b,
+ FloatParts64 *c, float_status *s,
+ int ab_mask, int abc_mask);
+static FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a,
+ FloatParts128 *b,
+ FloatParts128 *c,
+ float_status *s,
+ int ab_mask, int abc_mask);
+
+#define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \
+ PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM)
+
+static void parts64_canonicalize(FloatParts64 *p, float_status *status,
+ const FloatFmt *fmt);
+static void parts128_canonicalize(FloatParts128 *p, float_status *status,
+ const FloatFmt *fmt);
+
+#define parts_canonicalize(A, S, F) \
+ PARTS_GENERIC_64_128(canonicalize, A)(A, S, F)
+
+static void parts64_uncanon(FloatParts64 *p, float_status *status,
+ const FloatFmt *fmt);
+static void parts128_uncanon(FloatParts128 *p, float_status *status,
+ const FloatFmt *fmt);
+
+#define parts_uncanon(A, S, F) \
+ PARTS_GENERIC_64_128(uncanon, A)(A, S, F)
+
+static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b);
+static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b);
+static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b);
+
+#define parts_add_normal(A, B) \
+ PARTS_GENERIC_64_128_256(add_normal, A)(A, B)
+
+static bool parts64_sub_normal(FloatParts64 *a, FloatParts64 *b);
+static bool parts128_sub_normal(FloatParts128 *a, FloatParts128 *b);
+static bool parts256_sub_normal(FloatParts256 *a, FloatParts256 *b);
+
+#define parts_sub_normal(A, B) \
+ PARTS_GENERIC_64_128_256(sub_normal, A)(A, B)
+
+static FloatParts64 *parts64_addsub(FloatParts64 *a, FloatParts64 *b,
+ float_status *s, bool subtract);
+static FloatParts128 *parts128_addsub(FloatParts128 *a, FloatParts128 *b,
+ float_status *s, bool subtract);
+
+#define parts_addsub(A, B, S, Z) \
+ PARTS_GENERIC_64_128(addsub, A)(A, B, S, Z)
+
+static FloatParts64 *parts64_mul(FloatParts64 *a, FloatParts64 *b,
+ float_status *s);
+static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b,
+ float_status *s);
+
+#define parts_mul(A, B, S) \
+ PARTS_GENERIC_64_128(mul, A)(A, B, S)
+
+static FloatParts64 *parts64_muladd(FloatParts64 *a, FloatParts64 *b,
+ FloatParts64 *c, int flags,
+ float_status *s);
+static FloatParts128 *parts128_muladd(FloatParts128 *a, FloatParts128 *b,
+ FloatParts128 *c, int flags,
+ float_status *s);
+
+#define parts_muladd(A, B, C, Z, S) \
+ PARTS_GENERIC_64_128(muladd, A)(A, B, C, Z, S)
+
+static FloatParts64 *parts64_div(FloatParts64 *a, FloatParts64 *b,
+ float_status *s);
+static FloatParts128 *parts128_div(FloatParts128 *a, FloatParts128 *b,
+ float_status *s);
+
+#define parts_div(A, B, S) \
+ PARTS_GENERIC_64_128(div, A)(A, B, S)
+
+static bool parts64_round_to_int_normal(FloatParts64 *a, FloatRoundMode rm,
+ int scale, int frac_size);
+static bool parts128_round_to_int_normal(FloatParts128 *a, FloatRoundMode r,
+ int scale, int frac_size);
+
+#define parts_round_to_int_normal(A, R, C, F) \
+ PARTS_GENERIC_64_128(round_to_int_normal, A)(A, R, C, F)
+
+static void parts64_round_to_int(FloatParts64 *a, FloatRoundMode rm,
+ int scale, float_status *s,
+ const FloatFmt *fmt);
+static void parts128_round_to_int(FloatParts128 *a, FloatRoundMode r,
+ int scale, float_status *s,
+ const FloatFmt *fmt);
+
+#define parts_round_to_int(A, R, C, S, F) \
+ PARTS_GENERIC_64_128(round_to_int, A)(A, R, C, S, F)
+
+static int64_t parts64_float_to_sint(FloatParts64 *p, FloatRoundMode rmode,
+ int scale, int64_t min, int64_t max,
+ float_status *s);
+static int64_t parts128_float_to_sint(FloatParts128 *p, FloatRoundMode rmode,
+ int scale, int64_t min, int64_t max,
+ float_status *s);
+
+#define parts_float_to_sint(P, R, Z, MN, MX, S) \
+ PARTS_GENERIC_64_128(float_to_sint, P)(P, R, Z, MN, MX, S)
+
+/*
+ * Helper functions for softfloat-parts.c.inc, per-size operations.
+ */
+
+#define FRAC_GENERIC_64_128(NAME, P) \
+ QEMU_GENERIC(P, (FloatParts128 *, frac128_##NAME), frac64_##NAME)
+
+#define FRAC_GENERIC_64_128_256(NAME, P) \
+ QEMU_GENERIC(P, (FloatParts256 *, frac256_##NAME), \
+ (FloatParts128 *, frac128_##NAME), frac64_##NAME)
+
+static bool frac64_add(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b)
{
- if (part.exp == parm->exp_max && !parm->arm_althp) {
- if (part.frac == 0) {
- part.cls = float_class_inf;
- } else {
- part.frac <<= parm->frac_shift;
- part.cls = (parts_is_snan_frac(part.frac, status)
- ? float_class_snan : float_class_qnan);
- }
- } else if (part.exp == 0) {
- if (likely(part.frac == 0)) {
- part.cls = float_class_zero;
- } else if (status->flush_inputs_to_zero) {
- float_raise(float_flag_input_denormal, status);
- part.cls = float_class_zero;
- part.frac = 0;
- } else {
- int shift = clz64(part.frac) - 1;
- part.cls = float_class_normal;
- part.exp = parm->frac_shift - parm->exp_bias - shift + 1;
- part.frac <<= shift;
- }
- } else {
- part.cls = float_class_normal;
- part.exp -= parm->exp_bias;
- part.frac = DECOMPOSED_IMPLICIT_BIT + (part.frac << parm->frac_shift);
- }
- return part;
+ return uadd64_overflow(a->frac, b->frac, &r->frac);
}
-/* Round and uncanonicalize a floating-point number by parts. There
- * are FRAC_SHIFT bits that may require rounding at the bottom of the
- * fraction; these bits will be removed. The exponent will be biased
- * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0].
- */
+static bool frac128_add(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b)
+{
+ bool c = 0;
+ r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c);
+ r->frac_hi = uadd64_carry(a->frac_hi, b->frac_hi, &c);
+ return c;
+}
-static FloatParts round_canonical(FloatParts p, float_status *s,
- const FloatFmt *parm)
+static bool frac256_add(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b)
{
- const uint64_t frac_lsb = parm->frac_lsb;
- const uint64_t frac_lsbm1 = parm->frac_lsbm1;
- const uint64_t round_mask = parm->round_mask;
- const uint64_t roundeven_mask = parm->roundeven_mask;
- const int exp_max = parm->exp_max;
- const int frac_shift = parm->frac_shift;
- uint64_t frac, inc;
- int exp, flags = 0;
- bool overflow_norm;
+ bool c = 0;
+ r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c);
+ r->frac_lm = uadd64_carry(a->frac_lm, b->frac_lm, &c);
+ r->frac_hm = uadd64_carry(a->frac_hm, b->frac_hm, &c);
+ r->frac_hi = uadd64_carry(a->frac_hi, b->frac_hi, &c);
+ return c;
+}
- frac = p.frac;
- exp = p.exp;
+#define frac_add(R, A, B) FRAC_GENERIC_64_128_256(add, R)(R, A, B)
- switch (p.cls) {
- case float_class_normal:
- switch (s->float_rounding_mode) {
- case float_round_nearest_even:
- overflow_norm = false;
- inc = ((frac & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
- break;
- case float_round_ties_away:
- overflow_norm = false;
- inc = frac_lsbm1;
- break;
- case float_round_to_zero:
- overflow_norm = true;
- inc = 0;
- break;
- case float_round_up:
- inc = p.sign ? 0 : round_mask;
- overflow_norm = p.sign;
- break;
- case float_round_down:
- inc = p.sign ? round_mask : 0;
- overflow_norm = !p.sign;
- break;
- case float_round_to_odd:
- overflow_norm = true;
- inc = frac & frac_lsb ? 0 : round_mask;
- break;
- default:
- g_assert_not_reached();
- }
+static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c)
+{
+ return uadd64_overflow(a->frac, c, &r->frac);
+}
- exp += parm->exp_bias;
- if (likely(exp > 0)) {
- if (frac & round_mask) {
- flags |= float_flag_inexact;
- frac += inc;
- if (frac & DECOMPOSED_OVERFLOW_BIT) {
- frac >>= 1;
- exp++;
- }
- }
- frac >>= frac_shift;
-
- if (parm->arm_althp) {
- /* ARM Alt HP eschews Inf and NaN for a wider exponent. */
- if (unlikely(exp > exp_max)) {
- /* Overflow. Return the maximum normal. */
- flags = float_flag_invalid;
- exp = exp_max;
- frac = -1;
- }
- } else if (unlikely(exp >= exp_max)) {
- flags |= float_flag_overflow | float_flag_inexact;
- if (overflow_norm) {
- exp = exp_max - 1;
- frac = -1;
- } else {
- p.cls = float_class_inf;
- goto do_inf;
- }
- }
- } else if (s->flush_to_zero) {
- flags |= float_flag_output_denormal;
- p.cls = float_class_zero;
- goto do_zero;
- } else {
- bool is_tiny = s->tininess_before_rounding
- || (exp < 0)
- || !((frac + inc) & DECOMPOSED_OVERFLOW_BIT);
-
- shift64RightJamming(frac, 1 - exp, &frac);
- if (frac & round_mask) {
- /* Need to recompute round-to-even. */
- switch (s->float_rounding_mode) {
- case float_round_nearest_even:
- inc = ((frac & roundeven_mask) != frac_lsbm1
- ? frac_lsbm1 : 0);
- break;
- case float_round_to_odd:
- inc = frac & frac_lsb ? 0 : round_mask;
- break;
- default:
- break;
- }
- flags |= float_flag_inexact;
- frac += inc;
- }
+static bool frac128_addi(FloatParts128 *r, FloatParts128 *a, uint64_t c)
+{
+ c = uadd64_overflow(a->frac_lo, c, &r->frac_lo);
+ return uadd64_overflow(a->frac_hi, c, &r->frac_hi);
+}
- exp = (frac & DECOMPOSED_IMPLICIT_BIT ? 1 : 0);
- frac >>= frac_shift;
+#define frac_addi(R, A, C) FRAC_GENERIC_64_128(addi, R)(R, A, C)
- if (is_tiny && (flags & float_flag_inexact)) {
- flags |= float_flag_underflow;
- }
- if (exp == 0 && frac == 0) {
- p.cls = float_class_zero;
- }
- }
- break;
+static void frac64_allones(FloatParts64 *a)
+{
+ a->frac = -1;
+}
- case float_class_zero:
- do_zero:
- exp = 0;
- frac = 0;
- break;
+static void frac128_allones(FloatParts128 *a)
+{
+ a->frac_hi = a->frac_lo = -1;
+}
- case float_class_inf:
- do_inf:
- assert(!parm->arm_althp);
- exp = exp_max;
- frac = 0;
- break;
+#define frac_allones(A) FRAC_GENERIC_64_128(allones, A)(A)
- case float_class_qnan:
- case float_class_snan:
- assert(!parm->arm_althp);
- exp = exp_max;
- frac >>= parm->frac_shift;
- break;
+static int frac64_cmp(FloatParts64 *a, FloatParts64 *b)
+{
+ return a->frac == b->frac ? 0 : a->frac < b->frac ? -1 : 1;
+}
- default:
- g_assert_not_reached();
+static int frac128_cmp(FloatParts128 *a, FloatParts128 *b)
+{
+ uint64_t ta = a->frac_hi, tb = b->frac_hi;
+ if (ta == tb) {
+ ta = a->frac_lo, tb = b->frac_lo;
+ if (ta == tb) {
+ return 0;
+ }
}
-
- float_raise(flags, s);
- p.exp = exp;
- p.frac = frac;
- return p;
+ return ta < tb ? -1 : 1;
}
-/* Explicit FloatFmt version */
-static FloatParts float16a_unpack_canonical(float16 f, float_status *s,
- const FloatFmt *params)
+#define frac_cmp(A, B) FRAC_GENERIC_64_128(cmp, A)(A, B)
+
+static void frac64_clear(FloatParts64 *a)
{
- return sf_canonicalize(float16_unpack_raw(f), params, s);
+ a->frac = 0;
}
-static FloatParts float16_unpack_canonical(float16 f, float_status *s)
+static void frac128_clear(FloatParts128 *a)
{
- return float16a_unpack_canonical(f, s, &float16_params);
+ a->frac_hi = a->frac_lo = 0;
}
-static FloatParts bfloat16_unpack_canonical(bfloat16 f, float_status *s)
+#define frac_clear(A) FRAC_GENERIC_64_128(clear, A)(A)
+
+static bool frac64_div(FloatParts64 *a, FloatParts64 *b)
{
- return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s);
+ uint64_t n1, n0, r, q;
+ bool ret;
+
+ /*
+ * We want a 2*N / N-bit division to produce exactly an N-bit
+ * result, so that we do not lose any precision and so that we
+ * do not have to renormalize afterward. If A.frac < B.frac,
+ * then division would produce an (N-1)-bit result; shift A left
+ * by one to produce the an N-bit result, and return true to
+ * decrement the exponent to match.
+ *
+ * The udiv_qrnnd algorithm that we're using requires normalization,
+ * i.e. the msb of the denominator must be set, which is already true.
+ */
+ ret = a->frac < b->frac;
+ if (ret) {
+ n0 = a->frac;
+ n1 = 0;
+ } else {
+ n0 = a->frac >> 1;
+ n1 = a->frac << 63;
+ }
+ q = udiv_qrnnd(&r, n0, n1, b->frac);
+
+ /* Set lsb if there is a remainder, to set inexact. */
+ a->frac = q | (r != 0);
+
+ return ret;
}
-static float16 float16a_round_pack_canonical(FloatParts p, float_status *s,
- const FloatFmt *params)
+static bool frac128_div(FloatParts128 *a, FloatParts128 *b)
{
- return float16_pack_raw(round_canonical(p, s, params));
+ uint64_t q0, q1, a0, a1, b0, b1;
+ uint64_t r0, r1, r2, r3, t0, t1, t2, t3;
+ bool ret = false;
+
+ a0 = a->frac_hi, a1 = a->frac_lo;
+ b0 = b->frac_hi, b1 = b->frac_lo;
+
+ ret = lt128(a0, a1, b0, b1);
+ if (!ret) {
+ a1 = shr_double(a0, a1, 1);
+ a0 = a0 >> 1;
+ }
+
+ /* Use 128/64 -> 64 division as estimate for 192/128 -> 128 division. */
+ q0 = estimateDiv128To64(a0, a1, b0);
+
+ /*
+ * Estimate is high because B1 was not included (unless B1 == 0).
+ * Reduce quotient and increase remainder until remainder is non-negative.
+ * This loop will execute 0 to 2 times.
+ */
+ mul128By64To192(b0, b1, q0, &t0, &t1, &t2);
+ sub192(a0, a1, 0, t0, t1, t2, &r0, &r1, &r2);
+ while (r0 != 0) {
+ q0--;
+ add192(r0, r1, r2, 0, b0, b1, &r0, &r1, &r2);
+ }
+
+ /* Repeat using the remainder, producing a second word of quotient. */
+ q1 = estimateDiv128To64(r1, r2, b0);
+ mul128By64To192(b0, b1, q1, &t1, &t2, &t3);
+ sub192(r1, r2, 0, t1, t2, t3, &r1, &r2, &r3);
+ while (r1 != 0) {
+ q1--;
+ add192(r1, r2, r3, 0, b0, b1, &r1, &r2, &r3);
+ }
+
+ /* Any remainder indicates inexact; set sticky bit. */
+ q1 |= (r2 | r3) != 0;
+
+ a->frac_hi = q0;
+ a->frac_lo = q1;
+ return ret;
}
-static float16 float16_round_pack_canonical(FloatParts p, float_status *s)
+#define frac_div(A, B) FRAC_GENERIC_64_128(div, A)(A, B)
+
+static bool frac64_eqz(FloatParts64 *a)
{
- return float16a_round_pack_canonical(p, s, &float16_params);
+ return a->frac == 0;
}
-static bfloat16 bfloat16_round_pack_canonical(FloatParts p, float_status *s)
+static bool frac128_eqz(FloatParts128 *a)
{
- return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params));
+ return (a->frac_hi | a->frac_lo) == 0;
}
-static FloatParts float32_unpack_canonical(float32 f, float_status *s)
+#define frac_eqz(A) FRAC_GENERIC_64_128(eqz, A)(A)
+
+static void frac64_mulw(FloatParts128 *r, FloatParts64 *a, FloatParts64 *b)
{
- return sf_canonicalize(float32_unpack_raw(f), &float32_params, s);
+ mulu64(&r->frac_lo, &r->frac_hi, a->frac, b->frac);
}
-static float32 float32_round_pack_canonical(FloatParts p, float_status *s)
+static void frac128_mulw(FloatParts256 *r, FloatParts128 *a, FloatParts128 *b)
{
- return float32_pack_raw(round_canonical(p, s, &float32_params));
+ mul128To256(a->frac_hi, a->frac_lo, b->frac_hi, b->frac_lo,
+ &r->frac_hi, &r->frac_hm, &r->frac_lm, &r->frac_lo);
}
-static FloatParts float64_unpack_canonical(float64 f, float_status *s)
+#define frac_mulw(R, A, B) FRAC_GENERIC_64_128(mulw, A)(R, A, B)
+
+static void frac64_neg(FloatParts64 *a)
{
- return sf_canonicalize(float64_unpack_raw(f), &float64_params, s);
+ a->frac = -a->frac;
}
-static float64 float64_round_pack_canonical(FloatParts p, float_status *s)
+static void frac128_neg(FloatParts128 *a)
{
- return float64_pack_raw(round_canonical(p, s, &float64_params));
+ bool c = 0;
+ a->frac_lo = usub64_borrow(0, a->frac_lo, &c);
+ a->frac_hi = usub64_borrow(0, a->frac_hi, &c);
}
-static FloatParts return_nan(FloatParts a, float_status *s)
+static void frac256_neg(FloatParts256 *a)
{
- switch (a.cls) {
- case float_class_snan:
- s->float_exception_flags |= float_flag_invalid;
- a = parts_silence_nan(a, s);
- /* fall through */
- case float_class_qnan:
- if (s->default_nan_mode) {
- return parts_default_nan(s);
- }
- break;
+ bool c = 0;
+ a->frac_lo = usub64_borrow(0, a->frac_lo, &c);
+ a->frac_lm = usub64_borrow(0, a->frac_lm, &c);
+ a->frac_hm = usub64_borrow(0, a->frac_hm, &c);
+ a->frac_hi = usub64_borrow(0, a->frac_hi, &c);
+}
- default:
- g_assert_not_reached();
+#define frac_neg(A) FRAC_GENERIC_64_128_256(neg, A)(A)
+
+static int frac64_normalize(FloatParts64 *a)
+{
+ if (a->frac) {
+ int shift = clz64(a->frac);
+ a->frac <<= shift;
+ return shift;
}
- return a;
+ return 64;
}
-static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s)
+static int frac128_normalize(FloatParts128 *a)
{
- if (is_snan(a.cls) || is_snan(b.cls)) {
- s->float_exception_flags |= float_flag_invalid;
+ if (a->frac_hi) {
+ int shl = clz64(a->frac_hi);
+ a->frac_hi = shl_double(a->frac_hi, a->frac_lo, shl);
+ a->frac_lo <<= shl;
+ return shl;
+ } else if (a->frac_lo) {
+ int shl = clz64(a->frac_lo);
+ a->frac_hi = a->frac_lo << shl;
+ a->frac_lo = 0;
+ return shl + 64;
}
+ return 128;
+}
- if (s->default_nan_mode) {
- return parts_default_nan(s);
+static int frac256_normalize(FloatParts256 *a)
+{
+ uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
+ uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
+ int ret, shl;
+
+ if (likely(a0)) {
+ shl = clz64(a0);
+ if (shl == 0) {
+ return 0;
+ }
+ ret = shl;
} else {
- if (pickNaN(a.cls, b.cls,
- a.frac > b.frac ||
- (a.frac == b.frac && a.sign < b.sign), s)) {
- a = b;
+ if (a1) {
+ ret = 64;
+ a0 = a1, a1 = a2, a2 = a3, a3 = 0;
+ } else if (a2) {
+ ret = 128;
+ a0 = a2, a1 = a3, a2 = 0, a3 = 0;
+ } else if (a3) {
+ ret = 192;
+ a0 = a3, a1 = 0, a2 = 0, a3 = 0;
+ } else {
+ ret = 256;
+ a0 = 0, a1 = 0, a2 = 0, a3 = 0;
+ goto done;
}
- if (is_snan(a.cls)) {
- return parts_silence_nan(a, s);
+ shl = clz64(a0);
+ if (shl == 0) {
+ goto done;
}
+ ret += shl;
}
- return a;
+
+ a0 = shl_double(a0, a1, shl);
+ a1 = shl_double(a1, a2, shl);
+ a2 = shl_double(a2, a3, shl);
+ a3 <<= shl;
+
+ done:
+ a->frac_hi = a0;
+ a->frac_hm = a1;
+ a->frac_lm = a2;
+ a->frac_lo = a3;
+ return ret;
}
-static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c,
- bool inf_zero, float_status *s)
+#define frac_normalize(A) FRAC_GENERIC_64_128_256(normalize, A)(A)
+
+static void frac64_shl(FloatParts64 *a, int c)
{
- int which;
+ a->frac <<= c;
+}
- if (is_snan(a.cls) || is_snan(b.cls) || is_snan(c.cls)) {
- s->float_exception_flags |= float_flag_invalid;
- }
+static void frac128_shl(FloatParts128 *a, int c)
+{
+ uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
- which = pickNaNMulAdd(a.cls, b.cls, c.cls, inf_zero, s);
+ if (c & 64) {
+ a0 = a1, a1 = 0;
+ }
- if (s->default_nan_mode) {
- /* Note that this check is after pickNaNMulAdd so that function
- * has an opportunity to set the Invalid flag.
- */
- which = 3;
+ c &= 63;
+ if (c) {
+ a0 = shl_double(a0, a1, c);
+ a1 = a1 << c;
}
- switch (which) {
- case 0:
- break;
- case 1:
- a = b;
- break;
- case 2:
- a = c;
- break;
- case 3:
- return parts_default_nan(s);
- default:
- g_assert_not_reached();
+ a->frac_hi = a0;
+ a->frac_lo = a1;
+}
+
+#define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C)
+
+static void frac64_shr(FloatParts64 *a, int c)
+{
+ a->frac >>= c;
+}
+
+static void frac128_shr(FloatParts128 *a, int c)
+{
+ uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
+
+ if (c & 64) {
+ a1 = a0, a0 = 0;
}
- if (is_snan(a.cls)) {
- return parts_silence_nan(a, s);
+ c &= 63;
+ if (c) {
+ a1 = shr_double(a0, a1, c);
+ a0 = a0 >> c;
}
- return a;
+
+ a->frac_hi = a0;
+ a->frac_lo = a1;
}
-/*
- * Returns the result of adding or subtracting the values of the
- * floating-point values `a' and `b'. The operation is performed
- * according to the IEC/IEEE Standard for Binary Floating-Point
- * Arithmetic.
- */
+#define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C)
-static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract,
- float_status *s)
+static void frac64_shrjam(FloatParts64 *a, int c)
{
- bool a_sign = a.sign;
- bool b_sign = b.sign ^ subtract;
-
- if (a_sign != b_sign) {
- /* Subtraction */
-
- if (a.cls == float_class_normal && b.cls == float_class_normal) {
- if (a.exp > b.exp || (a.exp == b.exp && a.frac >= b.frac)) {
- shift64RightJamming(b.frac, a.exp - b.exp, &b.frac);
- a.frac = a.frac - b.frac;
- } else {
- shift64RightJamming(a.frac, b.exp - a.exp, &a.frac);
- a.frac = b.frac - a.frac;
- a.exp = b.exp;
- a_sign ^= 1;
- }
+ uint64_t a0 = a->frac;
- if (a.frac == 0) {
- a.cls = float_class_zero;
- a.sign = s->float_rounding_mode == float_round_down;
- } else {
- int shift = clz64(a.frac) - 1;
- a.frac = a.frac << shift;
- a.exp = a.exp - shift;
- a.sign = a_sign;
- }
- return a;
- }
- if (is_nan(a.cls) || is_nan(b.cls)) {
- return pick_nan(a, b, s);
- }
- if (a.cls == float_class_inf) {
- if (b.cls == float_class_inf) {
- float_raise(float_flag_invalid, s);
- return parts_default_nan(s);
- }
- return a;
- }
- if (a.cls == float_class_zero && b.cls == float_class_zero) {
- a.sign = s->float_rounding_mode == float_round_down;
- return a;
- }
- if (a.cls == float_class_zero || b.cls == float_class_inf) {
- b.sign = a_sign ^ 1;
- return b;
+ if (likely(c != 0)) {
+ if (likely(c < 64)) {
+ a0 = (a0 >> c) | (shr_double(a0, 0, c) != 0);
+ } else {
+ a0 = a0 != 0;
}
- if (b.cls == float_class_zero) {
- return a;
+ a->frac = a0;
+ }
+}
+
+static void frac128_shrjam(FloatParts128 *a, int c)
+{
+ uint64_t a0 = a->frac_hi, a1 = a->frac_lo;
+ uint64_t sticky = 0;
+
+ if (unlikely(c == 0)) {
+ return;
+ } else if (likely(c < 64)) {
+ /* nothing */
+ } else if (likely(c < 128)) {
+ sticky = a1;
+ a1 = a0;
+ a0 = 0;
+ c &= 63;
+ if (c == 0) {
+ goto done;
}
} else {
- /* Addition */
- if (a.cls == float_class_normal && b.cls == float_class_normal) {
- if (a.exp > b.exp) {
- shift64RightJamming(b.frac, a.exp - b.exp, &b.frac);
- } else if (a.exp < b.exp) {
- shift64RightJamming(a.frac, b.exp - a.exp, &a.frac);
- a.exp = b.exp;
- }
- a.frac += b.frac;
- if (a.frac & DECOMPOSED_OVERFLOW_BIT) {
- shift64RightJamming(a.frac, 1, &a.frac);
- a.exp += 1;
- }
- return a;
- }
- if (is_nan(a.cls) || is_nan(b.cls)) {
- return pick_nan(a, b, s);
+ sticky = a0 | a1;
+ a0 = a1 = 0;
+ goto done;
+ }
+
+ sticky |= shr_double(a1, 0, c);
+ a1 = shr_double(a0, a1, c);
+ a0 = a0 >> c;
+
+ done:
+ a->frac_lo = a1 | (sticky != 0);
+ a->frac_hi = a0;
+}
+
+static void frac256_shrjam(FloatParts256 *a, int c)
+{
+ uint64_t a0 = a->frac_hi, a1 = a->frac_hm;
+ uint64_t a2 = a->frac_lm, a3 = a->frac_lo;
+ uint64_t sticky = 0;
+
+ if (unlikely(c == 0)) {
+ return;
+ } else if (likely(c < 64)) {
+ /* nothing */
+ } else if (likely(c < 256)) {
+ if (unlikely(c & 128)) {
+ sticky |= a2 | a3;
+ a3 = a1, a2 = a0, a1 = 0, a0 = 0;
}
- if (a.cls == float_class_inf || b.cls == float_class_zero) {
- return a;
+ if (unlikely(c & 64)) {
+ sticky |= a3;
+ a3 = a2, a2 = a1, a1 = a0, a0 = 0;
}
- if (b.cls == float_class_inf || a.cls == float_class_zero) {
- b.sign = b_sign;
- return b;
+ c &= 63;
+ if (c == 0) {
+ goto done;
}
+ } else {
+ sticky = a0 | a1 | a2 | a3;
+ a0 = a1 = a2 = a3 = 0;
+ goto done;
}
- g_assert_not_reached();
+
+ sticky |= shr_double(a3, 0, c);
+ a3 = shr_double(a2, a3, c);
+ a2 = shr_double(a1, a2, c);
+ a1 = shr_double(a0, a1, c);
+ a0 = a0 >> c;
+
+ done:
+ a->frac_lo = a3 | (sticky != 0);
+ a->frac_lm = a2;
+ a->frac_hm = a1;
+ a->frac_hi = a0;
+}
+
+#define frac_shrjam(A, C) FRAC_GENERIC_64_128_256(shrjam, A)(A, C)
+
+static bool frac64_sub(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b)
+{
+ return usub64_overflow(a->frac, b->frac, &r->frac);
+}
+
+static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b)
+{
+ bool c = 0;
+ r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c);
+ r->frac_hi = usub64_borrow(a->frac_hi, b->frac_hi, &c);
+ return c;
+}
+
+static bool frac256_sub(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b)
+{
+ bool c = 0;
+ r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c);
+ r->frac_lm = usub64_borrow(a->frac_lm, b->frac_lm, &c);
+ r->frac_hm = usub64_borrow(a->frac_hm, b->frac_hm, &c);
+ r->frac_hi = usub64_borrow(a->frac_hi, b->frac_hi, &c);
+ return c;
+}
+
+#define frac_sub(R, A, B) FRAC_GENERIC_64_128_256(sub, R)(R, A, B)
+
+static void frac64_truncjam(FloatParts64 *r, FloatParts128 *a)
+{
+ r->frac = a->frac_hi | (a->frac_lo != 0);
}
+static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a)
+{
+ r->frac_hi = a->frac_hi;
+ r->frac_lo = a->frac_hm | ((a->frac_lm | a->frac_lo) != 0);
+}
+
+#define frac_truncjam(R, A) FRAC_GENERIC_64_128(truncjam, R)(R, A)
+
+static void frac64_widen(FloatParts128 *r, FloatParts64 *a)
+{
+ r->frac_hi = a->frac;
+ r->frac_lo = 0;
+}
+
+static void frac128_widen(FloatParts256 *r, FloatParts128 *a)
+{
+ r->frac_hi = a->frac_hi;
+ r->frac_hm = a->frac_lo;
+ r->frac_lm = 0;
+ r->frac_lo = 0;
+}
+
+#define frac_widen(A, B) FRAC_GENERIC_64_128(widen, B)(A, B)
+
+#define partsN(NAME) glue(glue(glue(parts,N),_),NAME)
+#define FloatPartsN glue(FloatParts,N)
+#define FloatPartsW glue(FloatParts,W)
+
+#define N 64
+#define W 128
+
+#include "softfloat-parts-addsub.c.inc"
+#include "softfloat-parts.c.inc"
+
+#undef N
+#undef W
+#define N 128
+#define W 256
+
+#include "softfloat-parts-addsub.c.inc"
+#include "softfloat-parts.c.inc"
+
+#undef N
+#undef W
+#define N 256
+
+#include "softfloat-parts-addsub.c.inc"
+
+#undef N
+#undef W
+#undef partsN
+#undef FloatPartsN
+#undef FloatPartsW
+
/*
- * Returns the result of adding or subtracting the floating-point
- * values `a' and `b'. The operation is performed according to the
- * IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+ * Pack/unpack routines with a specific FloatFmt.
*/
-float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status)
+static void float16a_unpack_canonical(FloatParts64 *p, float16 f,
+ float_status *s, const FloatFmt *params)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, false, status);
+ float16_unpack_raw(p, f);
+ parts_canonicalize(p, s, params);
+}
- return float16_round_pack_canonical(pr, status);
+static void float16_unpack_canonical(FloatParts64 *p, float16 f,
+ float_status *s)
+{
+ float16a_unpack_canonical(p, f, s, &float16_params);
}
-float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status)
+static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f,
+ float_status *s)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, true, status);
+ bfloat16_unpack_raw(p, f);
+ parts_canonicalize(p, s, &bfloat16_params);
+}
+
+static float16 float16a_round_pack_canonical(FloatParts64 *p,
+ float_status *s,
+ const FloatFmt *params)
+{
+ parts_uncanon(p, s, params);
+ return float16_pack_raw(p);
+}
+
+static float16 float16_round_pack_canonical(FloatParts64 *p,
+ float_status *s)
+{
+ return float16a_round_pack_canonical(p, s, &float16_params);
+}
+
+static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p,
+ float_status *s)
+{
+ parts_uncanon(p, s, &bfloat16_params);
+ return bfloat16_pack_raw(p);
+}
+
+static void float32_unpack_canonical(FloatParts64 *p, float32 f,
+ float_status *s)
+{
+ float32_unpack_raw(p, f);
+ parts_canonicalize(p, s, &float32_params);
+}
+
+static float32 float32_round_pack_canonical(FloatParts64 *p,
+ float_status *s)
+{
+ parts_uncanon(p, s, &float32_params);
+ return float32_pack_raw(p);
+}
+
+static void float64_unpack_canonical(FloatParts64 *p, float64 f,
+ float_status *s)
+{
+ float64_unpack_raw(p, f);
+ parts_canonicalize(p, s, &float64_params);
+}
+
+static float64 float64_round_pack_canonical(FloatParts64 *p,
+ float_status *s)
+{
+ parts_uncanon(p, s, &float64_params);
+ return float64_pack_raw(p);
+}
+
+static void float128_unpack_canonical(FloatParts128 *p, float128 f,
+ float_status *s)
+{
+ float128_unpack_raw(p, f);
+ parts_canonicalize(p, s, &float128_params);
+}
+
+static float128 float128_round_pack_canonical(FloatParts128 *p,
+ float_status *s)
+{
+ parts_uncanon(p, s, &float128_params);
+ return float128_pack_raw(p);
+}
+
+/*
+ * Addition and subtraction
+ */
+
+static float16 QEMU_FLATTEN
+float16_addsub(float16 a, float16 b, float_status *status, bool subtract)
+{
+ FloatParts64 pa, pb, *pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ float16_unpack_canonical(&pb, b, status);
+ pr = parts_addsub(&pa, &pb, status, subtract);
return float16_round_pack_canonical(pr, status);
}
+float16 float16_add(float16 a, float16 b, float_status *status)
+{
+ return float16_addsub(a, b, status, false);
+}
+
+float16 float16_sub(float16 a, float16 b, float_status *status)
+{
+ return float16_addsub(a, b, status, true);
+}
+
static float32 QEMU_SOFTFLOAT_ATTR
-soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status)
+soft_f32_addsub(float32 a, float32 b, float_status *status, bool subtract)
{
- FloatParts pa = float32_unpack_canonical(a, status);
- FloatParts pb = float32_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, subtract, status);
+ FloatParts64 pa, pb, *pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ float32_unpack_canonical(&pb, b, status);
+ pr = parts_addsub(&pa, &pb, status, subtract);
return float32_round_pack_canonical(pr, status);
}
-static inline float32 soft_f32_add(float32 a, float32 b, float_status *status)
+static float32 soft_f32_add(float32 a, float32 b, float_status *status)
{
- return soft_f32_addsub(a, b, false, status);
+ return soft_f32_addsub(a, b, status, false);
}
-static inline float32 soft_f32_sub(float32 a, float32 b, float_status *status)
+static float32 soft_f32_sub(float32 a, float32 b, float_status *status)
{
- return soft_f32_addsub(a, b, true, status);
+ return soft_f32_addsub(a, b, status, true);
}
static float64 QEMU_SOFTFLOAT_ATTR
-soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status)
+soft_f64_addsub(float64 a, float64 b, float_status *status, bool subtract)
{
- FloatParts pa = float64_unpack_canonical(a, status);
- FloatParts pb = float64_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, subtract, status);
+ FloatParts64 pa, pb, *pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ float64_unpack_canonical(&pb, b, status);
+ pr = parts_addsub(&pa, &pb, status, subtract);
return float64_round_pack_canonical(pr, status);
}
-static inline float64 soft_f64_add(float64 a, float64 b, float_status *status)
+static float64 soft_f64_add(float64 a, float64 b, float_status *status)
{
- return soft_f64_addsub(a, b, false, status);
+ return soft_f64_addsub(a, b, status, false);
}
-static inline float64 soft_f64_sub(float64 a, float64 b, float_status *status)
+static float64 soft_f64_sub(float64 a, float64 b, float_status *status)
{
- return soft_f64_addsub(a, b, true, status);
+ return soft_f64_addsub(a, b, status, true);
}
static float hard_f32_add(float a, float b)
@@ -1182,82 +1591,61 @@ float64_sub(float64 a, float64 b, float_status *s)
return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub);
}
-/*
- * Returns the result of adding or subtracting the bfloat16
- * values `a' and `b'.
- */
-bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status)
+static bfloat16 QEMU_FLATTEN
+bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pb = bfloat16_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, false, status);
+ FloatParts64 pa, pb, *pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ bfloat16_unpack_canonical(&pb, b, status);
+ pr = parts_addsub(&pa, &pb, status, subtract);
return bfloat16_round_pack_canonical(pr, status);
}
-bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status)
+bfloat16 bfloat16_add(bfloat16 a, bfloat16 b, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pb = bfloat16_unpack_canonical(b, status);
- FloatParts pr = addsub_floats(pa, pb, true, status);
-
- return bfloat16_round_pack_canonical(pr, status);
+ return bfloat16_addsub(a, b, status, false);
}
-/*
- * Returns the result of multiplying the floating-point values `a' and
- * `b'. The operation is performed according to the IEC/IEEE Standard
- * for Binary Floating-Point Arithmetic.
- */
+bfloat16 bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status)
+{
+ return bfloat16_addsub(a, b, status, true);
+}
-static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s)
+static float128 QEMU_FLATTEN
+float128_addsub(float128 a, float128 b, float_status *status, bool subtract)
{
- bool sign = a.sign ^ b.sign;
+ FloatParts128 pa, pb, *pr;
- if (a.cls == float_class_normal && b.cls == float_class_normal) {
- uint64_t hi, lo;
- int exp = a.exp + b.exp;
+ float128_unpack_canonical(&pa, a, status);
+ float128_unpack_canonical(&pb, b, status);
+ pr = parts_addsub(&pa, &pb, status, subtract);
- mul64To128(a.frac, b.frac, &hi, &lo);
- shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo);
- if (lo & DECOMPOSED_OVERFLOW_BIT) {
- shift64RightJamming(lo, 1, &lo);
- exp += 1;
- }
+ return float128_round_pack_canonical(pr, status);
+}
- /* Re-use a */
- a.exp = exp;
- a.sign = sign;
- a.frac = lo;
- return a;
- }
- /* handle all the NaN cases */
- if (is_nan(a.cls) || is_nan(b.cls)) {
- return pick_nan(a, b, s);
- }
- /* Inf * Zero == NaN */
- if ((a.cls == float_class_inf && b.cls == float_class_zero) ||
- (a.cls == float_class_zero && b.cls == float_class_inf)) {
- s->float_exception_flags |= float_flag_invalid;
- return parts_default_nan(s);
- }
- /* Multiply by 0 or Inf */
- if (a.cls == float_class_inf || a.cls == float_class_zero) {
- a.sign = sign;
- return a;
- }
- if (b.cls == float_class_inf || b.cls == float_class_zero) {
- b.sign = sign;
- return b;
- }
- g_assert_not_reached();
+float128 float128_add(float128 a, float128 b, float_status *status)
+{
+ return float128_addsub(a, b, status, false);
}
+float128 float128_sub(float128 a, float128 b, float_status *status)
+{
+ return float128_addsub(a, b, status, true);
+}
+
+/*
+ * Multiplication
+ */
+
float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pr = mul_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ float16_unpack_canonical(&pb, b, status);
+ pr = parts_mul(&pa, &pb, status);
return float16_round_pack_canonical(pr, status);
}
@@ -1265,9 +1653,11 @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 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);
- FloatParts pr = mul_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ float32_unpack_canonical(&pb, b, status);
+ pr = parts_mul(&pa, &pb, status);
return float32_round_pack_canonical(pr, status);
}
@@ -1275,9 +1665,11 @@ soft_f32_mul(float32 a, float32 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);
- FloatParts pr = mul_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ float64_unpack_canonical(&pb, b, status);
+ pr = parts_mul(&pa, &pb, status);
return float64_round_pack_canonical(pr, status);
}
@@ -1306,230 +1698,43 @@ float64_mul(float64 a, float64 b, float_status *s)
f64_is_zon2, f64_addsubmul_post);
}
-/*
- * Returns the result of multiplying the bfloat16
- * values `a' and `b'.
- */
-
-bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status)
+bfloat16 QEMU_FLATTEN
+bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pb = bfloat16_unpack_canonical(b, status);
- FloatParts pr = mul_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ bfloat16_unpack_canonical(&pb, b, status);
+ pr = parts_mul(&pa, &pb, status);
return bfloat16_round_pack_canonical(pr, status);
}
-/*
- * Returns the result of multiplying the floating-point values `a' and
- * `b' then adding 'c', with no intermediate rounding step after the
- * multiplication. The operation is performed according to the
- * IEC/IEEE Standard for Binary Floating-Point Arithmetic 754-2008.
- * The flags argument allows the caller to select negation of the
- * addend, the intermediate product, or the final result. (The
- * difference between this and having the caller do a separate
- * negation is that negating externally will flip the sign bit on
- * NaNs.)
- */
-
-static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c,
- int flags, float_status *s)
-{
- bool inf_zero = ((1 << a.cls) | (1 << b.cls)) ==
- ((1 << float_class_inf) | (1 << float_class_zero));
- bool p_sign;
- bool sign_flip = flags & float_muladd_negate_result;
- FloatClass p_class;
- uint64_t hi, lo;
- int p_exp;
-
- /* It is implementation-defined whether the cases of (0,inf,qnan)
- * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN
- * they return if they do), so we have to hand this information
- * off to the target-specific pick-a-NaN routine.
- */
- if (is_nan(a.cls) || is_nan(b.cls) || is_nan(c.cls)) {
- return pick_nan_muladd(a, b, c, inf_zero, s);
- }
-
- if (inf_zero) {
- s->float_exception_flags |= float_flag_invalid;
- return parts_default_nan(s);
- }
-
- if (flags & float_muladd_negate_c) {
- c.sign ^= 1;
- }
-
- p_sign = a.sign ^ b.sign;
-
- if (flags & float_muladd_negate_product) {
- p_sign ^= 1;
- }
-
- if (a.cls == float_class_inf || b.cls == float_class_inf) {
- p_class = float_class_inf;
- } else if (a.cls == float_class_zero || b.cls == float_class_zero) {
- p_class = float_class_zero;
- } else {
- p_class = float_class_normal;
- }
-
- if (c.cls == float_class_inf) {
- if (p_class == float_class_inf && p_sign != c.sign) {
- s->float_exception_flags |= float_flag_invalid;
- return parts_default_nan(s);
- } else {
- a.cls = float_class_inf;
- a.sign = c.sign ^ sign_flip;
- return a;
- }
- }
-
- if (p_class == float_class_inf) {
- a.cls = float_class_inf;
- a.sign = p_sign ^ sign_flip;
- return a;
- }
-
- if (p_class == float_class_zero) {
- if (c.cls == float_class_zero) {
- if (p_sign != c.sign) {
- p_sign = s->float_rounding_mode == float_round_down;
- }
- c.sign = p_sign;
- } else if (flags & float_muladd_halve_result) {
- c.exp -= 1;
- }
- c.sign ^= sign_flip;
- return c;
- }
-
- /* a & b should be normals now... */
- assert(a.cls == float_class_normal &&
- b.cls == float_class_normal);
-
- p_exp = a.exp + b.exp;
-
- /* Multiply of 2 62-bit numbers produces a (2*62) == 124-bit
- * result.
- */
- mul64To128(a.frac, b.frac, &hi, &lo);
- /* binary point now at bit 124 */
-
- /* check for overflow */
- if (hi & (1ULL << (DECOMPOSED_BINARY_POINT * 2 + 1 - 64))) {
- shift128RightJamming(hi, lo, 1, &hi, &lo);
- p_exp += 1;
- }
-
- /* + add/sub */
- if (c.cls == float_class_zero) {
- /* move binary point back to 62 */
- shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo);
- } else {
- int exp_diff = p_exp - c.exp;
- if (p_sign == c.sign) {
- /* Addition */
- if (exp_diff <= 0) {
- shift128RightJamming(hi, lo,
- DECOMPOSED_BINARY_POINT - exp_diff,
- &hi, &lo);
- lo += c.frac;
- p_exp = c.exp;
- } else {
- uint64_t c_hi, c_lo;
- /* shift c to the same binary point as the product (124) */
- c_hi = c.frac >> 2;
- c_lo = 0;
- shift128RightJamming(c_hi, c_lo,
- exp_diff,
- &c_hi, &c_lo);
- add128(hi, lo, c_hi, c_lo, &hi, &lo);
- /* move binary point back to 62 */
- shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo);
- }
-
- if (lo & DECOMPOSED_OVERFLOW_BIT) {
- shift64RightJamming(lo, 1, &lo);
- p_exp += 1;
- }
-
- } else {
- /* Subtraction */
- uint64_t c_hi, c_lo;
- /* make C binary point match product at bit 124 */
- c_hi = c.frac >> 2;
- c_lo = 0;
-
- if (exp_diff <= 0) {
- shift128RightJamming(hi, lo, -exp_diff, &hi, &lo);
- if (exp_diff == 0
- &&
- (hi > c_hi || (hi == c_hi && lo >= c_lo))) {
- sub128(hi, lo, c_hi, c_lo, &hi, &lo);
- } else {
- sub128(c_hi, c_lo, hi, lo, &hi, &lo);
- p_sign ^= 1;
- p_exp = c.exp;
- }
- } else {
- shift128RightJamming(c_hi, c_lo,
- exp_diff,
- &c_hi, &c_lo);
- sub128(hi, lo, c_hi, c_lo, &hi, &lo);
- }
-
- if (hi == 0 && lo == 0) {
- a.cls = float_class_zero;
- a.sign = s->float_rounding_mode == float_round_down;
- a.sign ^= sign_flip;
- return a;
- } else {
- int shift;
- if (hi != 0) {
- shift = clz64(hi);
- } else {
- shift = clz64(lo) + 64;
- }
- /* Normalizing to a binary point of 124 is the
- correct adjust for the exponent. However since we're
- shifting, we might as well put the binary point back
- at 62 where we really want it. Therefore shift as
- if we're leaving 1 bit at the top of the word, but
- adjust the exponent as if we're leaving 3 bits. */
- shift -= 1;
- if (shift >= 64) {
- lo = lo << (shift - 64);
- } else {
- hi = (hi << shift) | (lo >> (64 - shift));
- lo = hi | ((lo << shift) != 0);
- }
- p_exp -= shift - 2;
- }
- }
- }
-
- if (flags & float_muladd_halve_result) {
- p_exp -= 1;
- }
+float128 QEMU_FLATTEN
+float128_mul(float128 a, float128 b, float_status *status)
+{
+ FloatParts128 pa, pb, *pr;
- /* finally prepare our result */
- a.cls = float_class_normal;
- a.sign = p_sign ^ sign_flip;
- a.exp = p_exp;
- a.frac = lo;
+ float128_unpack_canonical(&pa, a, status);
+ float128_unpack_canonical(&pb, b, status);
+ pr = parts_mul(&pa, &pb, status);
- return a;
+ return float128_round_pack_canonical(pr, status);
}
+/*
+ * Fused multiply-add
+ */
+
float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c,
- int flags, float_status *status)
+ int flags, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pc = float16_unpack_canonical(c, status);
- FloatParts pr = muladd_floats(pa, pb, pc, flags, status);
+ FloatParts64 pa, pb, pc, *pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ float16_unpack_canonical(&pb, b, status);
+ float16_unpack_canonical(&pc, c, status);
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
return float16_round_pack_canonical(pr, status);
}
@@ -1538,10 +1743,12 @@ 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);
- FloatParts pc = float32_unpack_canonical(c, status);
- FloatParts pr = muladd_floats(pa, pb, pc, flags, status);
+ FloatParts64 pa, pb, pc, *pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ float32_unpack_canonical(&pb, b, status);
+ float32_unpack_canonical(&pc, c, status);
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
return float32_round_pack_canonical(pr, status);
}
@@ -1550,10 +1757,12 @@ 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);
- FloatParts pc = float64_unpack_canonical(c, status);
- FloatParts pr = muladd_floats(pa, pb, pc, flags, status);
+ FloatParts64 pa, pb, pc, *pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ float64_unpack_canonical(&pb, b, status);
+ float64_unpack_canonical(&pc, c, status);
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
return float64_round_pack_canonical(pr, status);
}
@@ -1615,7 +1824,7 @@ float32_muladd(float32 xa, float32 xb, float32 xc, int flags, float_status *s)
ur.h = fmaf(ua.h, ub.h, uc.h);
if (unlikely(f32_is_inf(ur))) {
- s->float_exception_flags |= float_flag_overflow;
+ float_raise(float_flag_overflow, s);
} else if (unlikely(fabsf(ur.h) <= FLT_MIN)) {
ua = ua_orig;
uc = uc_orig;
@@ -1686,7 +1895,7 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
ur.h = fma(ua.h, ub.h, uc.h);
if (unlikely(f64_is_inf(ur))) {
- s->float_exception_flags |= float_flag_overflow;
+ float_raise(float_flag_overflow, s);
} else if (unlikely(fabs(ur.h) <= FLT_MIN)) {
ua = ua_orig;
uc = uc_orig;
@@ -1702,107 +1911,43 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
return soft_f64_muladd(ua.s, ub.s, uc.s, flags, s);
}
-/*
- * Returns the result of multiplying the bfloat16 values `a'
- * and `b' then adding 'c', with no intermediate rounding step after the
- * multiplication.
- */
-
bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c,
int flags, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pb = bfloat16_unpack_canonical(b, status);
- FloatParts pc = bfloat16_unpack_canonical(c, status);
- FloatParts pr = muladd_floats(pa, pb, pc, flags, status);
+ FloatParts64 pa, pb, pc, *pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ bfloat16_unpack_canonical(&pb, b, status);
+ bfloat16_unpack_canonical(&pc, c, status);
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
return bfloat16_round_pack_canonical(pr, status);
}
-/*
- * Returns the result of dividing the floating-point value `a' by the
- * corresponding value `b'. The operation is performed according to
- * the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
- */
-
-static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s)
+float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c,
+ int flags, float_status *status)
{
- bool sign = a.sign ^ b.sign;
+ FloatParts128 pa, pb, pc, *pr;
- if (a.cls == float_class_normal && b.cls == float_class_normal) {
- uint64_t n0, n1, q, r;
- int exp = a.exp - b.exp;
+ float128_unpack_canonical(&pa, a, status);
+ float128_unpack_canonical(&pb, b, status);
+ float128_unpack_canonical(&pc, c, status);
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
- /*
- * We want a 2*N / N-bit division to produce exactly an N-bit
- * result, so that we do not lose any precision and so that we
- * do not have to renormalize afterward. If A.frac < B.frac,
- * then division would produce an (N-1)-bit result; shift A left
- * by one to produce the an N-bit result, and decrement the
- * exponent to match.
- *
- * The udiv_qrnnd algorithm that we're using requires normalization,
- * i.e. the msb of the denominator must be set. Since we know that
- * DECOMPOSED_BINARY_POINT is msb-1, the inputs must be shifted left
- * by one (more), and the remainder must be shifted right by one.
- */
- if (a.frac < b.frac) {
- exp -= 1;
- shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT + 2, &n1, &n0);
- } else {
- shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT + 1, &n1, &n0);
- }
- q = udiv_qrnnd(&r, n1, n0, b.frac << 1);
-
- /*
- * Set lsb if there is a remainder, to set inexact.
- * As mentioned above, to find the actual value of the remainder we
- * would need to shift right, but (1) we are only concerned about
- * non-zero-ness, and (2) the remainder will always be even because
- * both inputs to the division primitive are even.
- */
- a.frac = q | (r != 0);
- a.sign = sign;
- a.exp = exp;
- return a;
- }
- /* handle all the NaN cases */
- if (is_nan(a.cls) || is_nan(b.cls)) {
- return pick_nan(a, b, s);
- }
- /* 0/0 or Inf/Inf */
- if (a.cls == b.cls
- &&
- (a.cls == float_class_inf || a.cls == float_class_zero)) {
- s->float_exception_flags |= float_flag_invalid;
- return parts_default_nan(s);
- }
- /* Inf / x or 0 / x */
- if (a.cls == float_class_inf || a.cls == float_class_zero) {
- a.sign = sign;
- return a;
- }
- /* Div 0 => Inf */
- if (b.cls == float_class_zero) {
- s->float_exception_flags |= float_flag_divbyzero;
- a.cls = float_class_inf;
- a.sign = sign;
- return a;
- }
- /* Div by Inf */
- if (b.cls == float_class_inf) {
- a.cls = float_class_zero;
- a.sign = sign;
- return a;
- }
- g_assert_not_reached();
+ return float128_round_pack_canonical(pr, status);
}
+/*
+ * Division
+ */
+
float16 float16_div(float16 a, float16 b, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pb = float16_unpack_canonical(b, status);
- FloatParts pr = div_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ float16_unpack_canonical(&pb, b, status);
+ pr = parts_div(&pa, &pb, status);
return float16_round_pack_canonical(pr, status);
}
@@ -1810,9 +1955,11 @@ float16 float16_div(float16 a, float16 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);
- FloatParts pr = div_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ float32_unpack_canonical(&pb, b, status);
+ pr = parts_div(&pa, &pb, status);
return float32_round_pack_canonical(pr, status);
}
@@ -1820,9 +1967,11 @@ soft_f32_div(float32 a, float32 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);
- FloatParts pr = div_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ float64_unpack_canonical(&pb, b, status);
+ pr = parts_div(&pa, &pb, status);
return float64_round_pack_canonical(pr, status);
}
@@ -1885,20 +2034,30 @@ float64_div(float64 a, float64 b, float_status *s)
f64_div_pre, f64_div_post);
}
-/*
- * Returns the result of dividing the bfloat16
- * value `a' by the corresponding value `b'.
- */
-
-bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
+bfloat16 QEMU_FLATTEN
+bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pb = bfloat16_unpack_canonical(b, status);
- FloatParts pr = div_floats(pa, pb, status);
+ FloatParts64 pa, pb, *pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ bfloat16_unpack_canonical(&pb, b, status);
+ pr = parts_div(&pa, &pb, status);
return bfloat16_round_pack_canonical(pr, status);
}
+float128 QEMU_FLATTEN
+float128_div(float128 a, float128 b, float_status *status)
+{
+ FloatParts128 pa, pb, *pr;
+
+ float128_unpack_canonical(&pa, a, status);
+ float128_unpack_canonical(&pb, b, status);
+ pr = parts_div(&pa, &pb, status);
+
+ return float128_round_pack_canonical(pr, status);
+}
+
/*
* Float to Float conversions
*
@@ -1906,81 +2065,134 @@ bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
* conversion is performed according to the IEC/IEEE Standard for
* Binary Floating-Point Arithmetic.
*
- * The float_to_float helper only needs to take care of raising
- * invalid exceptions and handling the conversion on NaNs.
+ * Usually this only needs to take care of raising invalid exceptions
+ * and handling the conversion on NaNs.
*/
-static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf,
- float_status *s)
+static void parts_float_to_ahp(FloatParts64 *a, float_status *s)
{
- if (dstf->arm_althp) {
- switch (a.cls) {
- case float_class_qnan:
- case float_class_snan:
- /* There is no NaN in the destination format. Raise Invalid
- * and return a zero with the sign of the input NaN.
- */
- s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_zero;
- a.frac = 0;
- a.exp = 0;
- break;
+ switch (a->cls) {
+ case float_class_qnan:
+ case float_class_snan:
+ /*
+ * There is no NaN in the destination format. Raise Invalid
+ * and return a zero with the sign of the input NaN.
+ */
+ float_raise(float_flag_invalid, s);
+ a->cls = float_class_zero;
+ break;
- case float_class_inf:
- /* There is no Inf in the destination format. Raise Invalid
- * and return the maximum normal with the correct sign.
- */
- s->float_exception_flags |= float_flag_invalid;
- a.cls = float_class_normal;
- a.exp = dstf->exp_max;
- a.frac = ((1ull << dstf->frac_size) - 1) << dstf->frac_shift;
- break;
+ case float_class_inf:
+ /*
+ * There is no Inf in the destination format. Raise Invalid
+ * and return the maximum normal with the correct sign.
+ */
+ float_raise(float_flag_invalid, s);
+ a->cls = float_class_normal;
+ a->exp = float16_params_ahp.exp_max;
+ a->frac = MAKE_64BIT_MASK(float16_params_ahp.frac_shift,
+ float16_params_ahp.frac_size + 1);
+ break;
- default:
- break;
- }
- } else if (is_nan(a.cls)) {
- if (is_snan(a.cls)) {
- s->float_exception_flags |= float_flag_invalid;
- a = parts_silence_nan(a, s);
- }
- if (s->default_nan_mode) {
- return parts_default_nan(s);
- }
+ case float_class_normal:
+ case float_class_zero:
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void parts64_float_to_float(FloatParts64 *a, float_status *s)
+{
+ if (is_nan(a->cls)) {
+ parts_return_nan(a, s);
+ }
+}
+
+static void parts128_float_to_float(FloatParts128 *a, float_status *s)
+{
+ if (is_nan(a->cls)) {
+ parts_return_nan(a, s);
+ }
+}
+
+#define parts_float_to_float(P, S) \
+ PARTS_GENERIC_64_128(float_to_float, P)(P, S)
+
+static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b,
+ float_status *s)
+{
+ a->cls = b->cls;
+ a->sign = b->sign;
+ a->exp = b->exp;
+
+ if (a->cls == float_class_normal) {
+ frac_truncjam(a, b);
+ } else if (is_nan(a->cls)) {
+ /* Discard the low bits of the NaN. */
+ a->frac = b->frac_hi;
+ parts_return_nan(a, s);
+ }
+}
+
+static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b,
+ float_status *s)
+{
+ a->cls = b->cls;
+ a->sign = b->sign;
+ a->exp = b->exp;
+ frac_widen(a, b);
+
+ if (is_nan(a->cls)) {
+ parts_return_nan(a, s);
}
- return a;
}
float32 float16_to_float32(float16 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
- FloatParts p = float16a_unpack_canonical(a, s, fmt16);
- FloatParts pr = float_to_float(p, &float32_params, s);
- return float32_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float16a_unpack_canonical(&p, a, s, fmt16);
+ parts_float_to_float(&p, s);
+ return float32_round_pack_canonical(&p, s);
}
float64 float16_to_float64(float16 a, bool ieee, float_status *s)
{
const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
- FloatParts p = float16a_unpack_canonical(a, s, fmt16);
- FloatParts pr = float_to_float(p, &float64_params, s);
- return float64_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float16a_unpack_canonical(&p, a, s, fmt16);
+ parts_float_to_float(&p, s);
+ return float64_round_pack_canonical(&p, s);
}
float16 float32_to_float16(float32 a, bool ieee, float_status *s)
{
- const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
- FloatParts p = float32_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, fmt16, s);
- return float16a_round_pack_canonical(pr, s, fmt16);
+ FloatParts64 p;
+ const FloatFmt *fmt;
+
+ float32_unpack_canonical(&p, a, s);
+ if (ieee) {
+ parts_float_to_float(&p, s);
+ fmt = &float16_params;
+ } else {
+ parts_float_to_ahp(&p, s);
+ fmt = &float16_params_ahp;
+ }
+ return float16a_round_pack_canonical(&p, s, fmt);
}
static float64 QEMU_SOFTFLOAT_ATTR
soft_float32_to_float64(float32 a, float_status *s)
{
- FloatParts p = float32_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &float64_params, s);
- return float64_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return float64_round_pack_canonical(&p, s);
}
float64 float32_to_float64(float32 a, float_status *s)
@@ -2001,313 +2213,291 @@ float64 float32_to_float64(float32 a, float_status *s)
float16 float64_to_float16(float64 a, bool ieee, float_status *s)
{
- const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
- FloatParts p = float64_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, fmt16, s);
- return float16a_round_pack_canonical(pr, s, fmt16);
+ FloatParts64 p;
+ const FloatFmt *fmt;
+
+ float64_unpack_canonical(&p, a, s);
+ if (ieee) {
+ parts_float_to_float(&p, s);
+ fmt = &float16_params;
+ } else {
+ parts_float_to_ahp(&p, s);
+ fmt = &float16_params_ahp;
+ }
+ return float16a_round_pack_canonical(&p, s, fmt);
}
float32 float64_to_float32(float64 a, float_status *s)
{
- FloatParts p = float64_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &float32_params, s);
- return float32_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return float32_round_pack_canonical(&p, s);
}
float32 bfloat16_to_float32(bfloat16 a, float_status *s)
{
- FloatParts p = bfloat16_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &float32_params, s);
- return float32_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return float32_round_pack_canonical(&p, s);
}
float64 bfloat16_to_float64(bfloat16 a, float_status *s)
{
- FloatParts p = bfloat16_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &float64_params, s);
- return float64_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return float64_round_pack_canonical(&p, s);
}
bfloat16 float32_to_bfloat16(float32 a, float_status *s)
{
- FloatParts p = float32_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &bfloat16_params, s);
- return bfloat16_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return bfloat16_round_pack_canonical(&p, s);
}
bfloat16 float64_to_bfloat16(float64 a, float_status *s)
{
- FloatParts p = float64_unpack_canonical(a, s);
- FloatParts pr = float_to_float(p, &bfloat16_params, s);
- return bfloat16_round_pack_canonical(pr, s);
-}
+ FloatParts64 p;
-/*
- * Rounds the floating-point value `a' to an integer, and returns the
- * result as a floating-point value. The operation is performed
- * according to the IEC/IEEE Standard for Binary Floating-Point
- * Arithmetic.
- */
+ float64_unpack_canonical(&p, a, s);
+ parts_float_to_float(&p, s);
+ return bfloat16_round_pack_canonical(&p, s);
+}
-static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode,
- int scale, float_status *s)
+float32 float128_to_float32(float128 a, float_status *s)
{
- switch (a.cls) {
- case float_class_qnan:
- case float_class_snan:
- return return_nan(a, s);
+ FloatParts64 p64;
+ FloatParts128 p128;
- case float_class_zero:
- case float_class_inf:
- /* already "integral" */
- break;
+ float128_unpack_canonical(&p128, a, s);
+ parts_float_to_float_narrow(&p64, &p128, s);
+ return float32_round_pack_canonical(&p64, s);
+}
- case float_class_normal:
- scale = MIN(MAX(scale, -0x10000), 0x10000);
- a.exp += scale;
+float64 float128_to_float64(float128 a, float_status *s)
+{
+ FloatParts64 p64;
+ FloatParts128 p128;
- if (a.exp >= DECOMPOSED_BINARY_POINT) {
- /* already integral */
- break;
- }
- if (a.exp < 0) {
- bool one;
- /* all fractional */
- s->float_exception_flags |= float_flag_inexact;
- switch (rmode) {
- case float_round_nearest_even:
- one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT;
- break;
- case float_round_ties_away:
- one = a.exp == -1 && a.frac >= DECOMPOSED_IMPLICIT_BIT;
- break;
- case float_round_to_zero:
- one = false;
- break;
- case float_round_up:
- one = !a.sign;
- break;
- case float_round_down:
- one = a.sign;
- break;
- case float_round_to_odd:
- one = true;
- break;
- default:
- g_assert_not_reached();
- }
+ float128_unpack_canonical(&p128, a, s);
+ parts_float_to_float_narrow(&p64, &p128, s);
+ return float64_round_pack_canonical(&p64, s);
+}
- if (one) {
- a.frac = DECOMPOSED_IMPLICIT_BIT;
- a.exp = 0;
- } else {
- a.cls = float_class_zero;
- }
- } else {
- uint64_t frac_lsb = DECOMPOSED_IMPLICIT_BIT >> a.exp;
- uint64_t frac_lsbm1 = frac_lsb >> 1;
- uint64_t rnd_even_mask = (frac_lsb - 1) | frac_lsb;
- uint64_t rnd_mask = rnd_even_mask >> 1;
- uint64_t inc;
+float128 float32_to_float128(float32 a, float_status *s)
+{
+ FloatParts64 p64;
+ FloatParts128 p128;
- switch (rmode) {
- case float_round_nearest_even:
- inc = ((a.frac & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
- break;
- case float_round_ties_away:
- inc = frac_lsbm1;
- break;
- case float_round_to_zero:
- inc = 0;
- break;
- case float_round_up:
- inc = a.sign ? 0 : rnd_mask;
- break;
- case float_round_down:
- inc = a.sign ? rnd_mask : 0;
- break;
- case float_round_to_odd:
- inc = a.frac & frac_lsb ? 0 : rnd_mask;
- break;
- default:
- g_assert_not_reached();
- }
+ float32_unpack_canonical(&p64, a, s);
+ parts_float_to_float_widen(&p128, &p64, s);
+ return float128_round_pack_canonical(&p128, s);
+}
- if (a.frac & rnd_mask) {
- s->float_exception_flags |= float_flag_inexact;
- a.frac += inc;
- a.frac &= ~rnd_mask;
- if (a.frac & DECOMPOSED_OVERFLOW_BIT) {
- a.frac >>= 1;
- a.exp++;
- }
- }
- }
- break;
- default:
- g_assert_not_reached();
- }
- return a;
+float128 float64_to_float128(float64 a, float_status *s)
+{
+ FloatParts64 p64;
+ FloatParts128 p128;
+
+ float64_unpack_canonical(&p64, a, s);
+ parts_float_to_float_widen(&p128, &p64, s);
+ return float128_round_pack_canonical(&p128, s);
}
+/*
+ * Round to integral value
+ */
+
float16 float16_round_to_int(float16 a, float_status *s)
{
- FloatParts pa = float16_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
- return float16_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float16_params);
+ return float16_round_pack_canonical(&p, s);
}
float32 float32_round_to_int(float32 a, float_status *s)
{
- FloatParts pa = float32_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
- return float32_round_pack_canonical(pr, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float32_params);
+ return float32_round_pack_canonical(&p, s);
}
float64 float64_round_to_int(float64 a, float_status *s)
{
- FloatParts pa = float64_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
- return float64_round_pack_canonical(pr, s);
-}
+ FloatParts64 p;
-/*
- * Rounds the bfloat16 value `a' to an integer, and returns the
- * result as a bfloat16 value.
- */
+ float64_unpack_canonical(&p, a, s);
+ parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float64_params);
+ return float64_round_pack_canonical(&p, s);
+}
bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s)
{
- FloatParts pa = bfloat16_unpack_canonical(a, s);
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
- return bfloat16_round_pack_canonical(pr, s);
-}
+ FloatParts64 p;
-/*
- * Returns the result of converting the floating-point value `a' to
- * the two's complement integer format. The conversion is performed
- * according to the IEC/IEEE Standard for Binary Floating-Point
- * Arithmetic---which means in particular that the conversion is
- * rounded according to the current rounding mode. If `a' is a NaN,
- * the largest positive integer is returned. Otherwise, if the
- * conversion overflows, the largest integer with the same sign as `a'
- * is returned.
-*/
+ bfloat16_unpack_canonical(&p, a, s);
+ parts_round_to_int(&p, s->float_rounding_mode, 0, s, &bfloat16_params);
+ return bfloat16_round_pack_canonical(&p, s);
+}
-static int64_t round_to_int_and_pack(FloatParts in, FloatRoundMode rmode,
- int scale, int64_t min, int64_t max,
- float_status *s)
+float128 float128_round_to_int(float128 a, float_status *s)
{
- uint64_t r;
- int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, scale, s);
+ FloatParts128 p;
- switch (p.cls) {
- case float_class_snan:
- case float_class_qnan:
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return max;
- case float_class_inf:
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return p.sign ? min : max;
- case float_class_zero:
- return 0;
- case float_class_normal:
- if (p.exp < DECOMPOSED_BINARY_POINT) {
- r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp);
- } else if (p.exp - DECOMPOSED_BINARY_POINT < 2) {
- r = p.frac << (p.exp - DECOMPOSED_BINARY_POINT);
- } else {
- r = UINT64_MAX;
- }
- if (p.sign) {
- if (r <= -(uint64_t) min) {
- return -r;
- } else {
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return min;
- }
- } else {
- if (r <= max) {
- return r;
- } else {
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return max;
- }
- }
- default:
- g_assert_not_reached();
- }
+ float128_unpack_canonical(&p, a, s);
+ parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float128_params);
+ return float128_round_pack_canonical(&p, s);
}
+/*
+ * Floating-point to signed integer conversions
+ */
+
int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, INT8_MIN, INT8_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s);
}
int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, INT16_MIN, INT16_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s);
}
int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, INT32_MIN, INT32_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s);
}
int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, INT64_MIN, INT64_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s);
}
int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, INT16_MIN, INT16_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s);
}
int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, INT32_MIN, INT32_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s);
}
int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, INT64_MIN, INT64_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s);
}
int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, INT16_MIN, INT16_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s);
}
int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, INT32_MIN, INT32_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s);
}
int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_int_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, INT64_MIN, INT64_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s);
+}
+
+int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
+ float_status *s)
+{
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s);
+}
+
+static int32_t float128_to_int32_scalbn(float128 a, FloatRoundMode rmode,
+ int scale, float_status *s)
+{
+ FloatParts128 p;
+
+ float128_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s);
+}
+
+static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode,
+ int scale, float_status *s)
+{
+ FloatParts128 p;
+
+ float128_unpack_canonical(&p, a, s);
+ return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s);
}
int8_t float16_to_int8(float16 a, float_status *s)
@@ -2360,6 +2550,16 @@ int64_t float64_to_int64(float64 a, float_status *s)
return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
}
+int32_t float128_to_int32(float128 a, float_status *s)
+{
+ return float128_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
+int64_t float128_to_int64(float128 a, float_status *s)
+{
+ return float128_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
+}
+
int16_t float16_to_int16_round_to_zero(float16 a, float_status *s)
{
return float16_to_int16_scalbn(a, float_round_to_zero, 0, s);
@@ -2405,30 +2605,14 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
return float64_to_int64_scalbn(a, float_round_to_zero, 0, s);
}
-/*
- * Returns the result of converting the floating-point value `a' to
- * the two's complement integer format.
- */
-
-int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
- float_status *s)
-{
- return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, INT16_MIN, INT16_MAX, s);
-}
-
-int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
- float_status *s)
+int32_t float128_to_int32_round_to_zero(float128 a, float_status *s)
{
- return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, INT32_MIN, INT32_MAX, s);
+ return float128_to_int32_scalbn(a, float_round_to_zero, 0, s);
}
-int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale,
- float_status *s)
+int64_t float128_to_int64_round_to_zero(float128 a, float_status *s)
{
- return round_to_int_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, INT64_MIN, INT64_MAX, s);
+ return float128_to_int64_scalbn(a, float_round_to_zero, 0, s);
}
int16_t bfloat16_to_int16(bfloat16 a, float_status *s)
@@ -2474,121 +2658,149 @@ int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s)
* flag.
*/
-static uint64_t round_to_uint_and_pack(FloatParts in, FloatRoundMode rmode,
+static uint64_t round_to_uint_and_pack(FloatParts64 p, FloatRoundMode rmode,
int scale, uint64_t max,
float_status *s)
{
- int orig_flags = get_float_exception_flags(s);
- FloatParts p = round_to_int(in, rmode, scale, s);
+ int flags = 0;
uint64_t r;
switch (p.cls) {
case float_class_snan:
case float_class_qnan:
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return max;
+ flags = float_flag_invalid;
+ r = max;
+ break;
+
case float_class_inf:
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return p.sign ? 0 : max;
+ flags = float_flag_invalid;
+ r = p.sign ? 0 : max;
+ break;
+
case float_class_zero:
return 0;
+
case float_class_normal:
- if (p.sign) {
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return 0;
+ /* TODO: 62 = N - 2, frac_size for rounding */
+ if (parts_round_to_int_normal(&p, rmode, scale, 62)) {
+ flags = float_flag_inexact;
+ if (p.cls == float_class_zero) {
+ r = 0;
+ break;
+ }
}
- if (p.exp < DECOMPOSED_BINARY_POINT) {
- r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp);
- } else if (p.exp - DECOMPOSED_BINARY_POINT < 2) {
- r = p.frac << (p.exp - DECOMPOSED_BINARY_POINT);
+ if (p.sign) {
+ flags = float_flag_invalid;
+ r = 0;
+ } else if (p.exp > DECOMPOSED_BINARY_POINT) {
+ flags = float_flag_invalid;
+ r = max;
} else {
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return max;
+ r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp);
+ if (r > max) {
+ flags = float_flag_invalid;
+ r = max;
+ }
}
+ break;
- /* For uint64 this will never trip, but if p.exp is too large
- * to shift a decomposed fraction we shall have exited via the
- * 3rd leg above.
- */
- if (r > max) {
- s->float_exception_flags = orig_flags | float_flag_invalid;
- return max;
- }
- return r;
default:
g_assert_not_reached();
}
+
+ float_raise(flags, s);
+ return r;
}
uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, UINT8_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT8_MAX, s);
}
uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, UINT16_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s);
}
uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, UINT32_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s);
}
uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float16_unpack_canonical(a, s),
- rmode, scale, UINT64_MAX, s);
+ FloatParts64 p;
+
+ float16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s);
}
uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, UINT16_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s);
}
uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, UINT32_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s);
}
uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float32_unpack_canonical(a, s),
- rmode, scale, UINT64_MAX, s);
+ FloatParts64 p;
+
+ float32_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s);
}
uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, UINT16_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s);
}
uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, UINT32_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s);
}
uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale,
float_status *s)
{
- return round_to_uint_and_pack(float64_unpack_canonical(a, s),
- rmode, scale, UINT64_MAX, s);
+ FloatParts64 p;
+
+ float64_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s);
}
uint8_t float16_to_uint8(float16 a, float_status *s)
@@ -2694,22 +2906,28 @@ uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode,
int scale, float_status *s)
{
- return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, UINT16_MAX, s);
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s);
}
uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode,
int scale, float_status *s)
{
- return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, UINT32_MAX, s);
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s);
}
uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode,
int scale, float_status *s)
{
- return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s),
- rmode, scale, UINT64_MAX, s);
+ FloatParts64 p;
+
+ bfloat16_unpack_canonical(&p, a, s);
+ return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s);
}
uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s)
@@ -2750,9 +2968,9 @@ uint64_t bfloat16_to_uint64_round_to_zero(bfloat16 a, float_status *s)
* to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*/
-static FloatParts int_to_float(int64_t a, int scale, float_status *status)
+static FloatParts64 int_to_float(int64_t a, int scale, float_status *status)
{
- FloatParts r = { .sign = false };
+ FloatParts64 r = { .sign = false };
if (a == 0) {
r.cls = float_class_zero;
@@ -2765,11 +2983,11 @@ static FloatParts int_to_float(int64_t a, int scale, float_status *status)
f = -f;
r.sign = true;
}
- shift = clz64(f) - 1;
+ shift = clz64(f);
scale = MIN(MAX(scale, -0x10000), 0x10000);
r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
- r.frac = (shift < 0 ? DECOMPOSED_IMPLICIT_BIT : f << shift);
+ r.frac = f << shift;
}
return r;
@@ -2777,8 +2995,8 @@ static FloatParts int_to_float(int64_t a, int scale, float_status *status)
float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, scale, status);
- return float16_round_pack_canonical(pa, status);
+ FloatParts64 pa = int_to_float(a, scale, status);
+ return float16_round_pack_canonical(&pa, status);
}
float16 int32_to_float16_scalbn(int32_t a, int scale, float_status *status)
@@ -2813,8 +3031,8 @@ float16 int8_to_float16(int8_t a, float_status *status)
float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, scale, status);
- return float32_round_pack_canonical(pa, status);
+ FloatParts64 pa = int_to_float(a, scale, status);
+ return float32_round_pack_canonical(&pa, status);
}
float32 int32_to_float32_scalbn(int32_t a, int scale, float_status *status)
@@ -2844,8 +3062,8 @@ float32 int16_to_float32(int16_t a, float_status *status)
float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, scale, status);
- return float64_round_pack_canonical(pa, status);
+ FloatParts64 pa = int_to_float(a, scale, status);
+ return float64_round_pack_canonical(&pa, status);
}
float64 int32_to_float64_scalbn(int32_t a, int scale, float_status *status)
@@ -2880,8 +3098,8 @@ float64 int16_to_float64(int16_t a, float_status *status)
bfloat16 int64_to_bfloat16_scalbn(int64_t a, int scale, float_status *status)
{
- FloatParts pa = int_to_float(a, scale, status);
- return bfloat16_round_pack_canonical(pa, status);
+ FloatParts64 pa = int_to_float(a, scale, status);
+ return bfloat16_round_pack_canonical(&pa, status);
}
bfloat16 int32_to_bfloat16_scalbn(int32_t a, int scale, float_status *status)
@@ -2917,24 +3135,19 @@ bfloat16 int16_to_bfloat16(int16_t a, float_status *status)
* IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*/
-static FloatParts uint_to_float(uint64_t a, int scale, float_status *status)
+static FloatParts64 uint_to_float(uint64_t a, int scale, float_status *status)
{
- FloatParts r = { .sign = false };
+ FloatParts64 r = { .sign = false };
+ int shift;
if (a == 0) {
r.cls = float_class_zero;
} else {
scale = MIN(MAX(scale, -0x10000), 0x10000);
+ shift = clz64(a);
r.cls = float_class_normal;
- if ((int64_t)a < 0) {
- r.exp = DECOMPOSED_BINARY_POINT + 1 + scale;
- shift64RightJamming(a, 1, &a);
- r.frac = a;
- } else {
- int shift = clz64(a) - 1;
- r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
- r.frac = a << shift;
- }
+ r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
+ r.frac = a << shift;
}
return r;
@@ -2942,8 +3155,8 @@ static FloatParts uint_to_float(uint64_t a, int scale, float_status *status)
float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, scale, status);
- return float16_round_pack_canonical(pa, status);
+ FloatParts64 pa = uint_to_float(a, scale, status);
+ return float16_round_pack_canonical(&pa, status);
}
float16 uint32_to_float16_scalbn(uint32_t a, int scale, float_status *status)
@@ -2978,8 +3191,8 @@ float16 uint8_to_float16(uint8_t a, float_status *status)
float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, scale, status);
- return float32_round_pack_canonical(pa, status);
+ FloatParts64 pa = uint_to_float(a, scale, status);
+ return float32_round_pack_canonical(&pa, status);
}
float32 uint32_to_float32_scalbn(uint32_t a, int scale, float_status *status)
@@ -3009,8 +3222,8 @@ float32 uint16_to_float32(uint16_t a, float_status *status)
float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, scale, status);
- return float64_round_pack_canonical(pa, status);
+ FloatParts64 pa = uint_to_float(a, scale, status);
+ return float64_round_pack_canonical(&pa, status);
}
float64 uint32_to_float64_scalbn(uint32_t a, int scale, float_status *status)
@@ -3045,8 +3258,8 @@ float64 uint16_to_float64(uint16_t a, float_status *status)
bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int scale, float_status *status)
{
- FloatParts pa = uint_to_float(a, scale, status);
- return bfloat16_round_pack_canonical(pa, status);
+ FloatParts64 pa = uint_to_float(a, scale, status);
+ return bfloat16_round_pack_canonical(&pa, status);
}
bfloat16 uint32_to_bfloat16_scalbn(uint32_t a, int scale, float_status *status)
@@ -3090,7 +3303,7 @@ bfloat16 uint16_to_bfloat16(uint16_t a, float_status *status)
* minnummag() and maxnummag() functions correspond to minNumMag()
* and minNumMag() from the IEEE-754 2008.
*/
-static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin,
+static FloatParts64 minmax_floats(FloatParts64 a, FloatParts64 b, bool ismin,
bool ieee, bool ismag, float_status *s)
{
if (unlikely(is_nan(a.cls) || is_nan(b.cls))) {
@@ -3101,14 +3314,14 @@ static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin,
* the invalid exception is raised.
*/
if (is_snan(a.cls) || is_snan(b.cls)) {
- return pick_nan(a, b, s);
+ return *parts_pick_nan(&a, &b, s);
} else if (is_nan(a.cls) && !is_nan(b.cls)) {
return b;
} else if (is_nan(b.cls) && !is_nan(a.cls)) {
return a;
}
}
- return pick_nan(a, b, s);
+ return *parts_pick_nan(&a, &b, s);
} else {
int a_exp, b_exp;
@@ -3165,11 +3378,11 @@ static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin,
float ## sz float ## sz ## _ ## name(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); \
- FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \
- \
- return float ## sz ## _round_pack_canonical(pr, s); \
+ FloatParts64 pa, pb, pr; \
+ float ## sz ## _unpack_canonical(&pa, a, s); \
+ float ## sz ## _unpack_canonical(&pb, b, s); \
+ pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \
+ return float ## sz ## _round_pack_canonical(&pr, s); \
}
MINMAX(16, min, true, false, false)
@@ -3198,11 +3411,11 @@ MINMAX(64, maxnummag, false, true, true)
#define BF16_MINMAX(name, ismin, isiee, ismag) \
bfloat16 bfloat16_ ## name(bfloat16 a, bfloat16 b, float_status *s) \
{ \
- FloatParts pa = bfloat16_unpack_canonical(a, s); \
- FloatParts pb = bfloat16_unpack_canonical(b, s); \
- FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \
- \
- return bfloat16_round_pack_canonical(pr, s); \
+ FloatParts64 pa, pb, pr; \
+ bfloat16_unpack_canonical(&pa, a, s); \
+ bfloat16_unpack_canonical(&pb, b, s); \
+ pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \
+ return bfloat16_round_pack_canonical(&pr, s); \
}
BF16_MINMAX(min, true, false, false)
@@ -3215,14 +3428,14 @@ BF16_MINMAX(maxnummag, false, true, true)
#undef BF16_MINMAX
/* Floating point compare */
-static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet,
+static FloatRelation compare_floats(FloatParts64 a, FloatParts64 b, bool is_quiet,
float_status *s)
{
if (is_nan(a.cls) || is_nan(b.cls)) {
if (!is_quiet ||
a.cls == float_class_snan ||
b.cls == float_class_snan) {
- s->float_exception_flags |= float_flag_invalid;
+ float_raise(float_flag_invalid, s);
}
return float_relation_unordered;
}
@@ -3276,8 +3489,9 @@ static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet,
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); \
+ FloatParts64 pa, pb; \
+ float ## sz ## _unpack_canonical(&pa, a, s); \
+ float ## sz ## _unpack_canonical(&pb, b, s); \
return compare_floats(pa, pb, is_quiet, s); \
}
@@ -3378,8 +3592,10 @@ FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s)
static FloatRelation QEMU_FLATTEN
soft_bf16_compare(bfloat16 a, bfloat16 b, bool is_quiet, float_status *s)
{
- FloatParts pa = bfloat16_unpack_canonical(a, s);
- FloatParts pb = bfloat16_unpack_canonical(b, s);
+ FloatParts64 pa, pb;
+
+ bfloat16_unpack_canonical(&pa, a, s);
+ bfloat16_unpack_canonical(&pb, b, s);
return compare_floats(pa, pb, is_quiet, s);
}
@@ -3394,16 +3610,16 @@ FloatRelation bfloat16_compare_quiet(bfloat16 a, bfloat16 b, float_status *s)
}
/* Multiply A by 2 raised to the power N. */
-static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s)
+static FloatParts64 scalbn_decomposed(FloatParts64 a, int n, float_status *s)
{
if (unlikely(is_nan(a.cls))) {
- return return_nan(a, s);
+ parts_return_nan(&a, s);
}
if (a.cls == float_class_normal) {
- /* The largest float type (even though not supported by FloatParts)
+ /* The largest float type (even though not supported by FloatParts64)
* is float128, which has a 15 bit exponent. Bounding N to 16 bits
* still allows rounding to infinity, without allowing overflow
- * within the int32_t that backs FloatParts.exp.
+ * within the int32_t that backs FloatParts64.exp.
*/
n = MIN(MAX(n, -0x10000), 0x10000);
a.exp += n;
@@ -3413,30 +3629,38 @@ static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s)
float16 float16_scalbn(float16 a, int n, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pr = scalbn_decomposed(pa, n, status);
- return float16_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ pr = scalbn_decomposed(pa, n, status);
+ return float16_round_pack_canonical(&pr, status);
}
float32 float32_scalbn(float32 a, int n, float_status *status)
{
- FloatParts pa = float32_unpack_canonical(a, status);
- FloatParts pr = scalbn_decomposed(pa, n, status);
- return float32_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ pr = scalbn_decomposed(pa, n, status);
+ return float32_round_pack_canonical(&pr, status);
}
float64 float64_scalbn(float64 a, int n, float_status *status)
{
- FloatParts pa = float64_unpack_canonical(a, status);
- FloatParts pr = scalbn_decomposed(pa, n, status);
- return float64_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ pr = scalbn_decomposed(pa, n, status);
+ return float64_round_pack_canonical(&pr, status);
}
bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pr = scalbn_decomposed(pa, n, status);
- return bfloat16_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ pr = scalbn_decomposed(pa, n, status);
+ return bfloat16_round_pack_canonical(&pr, status);
}
/*
@@ -3451,20 +3675,22 @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status)
* especially for 64 bit floats.
*/
-static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
+static FloatParts64 sqrt_float(FloatParts64 a, float_status *s, const FloatFmt *p)
{
uint64_t a_frac, r_frac, s_frac;
int bit, last_bit;
if (is_nan(a.cls)) {
- return return_nan(a, s);
+ parts_return_nan(&a, s);
+ return a;
}
if (a.cls == float_class_zero) {
return a; /* sqrt(+-0) = +-0 */
}
if (a.sign) {
- s->float_exception_flags |= float_flag_invalid;
- return parts_default_nan(s);
+ float_raise(float_flag_invalid, s);
+ parts_default_nan(&a, s);
+ return a;
}
if (a.cls == float_class_inf) {
return a; /* sqrt(+inf) = +inf */
@@ -3475,12 +3701,9 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
/* We need two overflow bits at the top. Adding room for that is a
* right shift. If the exponent is odd, we can discard the low bit
* by multiplying the fraction by 2; that's a left shift. Combine
- * those and we shift right if the exponent is even.
+ * those and we shift right by 1 if the exponent is odd, otherwise 2.
*/
- a_frac = a.frac;
- if (!(a.exp & 1)) {
- a_frac >>= 1;
- }
+ a_frac = a.frac >> (2 - (a.exp & 1));
a.exp >>= 1;
/* Bit-by-bit computation of sqrt. */
@@ -3488,10 +3711,10 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
s_frac = 0;
/* Iterate from implicit bit down to the 3 extra bits to compute a
- * properly rounded result. Remember we've inserted one more bit
- * at the top, so these positions are one less.
+ * properly rounded result. Remember we've inserted two more bits
+ * at the top, so these positions are two less.
*/
- bit = DECOMPOSED_BINARY_POINT - 1;
+ bit = DECOMPOSED_BINARY_POINT - 2;
last_bit = MAX(p->frac_shift - 4, 0);
do {
uint64_t q = 1ULL << bit;
@@ -3507,32 +3730,38 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p)
/* Undo the right shift done above. If there is any remaining
* fraction, the result is inexact. Set the sticky bit.
*/
- a.frac = (r_frac << 1) + (a_frac != 0);
+ a.frac = (r_frac << 2) + (a_frac != 0);
return a;
}
float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status)
{
- FloatParts pa = float16_unpack_canonical(a, status);
- FloatParts pr = sqrt_float(pa, status, &float16_params);
- return float16_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ float16_unpack_canonical(&pa, a, status);
+ pr = sqrt_float(pa, status, &float16_params);
+ return float16_round_pack_canonical(&pr, 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);
+ FloatParts64 pa, pr;
+
+ float32_unpack_canonical(&pa, a, status);
+ pr = sqrt_float(pa, status, &float32_params);
+ return float32_round_pack_canonical(&pr, 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);
+ FloatParts64 pa, pr;
+
+ float64_unpack_canonical(&pa, a, status);
+ pr = sqrt_float(pa, status, &float64_params);
+ return float64_round_pack_canonical(&pr, status);
}
float32 QEMU_FLATTEN float32_sqrt(float32 xa, float_status *s)
@@ -3591,9 +3820,11 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s)
bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status)
{
- FloatParts pa = bfloat16_unpack_canonical(a, status);
- FloatParts pr = sqrt_float(pa, status, &bfloat16_params);
- return bfloat16_round_pack_canonical(pr, status);
+ FloatParts64 pa, pr;
+
+ bfloat16_unpack_canonical(&pa, a, status);
+ pr = sqrt_float(pa, status, &bfloat16_params);
+ return bfloat16_round_pack_canonical(&pr, status);
}
/*----------------------------------------------------------------------------
@@ -3602,47 +3833,47 @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status)
float16 float16_default_nan(float_status *status)
{
- FloatParts p = parts_default_nan(status);
+ FloatParts64 p;
+
+ parts_default_nan(&p, status);
p.frac >>= float16_params.frac_shift;
- return float16_pack_raw(p);
+ return float16_pack_raw(&p);
}
float32 float32_default_nan(float_status *status)
{
- FloatParts p = parts_default_nan(status);
+ FloatParts64 p;
+
+ parts_default_nan(&p, status);
p.frac >>= float32_params.frac_shift;
- return float32_pack_raw(p);
+ return float32_pack_raw(&p);
}
float64 float64_default_nan(float_status *status)
{
- FloatParts p = parts_default_nan(status);
+ FloatParts64 p;
+
+ parts_default_nan(&p, status);
p.frac >>= float64_params.frac_shift;
- return float64_pack_raw(p);
+ return float64_pack_raw(&p);
}
float128 float128_default_nan(float_status *status)
{
- FloatParts p = parts_default_nan(status);
- float128 r;
+ FloatParts128 p;
- /* Extrapolate from the choices made by parts_default_nan to fill
- * in the quad-floating format. If the low bit is set, assume we
- * want to set all non-snan bits.
- */
- r.low = -(p.frac & 1);
- r.high = p.frac >> (DECOMPOSED_BINARY_POINT - 48);
- r.high |= UINT64_C(0x7FFF000000000000);
- r.high |= (uint64_t)p.sign << 63;
-
- return r;
+ parts_default_nan(&p, status);
+ frac_shr(&p, float128_params.frac_shift);
+ return float128_pack_raw(&p);
}
bfloat16 bfloat16_default_nan(float_status *status)
{
- FloatParts p = parts_default_nan(status);
+ FloatParts64 p;
+
+ parts_default_nan(&p, status);
p.frac >>= bfloat16_params.frac_shift;
- return bfloat16_pack_raw(p);
+ return bfloat16_pack_raw(&p);
}
/*----------------------------------------------------------------------------
@@ -3651,38 +3882,57 @@ bfloat16 bfloat16_default_nan(float_status *status)
float16 float16_silence_nan(float16 a, float_status *status)
{
- FloatParts p = float16_unpack_raw(a);
+ FloatParts64 p;
+
+ float16_unpack_raw(&p, a);
p.frac <<= float16_params.frac_shift;
- p = parts_silence_nan(p, status);
+ parts_silence_nan(&p, status);
p.frac >>= float16_params.frac_shift;
- return float16_pack_raw(p);
+ return float16_pack_raw(&p);
}
float32 float32_silence_nan(float32 a, float_status *status)
{
- FloatParts p = float32_unpack_raw(a);
+ FloatParts64 p;
+
+ float32_unpack_raw(&p, a);
p.frac <<= float32_params.frac_shift;
- p = parts_silence_nan(p, status);
+ parts_silence_nan(&p, status);
p.frac >>= float32_params.frac_shift;
- return float32_pack_raw(p);
+ return float32_pack_raw(&p);
}
float64 float64_silence_nan(float64 a, float_status *status)
{
- FloatParts p = float64_unpack_raw(a);
+ FloatParts64 p;
+
+ float64_unpack_raw(&p, a);
p.frac <<= float64_params.frac_shift;
- p = parts_silence_nan(p, status);
+ parts_silence_nan(&p, status);
p.frac >>= float64_params.frac_shift;
- return float64_pack_raw(p);
+ return float64_pack_raw(&p);
}
bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status)
{
- FloatParts p = bfloat16_unpack_raw(a);
+ FloatParts64 p;
+
+ bfloat16_unpack_raw(&p, a);
p.frac <<= bfloat16_params.frac_shift;
- p = parts_silence_nan(p, status);
+ parts_silence_nan(&p, status);
p.frac >>= bfloat16_params.frac_shift;
- return bfloat16_pack_raw(p);
+ return bfloat16_pack_raw(&p);
+}
+
+float128 float128_silence_nan(float128 a, float_status *status)
+{
+ FloatParts128 p;
+
+ float128_unpack_raw(&p, a);
+ frac_shl(&p, float128_params.frac_shift);
+ parts_silence_nan(&p, status);
+ frac_shr(&p, float128_params.frac_shift);
+ return float128_pack_raw(&p);
}
/*----------------------------------------------------------------------------
@@ -3690,7 +3940,7 @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status)
| input-denormal exception and return zero. Otherwise just return the value.
*----------------------------------------------------------------------------*/
-static bool parts_squash_denormal(FloatParts p, float_status *status)
+static bool parts_squash_denormal(FloatParts64 p, float_status *status)
{
if (p.exp == 0 && p.frac != 0) {
float_raise(float_flag_input_denormal, status);
@@ -3703,7 +3953,9 @@ static bool parts_squash_denormal(FloatParts p, float_status *status)
float16 float16_squash_input_denormal(float16 a, float_status *status)
{
if (status->flush_inputs_to_zero) {
- FloatParts p = float16_unpack_raw(a);
+ FloatParts64 p;
+
+ float16_unpack_raw(&p, a);
if (parts_squash_denormal(p, status)) {
return float16_set_sign(float16_zero, p.sign);
}
@@ -3714,7 +3966,9 @@ float16 float16_squash_input_denormal(float16 a, float_status *status)
float32 float32_squash_input_denormal(float32 a, float_status *status)
{
if (status->flush_inputs_to_zero) {
- FloatParts p = float32_unpack_raw(a);
+ FloatParts64 p;
+
+ float32_unpack_raw(&p, a);
if (parts_squash_denormal(p, status)) {
return float32_set_sign(float32_zero, p.sign);
}
@@ -3725,7 +3979,9 @@ float32 float32_squash_input_denormal(float32 a, float_status *status)
float64 float64_squash_input_denormal(float64 a, float_status *status)
{
if (status->flush_inputs_to_zero) {
- FloatParts p = float64_unpack_raw(a);
+ FloatParts64 p;
+
+ float64_unpack_raw(&p, a);
if (parts_squash_denormal(p, status)) {
return float64_set_sign(float64_zero, p.sign);
}
@@ -3736,7 +3992,9 @@ float64 float64_squash_input_denormal(float64 a, float_status *status)
bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status)
{
if (status->flush_inputs_to_zero) {
- FloatParts p = bfloat16_unpack_raw(a);
+ FloatParts64 p;
+
+ bfloat16_unpack_raw(&p, a);
if (parts_squash_denormal(p, status)) {
return bfloat16_set_sign(bfloat16_zero, p.sign);
}
@@ -3797,7 +4055,7 @@ static int32_t roundAndPackInt32(bool zSign, uint64_t absZ,
return zSign ? INT32_MIN : INT32_MAX;
}
if (roundBits) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return z;
@@ -3859,7 +4117,7 @@ static int64_t roundAndPackInt64(bool zSign, uint64_t absZ0, uint64_t absZ1,
return zSign ? INT64_MIN : INT64_MAX;
}
if (absZ1) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return z;
@@ -3920,7 +4178,7 @@ static int64_t roundAndPackUint64(bool zSign, uint64_t absZ0,
}
if (absZ1) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return absZ0;
}
@@ -4031,7 +4289,7 @@ static float32 roundAndPackFloat32(bool zSign, int zExp, uint32_t zSig,
}
}
if (roundBits) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
zSig = ( zSig + roundIncrement )>>7;
if (!(roundBits ^ 0x40) && roundNearestEven) {
@@ -4187,7 +4445,7 @@ static float64 roundAndPackFloat64(bool zSign, int zExp, uint64_t zSig,
}
}
if (roundBits) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
zSig = ( zSig + roundIncrement )>>10;
if (!(roundBits ^ 0x200) && roundNearestEven) {
@@ -4321,7 +4579,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign,
float_raise(float_flag_underflow, status);
}
if (roundBits) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
zSig0 += roundIncrement;
if ( (int64_t) zSig0 < 0 ) zExp = 1;
@@ -4334,7 +4592,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign,
}
}
if (roundBits) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
zSig0 += roundIncrement;
if ( zSig0 < roundIncrement ) {
@@ -4397,7 +4655,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign,
float_raise(float_flag_underflow, status);
}
if (zSig1) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
switch (roundingMode) {
case float_round_nearest_even:
@@ -4427,7 +4685,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign,
}
}
if (zSig1) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
if ( increment ) {
++zSig0;
@@ -4704,7 +4962,7 @@ static float128 roundAndPackFloat128(bool zSign, int32_t zExp,
}
}
if (zSig2) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
if ( increment ) {
add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
@@ -4906,38 +5164,6 @@ floatx80 float32_to_floatx80(float32 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Returns the result of converting the single-precision floating-point value
-| `a' to the double-precision floating-point format. The conversion is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float32_to_float128(float32 a, float_status *status)
-{
- bool aSign;
- int aExp;
- uint32_t aSig;
-
- a = float32_squash_input_denormal(a, status);
- aSig = extractFloat32Frac( a );
- aExp = extractFloat32Exp( a );
- aSign = extractFloat32Sign( a );
- if ( aExp == 0xFF ) {
- if (aSig) {
- return commonNaNToFloat128(float32ToCommonNaN(a, status), status);
- }
- return packFloat128( aSign, 0x7FFF, 0, 0 );
- }
- if ( aExp == 0 ) {
- if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
- normalizeFloat32Subnormal( aSig, &aExp, &aSig );
- --aExp;
- }
- return packFloat128( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<25, 0 );
-
-}
-
-/*----------------------------------------------------------------------------
| Returns the remainder of the single-precision floating-point value `a'
| with respect to the corresponding value `b'. The operation is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -5211,40 +5437,6 @@ floatx80 float64_to_floatx80(float64 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Returns the result of converting the double-precision floating-point value
-| `a' to the quadruple-precision floating-point format. The conversion is
-| performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float64_to_float128(float64 a, float_status *status)
-{
- bool aSign;
- int aExp;
- uint64_t aSig, zSig0, zSig1;
-
- a = float64_squash_input_denormal(a, status);
- aSig = extractFloat64Frac( a );
- aExp = extractFloat64Exp( a );
- aSign = extractFloat64Sign( a );
- if ( aExp == 0x7FF ) {
- if (aSig) {
- return commonNaNToFloat128(float64ToCommonNaN(a, status), status);
- }
- return packFloat128( aSign, 0x7FFF, 0, 0 );
- }
- if ( aExp == 0 ) {
- if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
- normalizeFloat64Subnormal( aSig, &aExp, &aSig );
- --aExp;
- }
- shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
- return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
-
-}
-
-
-/*----------------------------------------------------------------------------
| Returns the remainder of the double-precision floating-point value `a'
| with respect to the corresponding value `b'. The operation is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
@@ -5442,7 +5634,7 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status)
}
else if ( aExp < 0x3FFF ) {
if (aExp || aSig) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return 0;
}
@@ -5457,7 +5649,7 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status)
return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF;
}
if ( ( aSig<<shiftCount ) != savedASig ) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return z;
@@ -5541,13 +5733,13 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status)
}
else if ( aExp < 0x3FFF ) {
if (aExp | aSig) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return 0;
}
z = aSig>>( - shiftCount );
if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
if ( aSign ) z = - z;
return z;
@@ -5698,7 +5890,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
&& ( (uint64_t) ( extractFloatx80Frac( a ) ) == 0 ) ) {
return a;
}
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
aSign = extractFloatx80Sign( a );
switch (status->float_rounding_mode) {
case float_round_nearest_even:
@@ -5765,7 +5957,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
z.low = UINT64_C(0x8000000000000000);
}
if (z.low != a.low) {
- status->float_exception_flags |= float_flag_inexact;
+ float_raise(float_flag_inexact, status);
}
return z;
@@ -6345,191 +6537,6 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the 32-bit two's complement integer format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic---which means in particular that the conversion is rounded
-| according to the current rounding mode. If `a' is a NaN, the largest
-| positive integer is returned. Otherwise, if the conversion overflows, the
-| largest integer with the same sign as `a' is returned.
-*----------------------------------------------------------------------------*/
-
-int32_t float128_to_int32(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp, shiftCount;
- uint64_t aSig0, aSig1;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
- if ( aExp ) aSig0 |= UINT64_C(0x0001000000000000);
- aSig0 |= ( aSig1 != 0 );
- shiftCount = 0x4028 - aExp;
- if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
- return roundAndPackInt32(aSign, aSig0, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the 32-bit two's complement integer format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic, except that the conversion is always rounded toward zero. If
-| `a' is a NaN, the largest positive integer is returned. Otherwise, if the
-| conversion overflows, the largest integer with the same sign as `a' is
-| returned.
-*----------------------------------------------------------------------------*/
-
-int32_t float128_to_int32_round_to_zero(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp, shiftCount;
- uint64_t aSig0, aSig1, savedASig;
- int32_t z;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- aSig0 |= ( aSig1 != 0 );
- if ( 0x401E < aExp ) {
- if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
- goto invalid;
- }
- else if ( aExp < 0x3FFF ) {
- if (aExp || aSig0) {
- status->float_exception_flags |= float_flag_inexact;
- }
- return 0;
- }
- aSig0 |= UINT64_C(0x0001000000000000);
- shiftCount = 0x402F - aExp;
- savedASig = aSig0;
- aSig0 >>= shiftCount;
- z = aSig0;
- if ( aSign ) z = - z;
- if ( ( z < 0 ) ^ aSign ) {
- invalid:
- float_raise(float_flag_invalid, status);
- return aSign ? INT32_MIN : INT32_MAX;
- }
- if ( ( aSig0<<shiftCount ) != savedASig ) {
- status->float_exception_flags |= float_flag_inexact;
- }
- return z;
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the 64-bit two's complement integer format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic---which means in particular that the conversion is rounded
-| according to the current rounding mode. If `a' is a NaN, the largest
-| positive integer is returned. Otherwise, if the conversion overflows, the
-| largest integer with the same sign as `a' is returned.
-*----------------------------------------------------------------------------*/
-
-int64_t float128_to_int64(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp, shiftCount;
- uint64_t aSig0, aSig1;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- if ( aExp ) aSig0 |= UINT64_C(0x0001000000000000);
- shiftCount = 0x402F - aExp;
- if ( shiftCount <= 0 ) {
- if ( 0x403E < aExp ) {
- float_raise(float_flag_invalid, status);
- if ( ! aSign
- || ( ( aExp == 0x7FFF )
- && ( aSig1 || ( aSig0 != UINT64_C(0x0001000000000000) ) )
- )
- ) {
- return INT64_MAX;
- }
- return INT64_MIN;
- }
- shortShift128Left( aSig0, aSig1, - shiftCount, &aSig0, &aSig1 );
- }
- else {
- shift64ExtraRightJamming( aSig0, aSig1, shiftCount, &aSig0, &aSig1 );
- }
- return roundAndPackInt64(aSign, aSig0, aSig1, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the 64-bit two's complement integer format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic, except that the conversion is always rounded toward zero.
-| If `a' is a NaN, the largest positive integer is returned. Otherwise, if
-| the conversion overflows, the largest integer with the same sign as `a' is
-| returned.
-*----------------------------------------------------------------------------*/
-
-int64_t float128_to_int64_round_to_zero(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp, shiftCount;
- uint64_t aSig0, aSig1;
- int64_t z;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- if ( aExp ) aSig0 |= UINT64_C(0x0001000000000000);
- shiftCount = aExp - 0x402F;
- if ( 0 < shiftCount ) {
- if ( 0x403E <= aExp ) {
- aSig0 &= UINT64_C(0x0000FFFFFFFFFFFF);
- if ( ( a.high == UINT64_C(0xC03E000000000000) )
- && ( aSig1 < UINT64_C(0x0002000000000000) ) ) {
- if (aSig1) {
- status->float_exception_flags |= float_flag_inexact;
- }
- }
- else {
- float_raise(float_flag_invalid, status);
- if ( ! aSign || ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) ) {
- return INT64_MAX;
- }
- }
- return INT64_MIN;
- }
- z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
- if ( (uint64_t) ( aSig1<<shiftCount ) ) {
- status->float_exception_flags |= float_flag_inexact;
- }
- }
- else {
- if ( aExp < 0x3FFF ) {
- if ( aExp | aSig0 | aSig1 ) {
- status->float_exception_flags |= float_flag_inexact;
- }
- return 0;
- }
- z = aSig0>>( - shiftCount );
- if ( aSig1
- || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) {
- status->float_exception_flags |= float_flag_inexact;
- }
- }
- if ( aSign ) z = - z;
- return z;
-
-}
-
-/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point value
| `a' to the 64-bit unsigned integer format. The conversion is
| performed according to the IEC/IEEE Standard for Binary Floating-Point
@@ -6647,74 +6654,6 @@ uint32_t float128_to_uint32(float128 a, float_status *status)
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the single-precision floating-point format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float32 float128_to_float32(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp;
- uint64_t aSig0, aSig1;
- uint32_t zSig;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- if ( aExp == 0x7FFF ) {
- if ( aSig0 | aSig1 ) {
- return commonNaNToFloat32(float128ToCommonNaN(a, status), status);
- }
- return packFloat32( aSign, 0xFF, 0 );
- }
- aSig0 |= ( aSig1 != 0 );
- shift64RightJamming( aSig0, 18, &aSig0 );
- zSig = aSig0;
- if ( aExp || zSig ) {
- zSig |= 0x40000000;
- aExp -= 0x3F81;
- }
- return roundAndPackFloat32(aSign, aExp, zSig, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
-| value `a' to the double-precision floating-point format. The conversion
-| is performed according to the IEC/IEEE Standard for Binary Floating-Point
-| Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float64 float128_to_float64(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp;
- uint64_t aSig0, aSig1;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- if ( aExp == 0x7FFF ) {
- if ( aSig0 | aSig1 ) {
- return commonNaNToFloat64(float128ToCommonNaN(a, status), status);
- }
- return packFloat64( aSign, 0x7FF, 0 );
- }
- shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
- aSig0 |= ( aSig1 != 0 );
- if ( aExp || aSig0 ) {
- aSig0 |= UINT64_C(0x4000000000000000);
- aExp -= 0x3C01;
- }
- return roundAndPackFloat64(aSign, aExp, aSig0, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of converting the quadruple-precision floating-point
| value `a' to the extended double-precision floating-point format. The
| conversion is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
@@ -6752,536 +6691,6 @@ floatx80 float128_to_floatx80(float128 a, float_status *status)
}
/*----------------------------------------------------------------------------
-| Rounds the quadruple-precision floating-point value `a' to an integer, and
-| returns the result as a quadruple-precision floating-point value. The
-| operation is performed according to the IEC/IEEE Standard for Binary
-| Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float128_round_to_int(float128 a, float_status *status)
-{
- bool aSign;
- int32_t aExp;
- uint64_t lastBitMask, roundBitsMask;
- float128 z;
-
- aExp = extractFloat128Exp( a );
- if ( 0x402F <= aExp ) {
- if ( 0x406F <= aExp ) {
- if ( ( aExp == 0x7FFF )
- && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
- ) {
- return propagateFloat128NaN(a, a, status);
- }
- return a;
- }
- lastBitMask = 1;
- lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
- roundBitsMask = lastBitMask - 1;
- z = a;
- switch (status->float_rounding_mode) {
- case float_round_nearest_even:
- if ( lastBitMask ) {
- add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
- if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
- }
- else {
- if ( (int64_t) z.low < 0 ) {
- ++z.high;
- if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1;
- }
- }
- break;
- case float_round_ties_away:
- if (lastBitMask) {
- add128(z.high, z.low, 0, lastBitMask >> 1, &z.high, &z.low);
- } else {
- if ((int64_t) z.low < 0) {
- ++z.high;
- }
- }
- break;
- case float_round_to_zero:
- break;
- case float_round_up:
- if (!extractFloat128Sign(z)) {
- add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
- }
- break;
- case float_round_down:
- if (extractFloat128Sign(z)) {
- add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
- }
- break;
- case float_round_to_odd:
- /*
- * Note that if lastBitMask == 0, the last bit is the lsb
- * of high, and roundBitsMask == -1.
- */
- if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) {
- add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
- }
- break;
- default:
- abort();
- }
- z.low &= ~ roundBitsMask;
- }
- else {
- if ( aExp < 0x3FFF ) {
- if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
- status->float_exception_flags |= float_flag_inexact;
- aSign = extractFloat128Sign( a );
- switch (status->float_rounding_mode) {
- case float_round_nearest_even:
- if ( ( aExp == 0x3FFE )
- && ( extractFloat128Frac0( a )
- | extractFloat128Frac1( a ) )
- ) {
- return packFloat128( aSign, 0x3FFF, 0, 0 );
- }
- break;
- case float_round_ties_away:
- if (aExp == 0x3FFE) {
- return packFloat128(aSign, 0x3FFF, 0, 0);
- }
- break;
- case float_round_down:
- return
- aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
- : packFloat128( 0, 0, 0, 0 );
- case float_round_up:
- return
- aSign ? packFloat128( 1, 0, 0, 0 )
- : packFloat128( 0, 0x3FFF, 0, 0 );
-
- case float_round_to_odd:
- return packFloat128(aSign, 0x3FFF, 0, 0);
-
- case float_round_to_zero:
- break;
- }
- return packFloat128( aSign, 0, 0, 0 );
- }
- lastBitMask = 1;
- lastBitMask <<= 0x402F - aExp;
- roundBitsMask = lastBitMask - 1;
- z.low = 0;
- z.high = a.high;
- switch (status->float_rounding_mode) {
- case float_round_nearest_even:
- z.high += lastBitMask>>1;
- if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
- z.high &= ~ lastBitMask;
- }
- break;
- case float_round_ties_away:
- z.high += lastBitMask>>1;
- break;
- case float_round_to_zero:
- break;
- case float_round_up:
- if (!extractFloat128Sign(z)) {
- z.high |= ( a.low != 0 );
- z.high += roundBitsMask;
- }
- break;
- case float_round_down:
- if (extractFloat128Sign(z)) {
- z.high |= (a.low != 0);
- z.high += roundBitsMask;
- }
- break;
- case float_round_to_odd:
- if ((z.high & lastBitMask) == 0) {
- z.high |= (a.low != 0);
- z.high += roundBitsMask;
- }
- break;
- default:
- abort();
- }
- z.high &= ~ roundBitsMask;
- }
- if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
- status->float_exception_flags |= float_flag_inexact;
- }
- return z;
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of adding the absolute values of the quadruple-precision
-| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
-| before being returned. `zSign' is ignored if the result is a NaN.
-| The addition is performed according to the IEC/IEEE Standard for Binary
-| Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-static float128 addFloat128Sigs(float128 a, float128 b, bool zSign,
- float_status *status)
-{
- int32_t aExp, bExp, zExp;
- uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
- int32_t expDiff;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- bSig1 = extractFloat128Frac1( b );
- bSig0 = extractFloat128Frac0( b );
- bExp = extractFloat128Exp( b );
- expDiff = aExp - bExp;
- if ( 0 < expDiff ) {
- if ( aExp == 0x7FFF ) {
- if (aSig0 | aSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- return a;
- }
- if ( bExp == 0 ) {
- --expDiff;
- }
- else {
- bSig0 |= UINT64_C(0x0001000000000000);
- }
- shift128ExtraRightJamming(
- bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
- zExp = aExp;
- }
- else if ( expDiff < 0 ) {
- if ( bExp == 0x7FFF ) {
- if (bSig0 | bSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- return packFloat128( zSign, 0x7FFF, 0, 0 );
- }
- if ( aExp == 0 ) {
- ++expDiff;
- }
- else {
- aSig0 |= UINT64_C(0x0001000000000000);
- }
- shift128ExtraRightJamming(
- aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
- zExp = bExp;
- }
- else {
- if ( aExp == 0x7FFF ) {
- if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
- return propagateFloat128NaN(a, b, status);
- }
- return a;
- }
- add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
- if ( aExp == 0 ) {
- if (status->flush_to_zero) {
- if (zSig0 | zSig1) {
- float_raise(float_flag_output_denormal, status);
- }
- return packFloat128(zSign, 0, 0, 0);
- }
- return packFloat128( zSign, 0, zSig0, zSig1 );
- }
- zSig2 = 0;
- zSig0 |= UINT64_C(0x0002000000000000);
- zExp = aExp;
- goto shiftRight1;
- }
- aSig0 |= UINT64_C(0x0001000000000000);
- add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
- --zExp;
- if ( zSig0 < UINT64_C(0x0002000000000000) ) goto roundAndPack;
- ++zExp;
- shiftRight1:
- shift128ExtraRightJamming(
- zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
- roundAndPack:
- return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of subtracting the absolute values of the quadruple-
-| precision floating-point values `a' and `b'. If `zSign' is 1, the
-| difference is negated before being returned. `zSign' is ignored if the
-| result is a NaN. The subtraction is performed according to the IEC/IEEE
-| Standard for Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-static float128 subFloat128Sigs(float128 a, float128 b, bool zSign,
- float_status *status)
-{
- int32_t aExp, bExp, zExp;
- uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
- int32_t expDiff;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- bSig1 = extractFloat128Frac1( b );
- bSig0 = extractFloat128Frac0( b );
- bExp = extractFloat128Exp( b );
- expDiff = aExp - bExp;
- shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
- shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
- if ( 0 < expDiff ) goto aExpBigger;
- if ( expDiff < 0 ) goto bExpBigger;
- if ( aExp == 0x7FFF ) {
- if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
- return propagateFloat128NaN(a, b, status);
- }
- float_raise(float_flag_invalid, status);
- return float128_default_nan(status);
- }
- if ( aExp == 0 ) {
- aExp = 1;
- bExp = 1;
- }
- if ( bSig0 < aSig0 ) goto aBigger;
- if ( aSig0 < bSig0 ) goto bBigger;
- if ( bSig1 < aSig1 ) goto aBigger;
- if ( aSig1 < bSig1 ) goto bBigger;
- return packFloat128(status->float_rounding_mode == float_round_down,
- 0, 0, 0);
- bExpBigger:
- if ( bExp == 0x7FFF ) {
- if (bSig0 | bSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
- }
- if ( aExp == 0 ) {
- ++expDiff;
- }
- else {
- aSig0 |= UINT64_C(0x4000000000000000);
- }
- shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
- bSig0 |= UINT64_C(0x4000000000000000);
- bBigger:
- sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
- zExp = bExp;
- zSign ^= 1;
- goto normalizeRoundAndPack;
- aExpBigger:
- if ( aExp == 0x7FFF ) {
- if (aSig0 | aSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- return a;
- }
- if ( bExp == 0 ) {
- --expDiff;
- }
- else {
- bSig0 |= UINT64_C(0x4000000000000000);
- }
- shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
- aSig0 |= UINT64_C(0x4000000000000000);
- aBigger:
- sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
- zExp = aExp;
- normalizeRoundAndPack:
- --zExp;
- return normalizeRoundAndPackFloat128(zSign, zExp - 14, zSig0, zSig1,
- status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of adding the quadruple-precision floating-point values
-| `a' and `b'. The operation is performed according to the IEC/IEEE Standard
-| for Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float128_add(float128 a, float128 b, float_status *status)
-{
- bool aSign, bSign;
-
- aSign = extractFloat128Sign( a );
- bSign = extractFloat128Sign( b );
- if ( aSign == bSign ) {
- return addFloat128Sigs(a, b, aSign, status);
- }
- else {
- return subFloat128Sigs(a, b, aSign, status);
- }
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of subtracting the quadruple-precision floating-point
-| values `a' and `b'. The operation is performed according to the IEC/IEEE
-| Standard for Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float128_sub(float128 a, float128 b, float_status *status)
-{
- bool aSign, bSign;
-
- aSign = extractFloat128Sign( a );
- bSign = extractFloat128Sign( b );
- if ( aSign == bSign ) {
- return subFloat128Sigs(a, b, aSign, status);
- }
- else {
- return addFloat128Sigs(a, b, aSign, status);
- }
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of multiplying the quadruple-precision floating-point
-| values `a' and `b'. The operation is performed according to the IEC/IEEE
-| Standard for Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float128_mul(float128 a, float128 b, float_status *status)
-{
- bool aSign, bSign, zSign;
- int32_t aExp, bExp, zExp;
- uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- bSig1 = extractFloat128Frac1( b );
- bSig0 = extractFloat128Frac0( b );
- bExp = extractFloat128Exp( b );
- bSign = extractFloat128Sign( b );
- zSign = aSign ^ bSign;
- if ( aExp == 0x7FFF ) {
- if ( ( aSig0 | aSig1 )
- || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
- return propagateFloat128NaN(a, b, status);
- }
- if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
- return packFloat128( zSign, 0x7FFF, 0, 0 );
- }
- if ( bExp == 0x7FFF ) {
- if (bSig0 | bSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
- float_raise(float_flag_invalid, status);
- return float128_default_nan(status);
- }
- return packFloat128( zSign, 0x7FFF, 0, 0 );
- }
- if ( aExp == 0 ) {
- if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
- normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
- }
- if ( bExp == 0 ) {
- if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
- normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
- }
- zExp = aExp + bExp - 0x4000;
- aSig0 |= UINT64_C(0x0001000000000000);
- shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
- mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
- add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
- zSig2 |= ( zSig3 != 0 );
- if (UINT64_C( 0x0002000000000000) <= zSig0 ) {
- shift128ExtraRightJamming(
- zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
- ++zExp;
- }
- return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status);
-
-}
-
-/*----------------------------------------------------------------------------
-| Returns the result of dividing the quadruple-precision floating-point value
-| `a' by the corresponding value `b'. The operation is performed according to
-| the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-*----------------------------------------------------------------------------*/
-
-float128 float128_div(float128 a, float128 b, float_status *status)
-{
- bool aSign, bSign, zSign;
- int32_t aExp, bExp, zExp;
- uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
- uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
-
- aSig1 = extractFloat128Frac1( a );
- aSig0 = extractFloat128Frac0( a );
- aExp = extractFloat128Exp( a );
- aSign = extractFloat128Sign( a );
- bSig1 = extractFloat128Frac1( b );
- bSig0 = extractFloat128Frac0( b );
- bExp = extractFloat128Exp( b );
- bSign = extractFloat128Sign( b );
- zSign = aSign ^ bSign;
- if ( aExp == 0x7FFF ) {
- if (aSig0 | aSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- if ( bExp == 0x7FFF ) {
- if (bSig0 | bSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- goto invalid;
- }
- return packFloat128( zSign, 0x7FFF, 0, 0 );
- }
- if ( bExp == 0x7FFF ) {
- if (bSig0 | bSig1) {
- return propagateFloat128NaN(a, b, status);
- }
- return packFloat128( zSign, 0, 0, 0 );
- }
- if ( bExp == 0 ) {
- if ( ( bSig0 | bSig1 ) == 0 ) {
- if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
- float_raise(float_flag_invalid, status);
- return float128_default_nan(status);
- }
- float_raise(float_flag_divbyzero, status);
- return packFloat128( zSign, 0x7FFF, 0, 0 );
- }
- normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
- }
- if ( aExp == 0 ) {
- if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
- normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
- }
- zExp = aExp - bExp + 0x3FFD;
- shortShift128Left(
- aSig0 | UINT64_C(0x0001000000000000), aSig1, 15, &aSig0, &aSig1 );
- shortShift128Left(
- bSig0 | UINT64_C(0x0001000000000000), bSig1, 15, &bSig0, &bSig1 );
- if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
- shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
- ++zExp;
- }
- zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
- mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
- sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
- while ( (int64_t) rem0 < 0 ) {
- --zSig0;
- add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
- }
- zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
- if ( ( zSig1 & 0x3FFF ) <= 4 ) {
- mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
- sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
- while ( (int64_t) rem1 < 0 ) {
- --zSig1;
- add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
- }
- zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
- }
- shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
- return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status);
-
-}
-
-/*----------------------------------------------------------------------------
| Returns the remainder of the quadruple-precision floating-point value `a'
| with respect to the corresponding value `b'. The operation is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
diff --git a/hw/Kconfig b/hw/Kconfig
index ff40bd3f7b..805860f564 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -21,6 +21,7 @@ source mem/Kconfig
source misc/Kconfig
source net/Kconfig
source nubus/Kconfig
+source nvme/Kconfig
source nvram/Kconfig
source pci-bridge/Kconfig
source pci-host/Kconfig
@@ -47,11 +48,9 @@ source avr/Kconfig
source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
-source lm32/Kconfig
source m68k/Kconfig
source microblaze/Kconfig
source mips/Kconfig
-source moxie/Kconfig
source nios2/Kconfig
source openrisc/Kconfig
source ppc/Kconfig
@@ -62,7 +61,6 @@ source sh4/Kconfig
source sparc/Kconfig
source sparc64/Kconfig
source tricore/Kconfig
-source unicore32/Kconfig
source xtensa/Kconfig
# Symbols used by multiple targets
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index d33ce8954a..f0035d2b4a 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -1830,6 +1830,7 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
int i;
unsigned rsdt_entries_offset;
AcpiRsdtDescriptorRev1 *rsdt;
+ int rsdt_start = table_data->len;
const unsigned table_data_len = (sizeof(uint32_t) * table_offsets->len);
const unsigned rsdt_entry_size = sizeof(rsdt->table_offset_entry[0]);
const size_t rsdt_len = sizeof(*rsdt) + table_data_len;
@@ -1846,7 +1847,8 @@ build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
}
build_header(linker, table_data,
- (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id);
+ (void *)(table_data->data + rsdt_start),
+ "RSDT", rsdt_len, 1, oem_id, oem_table_id);
}
/* Build xsdt table */
@@ -1857,6 +1859,7 @@ build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
int i;
unsigned xsdt_entries_offset;
AcpiXsdtDescriptorRev2 *xsdt;
+ int xsdt_start = table_data->len;
const unsigned table_data_len = (sizeof(uint64_t) * table_offsets->len);
const unsigned xsdt_entry_size = sizeof(xsdt->table_offset_entry[0]);
const size_t xsdt_len = sizeof(*xsdt) + table_data_len;
@@ -1873,7 +1876,8 @@ build_xsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets,
ACPI_BUILD_TABLE_FILE, ref_tbl_offset);
}
build_header(linker, table_data,
- (void *)xsdt, "XSDT", xsdt_len, 1, oem_id, oem_table_id);
+ (void *)(table_data->data + xsdt_start),
+ "XSDT", xsdt_len, 1, oem_id, oem_table_id);
}
void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
@@ -2053,10 +2057,9 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
uint64_t control_area_start_address;
TPMIf *tpmif = tpm_find();
uint32_t start_method;
- void *tpm2_ptr;
tpm2_start = table_data->len;
- tpm2_ptr = acpi_data_push(table_data, sizeof(AcpiTableHeader));
+ acpi_data_push(table_data, sizeof(AcpiTableHeader));
/* Platform Class */
build_append_int_noprefix(table_data, TPM2_ACPI_CLASS_CLIENT, 2);
@@ -2095,8 +2098,8 @@ void build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
log_addr_offset, 8,
ACPI_BUILD_TPMLOG_FILE, 0);
build_header(linker, table_data,
- tpm2_ptr, "TPM2", table_data->len - tpm2_start, 4, oem_id,
- oem_table_id);
+ (void *)(table_data->data + tpm2_start),
+ "TPM2", table_data->len - tpm2_start, 4, oem_id, oem_table_id);
}
Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set, uint32_t io_offset,
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0a78532018..840758666d 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -50,6 +50,7 @@
#include "sysemu/tpm.h"
#include "sysemu/kvm.h"
#include "hw/loader.h"
+#include "qapi/error.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
@@ -1521,8 +1522,10 @@ static void virt_build_smbios(VirtMachineState *vms)
vmc->smbios_old_sys_ver ? "1.0" : mc->name, false,
true, SMBIOS_ENTRY_POINT_30);
- smbios_get_tables(MACHINE(vms), NULL, 0, &smbios_tables, &smbios_tables_len,
- &smbios_anchor, &smbios_anchor_len);
+ smbios_get_tables(MACHINE(vms), NULL, 0,
+ &smbios_tables, &smbios_tables_len,
+ &smbios_anchor, &smbios_anchor_len,
+ &error_fatal);
if (smbios_anchor) {
fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-tables",
diff --git a/hw/audio/meson.build b/hw/audio/meson.build
index 32c42bdebe..e48a9fc73d 100644
--- a/hw/audio/meson.build
+++ b/hw/audio/meson.build
@@ -7,7 +7,6 @@ softmmu_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c'))
softmmu_ss.add(when: 'CONFIG_GUS', if_true: files('gus.c', 'gusemu_hal.c', 'gusemu_mixer.c'))
softmmu_ss.add(when: 'CONFIG_HDA', if_true: files('intel-hda.c', 'hda-codec.c'))
softmmu_ss.add(when: 'CONFIG_MARVELL_88W8618', if_true: files('marvell_88w8618.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-ac97.c'))
softmmu_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c'))
softmmu_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c'))
softmmu_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c'))
diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c
deleted file mode 100644
index 7d2e057038..0000000000
--- a/hw/audio/milkymist-ac97.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * QEMU model of the Milkymist System Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/ac97.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "audio/audio.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- R_AC97_CTRL = 0,
- R_AC97_ADDR,
- R_AC97_DATAOUT,
- R_AC97_DATAIN,
- R_D_CTRL,
- R_D_ADDR,
- R_D_REMAINING,
- R_RESERVED,
- R_U_CTRL,
- R_U_ADDR,
- R_U_REMAINING,
- R_MAX
-};
-
-enum {
- AC97_CTRL_RQEN = (1<<0),
- AC97_CTRL_WRITE = (1<<1),
-};
-
-enum {
- CTRL_EN = (1<<0),
-};
-
-#define TYPE_MILKYMIST_AC97 "milkymist-ac97"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistAC97State, MILKYMIST_AC97)
-
-struct MilkymistAC97State {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- QEMUSoundCard card;
- SWVoiceIn *voice_in;
- SWVoiceOut *voice_out;
-
- uint32_t regs[R_MAX];
-
- qemu_irq crrequest_irq;
- qemu_irq crreply_irq;
- qemu_irq dmar_irq;
- qemu_irq dmaw_irq;
-};
-
-static void update_voices(MilkymistAC97State *s)
-{
- if (s->regs[R_D_CTRL] & CTRL_EN) {
- AUD_set_active_out(s->voice_out, 1);
- } else {
- AUD_set_active_out(s->voice_out, 0);
- }
-
- if (s->regs[R_U_CTRL] & CTRL_EN) {
- AUD_set_active_in(s->voice_in, 1);
- } else {
- AUD_set_active_in(s->voice_in, 0);
- }
-}
-
-static uint64_t ac97_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistAC97State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_AC97_CTRL:
- case R_AC97_ADDR:
- case R_AC97_DATAOUT:
- case R_AC97_DATAIN:
- case R_D_CTRL:
- case R_D_ADDR:
- case R_D_REMAINING:
- case R_U_CTRL:
- case R_U_ADDR:
- case R_U_REMAINING:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_ac97: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_ac97_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void ac97_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistAC97State *s = opaque;
-
- trace_milkymist_ac97_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_AC97_CTRL:
- /* always raise an IRQ according to the direction */
- if (value & AC97_CTRL_RQEN) {
- if (value & AC97_CTRL_WRITE) {
- trace_milkymist_ac97_pulse_irq_crrequest();
- qemu_irq_pulse(s->crrequest_irq);
- } else {
- trace_milkymist_ac97_pulse_irq_crreply();
- qemu_irq_pulse(s->crreply_irq);
- }
- }
-
- /* RQEN is self clearing */
- s->regs[addr] = value & ~AC97_CTRL_RQEN;
- break;
- case R_D_CTRL:
- case R_U_CTRL:
- s->regs[addr] = value;
- update_voices(s);
- break;
- case R_AC97_ADDR:
- case R_AC97_DATAOUT:
- case R_AC97_DATAIN:
- case R_D_ADDR:
- case R_D_REMAINING:
- case R_U_ADDR:
- case R_U_REMAINING:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_ac97: write access to unknown register 0x"
- TARGET_FMT_plx, addr);
- break;
- }
-
-}
-
-static const MemoryRegionOps ac97_mmio_ops = {
- .read = ac97_read,
- .write = ac97_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ac97_in_cb(void *opaque, int avail_b)
-{
- MilkymistAC97State *s = opaque;
- uint8_t buf[4096];
- uint32_t remaining = s->regs[R_U_REMAINING];
- int temp = MIN(remaining, avail_b);
- uint32_t addr = s->regs[R_U_ADDR];
- int transferred = 0;
-
- trace_milkymist_ac97_in_cb(avail_b, remaining);
-
- /* prevent from raising an IRQ */
- if (temp == 0) {
- return;
- }
-
- while (temp) {
- int acquired, to_copy;
-
- to_copy = MIN(temp, sizeof(buf));
- acquired = AUD_read(s->voice_in, buf, to_copy);
- if (!acquired) {
- break;
- }
-
- cpu_physical_memory_write(addr, buf, acquired);
-
- temp -= acquired;
- addr += acquired;
- transferred += acquired;
- }
-
- trace_milkymist_ac97_in_cb_transferred(transferred);
-
- s->regs[R_U_ADDR] = addr;
- s->regs[R_U_REMAINING] -= transferred;
-
- if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
- trace_milkymist_ac97_pulse_irq_dmaw();
- qemu_irq_pulse(s->dmaw_irq);
- }
-}
-
-static void ac97_out_cb(void *opaque, int free_b)
-{
- MilkymistAC97State *s = opaque;
- uint8_t buf[4096];
- uint32_t remaining = s->regs[R_D_REMAINING];
- int temp = MIN(remaining, free_b);
- uint32_t addr = s->regs[R_D_ADDR];
- int transferred = 0;
-
- trace_milkymist_ac97_out_cb(free_b, remaining);
-
- /* prevent from raising an IRQ */
- if (temp == 0) {
- return;
- }
-
- while (temp) {
- int copied, to_copy;
-
- to_copy = MIN(temp, sizeof(buf));
- cpu_physical_memory_read(addr, buf, to_copy);
- copied = AUD_write(s->voice_out, buf, to_copy);
- if (!copied) {
- break;
- }
- temp -= copied;
- addr += copied;
- transferred += copied;
- }
-
- trace_milkymist_ac97_out_cb_transferred(transferred);
-
- s->regs[R_D_ADDR] = addr;
- s->regs[R_D_REMAINING] -= transferred;
-
- if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
- trace_milkymist_ac97_pulse_irq_dmar();
- qemu_irq_pulse(s->dmar_irq);
- }
-}
-
-static void milkymist_ac97_reset(DeviceState *d)
-{
- MilkymistAC97State *s = MILKYMIST_AC97(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- AUD_set_active_in(s->voice_in, 0);
- AUD_set_active_out(s->voice_out, 0);
-}
-
-static int ac97_post_load(void *opaque, int version_id)
-{
- MilkymistAC97State *s = opaque;
-
- update_voices(s);
-
- return 0;
-}
-
-static void milkymist_ac97_init(Object *obj)
-{
- MilkymistAC97State *s = MILKYMIST_AC97(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->crrequest_irq);
- sysbus_init_irq(dev, &s->crreply_irq);
- sysbus_init_irq(dev, &s->dmar_irq);
- sysbus_init_irq(dev, &s->dmaw_irq);
-
- memory_region_init_io(&s->regs_region, obj, &ac97_mmio_ops, s,
- "milkymist-ac97", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_ac97_realize(DeviceState *dev, Error **errp)
-{
- MilkymistAC97State *s = MILKYMIST_AC97(dev);
- struct audsettings as;
-
- AUD_register_card("Milkymist AC'97", &s->card);
-
- as.freq = 48000;
- as.nchannels = 2;
- as.fmt = AUDIO_FORMAT_S16;
- as.endianness = 1;
-
- s->voice_in = AUD_open_in(&s->card, s->voice_in,
- "mm_ac97.in", s, ac97_in_cb, &as);
- s->voice_out = AUD_open_out(&s->card, s->voice_out,
- "mm_ac97.out", s, ac97_out_cb, &as);
-}
-
-static const VMStateDescription vmstate_milkymist_ac97 = {
- .name = "milkymist-ac97",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ac97_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_ac97_properties[] = {
- DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_ac97_realize;
- dc->reset = milkymist_ac97_reset;
- dc->vmsd = &vmstate_milkymist_ac97;
- device_class_set_props(dc, milkymist_ac97_properties);
-}
-
-static const TypeInfo milkymist_ac97_info = {
- .name = TYPE_MILKYMIST_AC97,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistAC97State),
- .instance_init = milkymist_ac97_init,
- .class_init = milkymist_ac97_class_init,
-};
-
-static void milkymist_ac97_register_types(void)
-{
- type_register_static(&milkymist_ac97_info);
-}
-
-type_init(milkymist_ac97_register_types)
diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index 60556b4a97..432e10712f 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -6,18 +6,6 @@ cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x"
cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x"
cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x"
-# milkymist-ac97.c
-milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request"
-milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply"
-milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write"
-milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read"
-milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u"
-milkymist_ac97_in_cb_transferred(int transferred) "transferred %d"
-milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u"
-milkymist_ac97_out_cb_transferred(int transferred) "transferred %d"
-
# hda-codec.c
hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d"
hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz"
diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c
index 80b8a41cb5..0608e2d475 100644
--- a/hw/avr/atmega.c
+++ b/hw/avr/atmega.c
@@ -401,7 +401,7 @@ static void atmega1280_class_init(ObjectClass *oc, void *data)
{
AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc);
- amc->cpu_type = AVR_CPU_TYPE_NAME("avr6");
+ amc->cpu_type = AVR_CPU_TYPE_NAME("avr51");
amc->flash_size = 128 * KiB;
amc->eeprom_size = 4 * KiB;
amc->sram_size = 8 * KiB;
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 4fcd152166..295441e64a 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -25,11 +25,6 @@ config ONENAND
config TC58128
bool
-config NVME_PCI
- bool
- default y if PCI_DEVICES
- depends on PCI
-
config VIRTIO_BLK
bool
default y
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index e9050c8987..cd81893d1d 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -198,19 +198,30 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
goto fail_guest_notifiers;
}
+ memory_region_transaction_begin();
+
/* Set up virtqueue notify */
for (i = 0; i < nvqs; i++) {
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true);
if (r != 0) {
+ int j = i;
+
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
while (i--) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
+ }
+
+ memory_region_transaction_commit();
+
+ while (j--) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
}
- goto fail_guest_notifiers;
+ goto fail_host_notifiers;
}
}
+ memory_region_transaction_commit();
+
s->starting = false;
vblk->dataplane_started = true;
trace_virtio_blk_data_plane_start(s);
@@ -221,7 +232,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
aio_context_release(old_context);
if (r < 0) {
error_report_err(local_err);
- goto fail_guest_notifiers;
+ goto fail_aio_context;
}
/* Process queued requests before the ones in vring */
@@ -245,6 +256,20 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
aio_context_release(s->ctx);
return 0;
+ fail_aio_context:
+ memory_region_transaction_begin();
+
+ for (i = 0; i < nvqs; i++) {
+ virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
+ }
+
+ memory_region_transaction_commit();
+
+ for (i = 0; i < nvqs; i++) {
+ virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
+ }
+ fail_host_notifiers:
+ k->set_guest_notifiers(qbus->parent, nvqs, false);
fail_guest_notifiers:
/*
* If we failed to set up the guest notifiers queued requests will be
@@ -305,8 +330,15 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev)
aio_context_release(s->ctx);
+ memory_region_transaction_begin();
+
for (i = 0; i < nvqs; i++) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
+ }
+
+ memory_region_transaction_commit();
+
+ for (i = 0; i < nvqs; i++) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
}
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 5b4a7699f9..8b0de54db1 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c'))
softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
-softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c', 'nvme-subsys.c', 'nvme-dif.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
diff --git a/hw/block/nvme-dif.h b/hw/block/nvme-dif.h
deleted file mode 100644
index 524faffbd7..0000000000
--- a/hw/block/nvme-dif.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * QEMU NVM Express End-to-End Data Protection support
- *
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Authors:
- * Klaus Jensen <k.jensen@samsung.com>
- * Gollu Appalanaidu <anaidu.gollu@samsung.com>
- */
-
-#ifndef HW_NVME_DIF_H
-#define HW_NVME_DIF_H
-
-/* from Linux kernel (crypto/crct10dif_common.c) */
-static const uint16_t t10_dif_crc_table[256] = {
- 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
- 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
- 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
- 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
- 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
- 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
- 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
- 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
- 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
- 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
- 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
- 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
- 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
- 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
- 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
- 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
- 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
- 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
- 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
- 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
- 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
- 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
- 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
- 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
- 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
- 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
- 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
- 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
- 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
- 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
- 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
- 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
-};
-
-uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba,
- uint32_t reftag);
-uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen,
- uint64_t slba);
-void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len,
- uint8_t *mbuf, size_t mlen, uint16_t apptag,
- uint32_t reftag);
-uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len,
- uint8_t *mbuf, size_t mlen, uint16_t ctrl,
- uint64_t slba, uint16_t apptag,
- uint16_t appmask, uint32_t reftag);
-uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req);
-
-#endif /* HW_NVME_DIF_H */
diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
deleted file mode 100644
index fb0a41f912..0000000000
--- a/hw/block/nvme-ns.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * QEMU NVM Express Virtual Namespace
- *
- * Copyright (c) 2019 CNEX Labs
- * Copyright (c) 2020 Samsung Electronics
- *
- * Authors:
- * Klaus Jensen <k.jensen@samsung.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See the
- * COPYING file in the top-level directory.
- *
- */
-
-#ifndef NVME_NS_H
-#define NVME_NS_H
-
-#include "qemu/uuid.h"
-
-#define TYPE_NVME_NS "nvme-ns"
-#define NVME_NS(obj) \
- OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
-
-typedef struct NvmeZone {
- NvmeZoneDescr d;
- uint64_t w_ptr;
- QTAILQ_ENTRY(NvmeZone) entry;
-} NvmeZone;
-
-typedef struct NvmeNamespaceParams {
- bool detached;
- bool shared;
- uint32_t nsid;
- QemuUUID uuid;
-
- uint16_t ms;
- uint8_t mset;
- uint8_t pi;
- uint8_t pil;
-
- uint16_t mssrl;
- uint32_t mcl;
- uint8_t msrc;
-
- bool zoned;
- bool cross_zone_read;
- uint64_t zone_size_bs;
- uint64_t zone_cap_bs;
- uint32_t max_active_zones;
- uint32_t max_open_zones;
- uint32_t zd_extension_size;
-} NvmeNamespaceParams;
-
-typedef struct NvmeNamespace {
- DeviceState parent_obj;
- BlockConf blkconf;
- int32_t bootindex;
- int64_t size;
- int64_t mdata_offset;
- NvmeIdNs id_ns;
- const uint32_t *iocs;
- uint8_t csi;
- uint16_t status;
- int attached;
-
- QTAILQ_ENTRY(NvmeNamespace) entry;
-
- NvmeIdNsZoned *id_ns_zoned;
- NvmeZone *zone_array;
- QTAILQ_HEAD(, NvmeZone) exp_open_zones;
- QTAILQ_HEAD(, NvmeZone) imp_open_zones;
- QTAILQ_HEAD(, NvmeZone) closed_zones;
- QTAILQ_HEAD(, NvmeZone) full_zones;
- uint32_t num_zones;
- uint64_t zone_size;
- uint64_t zone_capacity;
- uint32_t zone_size_log2;
- uint8_t *zd_extensions;
- int32_t nr_open_zones;
- int32_t nr_active_zones;
-
- NvmeNamespaceParams params;
-
- struct {
- uint32_t err_rec;
- } features;
-} NvmeNamespace;
-
-static inline uint16_t nvme_ns_status(NvmeNamespace *ns)
-{
- return ns->status;
-}
-
-static inline uint32_t nvme_nsid(NvmeNamespace *ns)
-{
- if (ns) {
- return ns->params.nsid;
- }
-
- return 0;
-}
-
-static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
-{
- NvmeIdNs *id_ns = &ns->id_ns;
- return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
-}
-
-static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
-{
- return nvme_ns_lbaf(ns)->ds;
-}
-
-/* convert an LBA to the equivalent in bytes */
-static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
-{
- return lba << nvme_ns_lbads(ns);
-}
-
-static inline size_t nvme_lsize(NvmeNamespace *ns)
-{
- return 1 << nvme_ns_lbads(ns);
-}
-
-static inline uint16_t nvme_msize(NvmeNamespace *ns)
-{
- return nvme_ns_lbaf(ns)->ms;
-}
-
-static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
-{
- return nvme_msize(ns) * lba;
-}
-
-static inline bool nvme_ns_ext(NvmeNamespace *ns)
-{
- return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
-}
-
-/* calculate the number of LBAs that the namespace can accomodate */
-static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
-{
- if (nvme_msize(ns)) {
- return ns->size / (nvme_lsize(ns) + nvme_msize(ns));
- }
- return ns->size >> nvme_ns_lbads(ns);
-}
-
-typedef struct NvmeCtrl NvmeCtrl;
-
-static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
-{
- return zone->d.zs >> 4;
-}
-
-static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
-{
- zone->d.zs = state << 4;
-}
-
-static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
-{
- return zone->d.zslba + ns->zone_size;
-}
-
-static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
-{
- return zone->d.zslba + zone->d.zcap;
-}
-
-static inline bool nvme_wp_is_valid(NvmeZone *zone)
-{
- uint8_t st = nvme_get_zone_state(zone);
-
- return st != NVME_ZONE_STATE_FULL &&
- st != NVME_ZONE_STATE_READ_ONLY &&
- st != NVME_ZONE_STATE_OFFLINE;
-}
-
-static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
- uint32_t zone_idx)
-{
- return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
-}
-
-static inline void nvme_aor_inc_open(NvmeNamespace *ns)
-{
- assert(ns->nr_open_zones >= 0);
- if (ns->params.max_open_zones) {
- ns->nr_open_zones++;
- assert(ns->nr_open_zones <= ns->params.max_open_zones);
- }
-}
-
-static inline void nvme_aor_dec_open(NvmeNamespace *ns)
-{
- if (ns->params.max_open_zones) {
- assert(ns->nr_open_zones > 0);
- ns->nr_open_zones--;
- }
- assert(ns->nr_open_zones >= 0);
-}
-
-static inline void nvme_aor_inc_active(NvmeNamespace *ns)
-{
- assert(ns->nr_active_zones >= 0);
- if (ns->params.max_active_zones) {
- ns->nr_active_zones++;
- assert(ns->nr_active_zones <= ns->params.max_active_zones);
- }
-}
-
-static inline void nvme_aor_dec_active(NvmeNamespace *ns)
-{
- if (ns->params.max_active_zones) {
- assert(ns->nr_active_zones > 0);
- ns->nr_active_zones--;
- assert(ns->nr_active_zones >= ns->nr_open_zones);
- }
- assert(ns->nr_active_zones >= 0);
-}
-
-void nvme_ns_init_format(NvmeNamespace *ns);
-int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
-void nvme_ns_drain(NvmeNamespace *ns);
-void nvme_ns_shutdown(NvmeNamespace *ns);
-void nvme_ns_cleanup(NvmeNamespace *ns);
-
-#endif /* NVME_NS_H */
diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h
deleted file mode 100644
index 7d7ef5f7f1..0000000000
--- a/hw/block/nvme-subsys.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * QEMU NVM Express Subsystem: nvme-subsys
- *
- * Copyright (c) 2021 Minwoo Im <minwoo.im.dev@gmail.com>
- *
- * This code is licensed under the GNU GPL v2. Refer COPYING.
- */
-
-#ifndef NVME_SUBSYS_H
-#define NVME_SUBSYS_H
-
-#define TYPE_NVME_SUBSYS "nvme-subsys"
-#define NVME_SUBSYS(obj) \
- OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)
-
-#define NVME_SUBSYS_MAX_CTRLS 32
-#define NVME_MAX_NAMESPACES 256
-
-typedef struct NvmeCtrl NvmeCtrl;
-typedef struct NvmeNamespace NvmeNamespace;
-typedef struct NvmeSubsystem {
- DeviceState parent_obj;
- uint8_t subnqn[256];
-
- NvmeCtrl *ctrls[NVME_SUBSYS_MAX_CTRLS];
- /* Allocated namespaces for this subsystem */
- NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
-
- struct {
- char *nqn;
- } params;
-} NvmeSubsystem;
-
-int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp);
-
-static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
- uint32_t cntlid)
-{
- if (!subsys || cntlid >= NVME_SUBSYS_MAX_CTRLS) {
- return NULL;
- }
-
- return subsys->ctrls[cntlid];
-}
-
-/*
- * Return allocated namespace of the specified nsid in the subsystem.
- */
-static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys,
- uint32_t nsid)
-{
- if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) {
- return NULL;
- }
-
- return subsys->namespaces[nsid];
-}
-
-#endif /* NVME_SUBSYS_H */
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
deleted file mode 100644
index 5d05ec368f..0000000000
--- a/hw/block/nvme.h
+++ /dev/null
@@ -1,266 +0,0 @@
-#ifndef HW_NVME_H
-#define HW_NVME_H
-
-#include "block/nvme.h"
-#include "hw/pci/pci.h"
-#include "nvme-subsys.h"
-#include "nvme-ns.h"
-
-#define NVME_DEFAULT_ZONE_SIZE (128 * MiB)
-#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB)
-
-typedef struct NvmeParams {
- char *serial;
- uint32_t num_queues; /* deprecated since 5.1 */
- uint32_t max_ioqpairs;
- uint16_t msix_qsize;
- uint32_t cmb_size_mb;
- uint8_t aerl;
- uint32_t aer_max_queued;
- uint8_t mdts;
- uint8_t vsl;
- bool use_intel_id;
- uint8_t zasl;
- bool legacy_cmb;
-} NvmeParams;
-
-typedef struct NvmeAsyncEvent {
- QTAILQ_ENTRY(NvmeAsyncEvent) entry;
- NvmeAerResult result;
-} NvmeAsyncEvent;
-
-enum {
- NVME_SG_ALLOC = 1 << 0,
- NVME_SG_DMA = 1 << 1,
-};
-
-typedef struct NvmeSg {
- int flags;
-
- union {
- QEMUSGList qsg;
- QEMUIOVector iov;
- };
-} NvmeSg;
-
-typedef struct NvmeRequest {
- struct NvmeSQueue *sq;
- struct NvmeNamespace *ns;
- BlockAIOCB *aiocb;
- uint16_t status;
- void *opaque;
- NvmeCqe cqe;
- NvmeCmd cmd;
- BlockAcctCookie acct;
- NvmeSg sg;
- QTAILQ_ENTRY(NvmeRequest)entry;
-} NvmeRequest;
-
-typedef struct NvmeBounceContext {
- NvmeRequest *req;
-
- struct {
- QEMUIOVector iov;
- uint8_t *bounce;
- } data, mdata;
-} NvmeBounceContext;
-
-static inline const char *nvme_adm_opc_str(uint8_t opc)
-{
- switch (opc) {
- case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ";
- case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ";
- case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE";
- case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ";
- case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ";
- case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY";
- case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT";
- case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES";
- case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES";
- case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ";
- case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT";
- case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM";
- default: return "NVME_ADM_CMD_UNKNOWN";
- }
-}
-
-static inline const char *nvme_io_opc_str(uint8_t opc)
-{
- switch (opc) {
- case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH";
- case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE";
- case NVME_CMD_READ: return "NVME_NVM_CMD_READ";
- case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE";
- case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES";
- case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM";
- case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY";
- case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY";
- case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND";
- case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV";
- case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND";
- default: return "NVME_NVM_CMD_UNKNOWN";
- }
-}
-
-typedef struct NvmeSQueue {
- struct NvmeCtrl *ctrl;
- uint16_t sqid;
- uint16_t cqid;
- uint32_t head;
- uint32_t tail;
- uint32_t size;
- uint64_t dma_addr;
- QEMUTimer *timer;
- NvmeRequest *io_req;
- QTAILQ_HEAD(, NvmeRequest) req_list;
- QTAILQ_HEAD(, NvmeRequest) out_req_list;
- QTAILQ_ENTRY(NvmeSQueue) entry;
-} NvmeSQueue;
-
-typedef struct NvmeCQueue {
- struct NvmeCtrl *ctrl;
- uint8_t phase;
- uint16_t cqid;
- uint16_t irq_enabled;
- uint32_t head;
- uint32_t tail;
- uint32_t vector;
- uint32_t size;
- uint64_t dma_addr;
- QEMUTimer *timer;
- QTAILQ_HEAD(, NvmeSQueue) sq_list;
- QTAILQ_HEAD(, NvmeRequest) req_list;
-} NvmeCQueue;
-
-#define TYPE_NVME_BUS "nvme-bus"
-#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS)
-
-typedef struct NvmeBus {
- BusState parent_bus;
-} NvmeBus;
-
-#define TYPE_NVME "nvme"
-#define NVME(obj) \
- OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
-
-typedef struct NvmeFeatureVal {
- struct {
- uint16_t temp_thresh_hi;
- uint16_t temp_thresh_low;
- };
- uint32_t async_config;
-} NvmeFeatureVal;
-
-typedef struct NvmeCtrl {
- PCIDevice parent_obj;
- MemoryRegion bar0;
- MemoryRegion iomem;
- NvmeBar bar;
- NvmeParams params;
- NvmeBus bus;
-
- uint16_t cntlid;
- bool qs_created;
- uint32_t page_size;
- uint16_t page_bits;
- uint16_t max_prp_ents;
- uint16_t cqe_size;
- uint16_t sqe_size;
- uint32_t reg_size;
- uint32_t num_namespaces;
- uint32_t max_q_ents;
- uint8_t outstanding_aers;
- uint32_t irq_status;
- uint64_t host_timestamp; /* Timestamp sent by the host */
- uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
- uint64_t starttime_ms;
- uint16_t temperature;
- uint8_t smart_critical_warning;
-
- struct {
- MemoryRegion mem;
- uint8_t *buf;
- bool cmse;
- hwaddr cba;
- } cmb;
-
- struct {
- HostMemoryBackend *dev;
- bool cmse;
- hwaddr cba;
- } pmr;
-
- uint8_t aer_mask;
- NvmeRequest **aer_reqs;
- QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
- int aer_queued;
-
- uint32_t dmrsl;
-
- /* Namespace ID is started with 1 so bitmap should be 1-based */
-#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1)
- DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE);
-
- NvmeSubsystem *subsys;
-
- NvmeNamespace namespace;
- /*
- * Attached namespaces to this controller. If subsys is not given, all
- * namespaces in this list will always be attached.
- */
- NvmeNamespace *namespaces[NVME_MAX_NAMESPACES];
- NvmeSQueue **sq;
- NvmeCQueue **cq;
- NvmeSQueue admin_sq;
- NvmeCQueue admin_cq;
- NvmeIdCtrl id_ctrl;
- NvmeFeatureVal features;
-} NvmeCtrl;
-
-static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
-{
- if (!nsid || nsid > n->num_namespaces) {
- return NULL;
- }
-
- return n->namespaces[nsid - 1];
-}
-
-static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
-{
- NvmeSQueue *sq = req->sq;
- NvmeCtrl *n = sq->ctrl;
-
- return n->cq[sq->cqid];
-}
-
-static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req)
-{
- NvmeSQueue *sq = req->sq;
- return sq->ctrl;
-}
-
-static inline uint16_t nvme_cid(NvmeRequest *req)
-{
- if (!req) {
- return 0xffff;
- }
-
- return le16_to_cpu(req->cqe.cid);
-}
-
-typedef enum NvmeTxDirection {
- NVME_TX_DIRECTION_TO_DEVICE = 0,
- NVME_TX_DIRECTION_FROM_DEVICE = 1,
-} NvmeTxDirection;
-
-void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns);
-uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
- NvmeTxDirection dir, NvmeRequest *req);
-uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
- NvmeTxDirection dir, NvmeRequest *req);
-void nvme_rw_complete_cb(void *opaque, int ret);
-uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len,
- NvmeCmd *cmd);
-
-#endif /* HW_NVME_H */
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 25c053693c..02c514fb6e 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -173,7 +173,6 @@ static void pflash_setup_mappings(PFlashCFI02 *pfl)
"pflash-alias", &pfl->orig_mem, 0, size);
memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
}
- pfl->rom_mode = true;
}
static void pflash_reset_state_machine(PFlashCFI02 *pfl)
@@ -917,8 +916,13 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
/* Allocate memory for a bitmap for sectors being erased. */
pfl->sector_erase_map = bitmap_new(pfl->total_sectors);
- pflash_setup_mappings(pfl);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
+ pfl->rom_mode = true;
+ if (pfl->mappings > 1) {
+ pflash_setup_mappings(pfl);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
+ } else {
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->orig_mem);
+ }
timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
pfl->status = 0;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index fa12e3a67a..646917d045 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -49,212 +49,6 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6
hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d"
hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d"
-# nvme.c
-# nvme traces for successful events
-pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
-pci_nvme_irq_pin(void) "pulsing IRQ pin"
-pci_nvme_irq_masked(void) "IRQ is masked"
-pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
-pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
-pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
-pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d"
-pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64""
-pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
-pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
-pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32""
-pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8""
-pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8""
-pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32""
-pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64""
-pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64""
-pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8""
-pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32""
-pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32""
-pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16""
-pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32""
-pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16""
-pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16""
-pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32""
-pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8""
-pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32""
-pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16""
-pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32""
-pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32""
-pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d"
-pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32""
-pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32""
-pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32""
-pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32""
-pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64""
-pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
-pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
-pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
-pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
-pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
-pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8""
-pci_nvme_identify_ctrl(void) "identify controller"
-pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8""
-pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
-pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16""
-pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8""
-pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
-pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8""
-pci_nvme_identify_cmd_set(void) "identify i/o command set"
-pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32""
-pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
-pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
-pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""
-pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
-pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
-pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
-pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
-pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
-pci_nvme_process_aers(int queued) "queued %d"
-pci_nvme_aer(uint16_t cid) "cid %"PRIu16""
-pci_nvme_aer_aerl_exceeded(void) "aerl exceeded"
-pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8""
-pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
-pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8""
-pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32""
-pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
-pci_nvme_enqueue_event_noqueue(int queued) "queued %d"
-pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8""
-pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs"
-pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
-pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d"
-pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
-pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16""
-pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16""
-pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
-pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
-pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
-pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
-pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
-pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
-pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
-pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
-pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded"
-pci_nvme_mmio_stopped(void) "cleared controller enable bit"
-pci_nvme_mmio_shutdown_set(void) "shutdown bit set"
-pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
-pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
-pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
-pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
-pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
-pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
-pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32""
-pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32""
-pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state"
-pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state"
-
-# nvme traces for error conditions
-pci_nvme_err_mdts(size_t len) "len %zu"
-pci_nvme_err_zasl(size_t len) "len %zu"
-pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8""
-pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64""
-pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64""
-pci_nvme_err_cfs(void) "controller fatal status"
-pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16""
-pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8""
-pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
-pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
-pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32""
-pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
-pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64""
-pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
-pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
-pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
-pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
-pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64""
-pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64""
-pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64""
-pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64""
-pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32""
-pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64""
-pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64""
-pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64""
-pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64""
-pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64""
-pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64""
-pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64""
-pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16""
-pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16""
-pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded"
-pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded"
-pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32""
-pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32""
-pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
-pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
-pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
-pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
-pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
-pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
-pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
-pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
-pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
-pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
-pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
-pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
-pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
-pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
-pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
-pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
-pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16""
-pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
-pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
-pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
-pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
-pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
-pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
-pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
-pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
-pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
-pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
-pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
-pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
-pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u"
-pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
-pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
-pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32""
-pci_nvme_err_startfail(void) "setting controller enable bit failed"
-pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8""
-
-# Traces for undefined behavior
-pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
-pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
-pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
-pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
-pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
-pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
-pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
-pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
-pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
-pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
-pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
-pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
-pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
-pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
-pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
-pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
-pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
-pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
-pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
-pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
-pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
-pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field"
-
# 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"
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index f5e9682703..c6210fad0c 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -47,9 +47,13 @@ static const int user_feature_bits[] = {
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_F_NOTIFY_ON_EMPTY,
+ VIRTIO_F_RING_PACKED,
+ VIRTIO_F_IOMMU_PLATFORM,
VHOST_INVALID_FEATURE_BIT
};
+static void vhost_user_blk_event(void *opaque, QEMUChrEvent event);
+
static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
VHostUserBlk *s = VHOST_USER_BLK(vdev);
@@ -309,7 +313,7 @@ static void vhost_user_blk_reset(VirtIODevice *vdev)
vhost_dev_free_inflight(s->inflight);
}
-static int vhost_user_blk_connect(DeviceState *dev)
+static int vhost_user_blk_connect(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
@@ -320,6 +324,7 @@ static int vhost_user_blk_connect(DeviceState *dev)
}
s->connected = true;
+ s->dev.num_queues = s->num_queues;
s->dev.nvqs = s->num_queues;
s->dev.vqs = s->vhost_vqs;
s->dev.vq_index = 0;
@@ -329,8 +334,7 @@ static int vhost_user_blk_connect(DeviceState *dev)
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
- error_report("vhost-user-blk: vhost initialization failed: %s",
- strerror(-ret));
+ error_setg_errno(errp, -ret, "vhost initialization failed");
return ret;
}
@@ -338,8 +342,7 @@ static int vhost_user_blk_connect(DeviceState *dev)
if (virtio_device_started(vdev, vdev->status)) {
ret = vhost_user_blk_start(vdev);
if (ret < 0) {
- error_report("vhost-user-blk: vhost start failed: %s",
- strerror(-ret));
+ error_setg_errno(errp, -ret, "vhost start failed");
return ret;
}
}
@@ -362,19 +365,6 @@ static void vhost_user_blk_disconnect(DeviceState *dev)
vhost_dev_cleanup(&s->dev);
}
-static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
- bool realized);
-
-static void vhost_user_blk_event_realize(void *opaque, QEMUChrEvent event)
-{
- vhost_user_blk_event(opaque, event, false);
-}
-
-static void vhost_user_blk_event_oper(void *opaque, QEMUChrEvent event)
-{
- vhost_user_blk_event(opaque, event, true);
-}
-
static void vhost_user_blk_chr_closed_bh(void *opaque)
{
DeviceState *dev = opaque;
@@ -382,36 +372,27 @@ static void vhost_user_blk_chr_closed_bh(void *opaque)
VHostUserBlk *s = VHOST_USER_BLK(vdev);
vhost_user_blk_disconnect(dev);
- qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL,
- vhost_user_blk_event_oper, NULL, opaque, NULL, true);
+ qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event,
+ NULL, opaque, NULL, true);
}
-static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
- bool realized)
+static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
{
DeviceState *dev = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
+ Error *local_err = NULL;
switch (event) {
case CHR_EVENT_OPENED:
- if (vhost_user_blk_connect(dev) < 0) {
+ if (vhost_user_blk_connect(dev, &local_err) < 0) {
+ error_report_err(local_err);
qemu_chr_fe_disconnect(&s->chardev);
return;
}
break;
case CHR_EVENT_CLOSED:
- /*
- * Closing the connection should happen differently on device
- * initialization and operation stages.
- * On initalization, we want to re-start vhost_dev initialization
- * from the very beginning right away when the connection is closed,
- * so we clean up vhost_dev on each connection closing.
- * On operation, we want to postpone vhost_dev cleanup to let the
- * other code perform its own cleanup sequence using vhost_dev data
- * (e.g. vhost_dev_set_log).
- */
- if (realized && !runstate_check(RUN_STATE_SHUTDOWN)) {
+ if (!runstate_check(RUN_STATE_SHUTDOWN)) {
/*
* A close event may happen during a read/write, but vhost
* code assumes the vhost_dev remains setup, so delay the
@@ -431,8 +412,6 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
* knowing its type (in this case vhost-user).
*/
s->dev.started = false;
- } else {
- vhost_user_blk_disconnect(dev);
}
break;
case CHR_EVENT_BREAK:
@@ -447,11 +426,10 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
- Error *err = NULL;
int i, ret;
if (!s->chardev.chr) {
- error_setg(errp, "vhost-user-blk: chardev is mandatory");
+ error_setg(errp, "chardev is mandatory");
return;
}
@@ -459,16 +437,16 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
s->num_queues = 1;
}
if (!s->num_queues || s->num_queues > VIRTIO_QUEUE_MAX) {
- error_setg(errp, "vhost-user-blk: invalid number of IO queues");
+ error_setg(errp, "invalid number of IO queues");
return;
}
if (!s->queue_size) {
- error_setg(errp, "vhost-user-blk: queue size must be non-zero");
+ error_setg(errp, "queue size must be non-zero");
return;
}
if (s->queue_size > VIRTQUEUE_MAX_SIZE) {
- error_setg(errp, "vhost-user-blk: queue size must not exceed %d",
+ error_setg(errp, "queue size must not exceed %d",
VIRTQUEUE_MAX_SIZE);
return;
}
@@ -490,34 +468,31 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues);
s->connected = false;
- qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL,
- vhost_user_blk_event_realize, NULL, (void *)dev,
- NULL, true);
-
-reconnect:
- if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) {
- error_report_err(err);
+ if (qemu_chr_fe_wait_connected(&s->chardev, errp) < 0) {
goto virtio_err;
}
- /* check whether vhost_user_blk_connect() failed or not */
- if (!s->connected) {
- goto reconnect;
+ if (vhost_user_blk_connect(dev, errp) < 0) {
+ qemu_chr_fe_disconnect(&s->chardev);
+ goto virtio_err;
}
+ assert(s->connected);
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
sizeof(struct virtio_blk_config));
if (ret < 0) {
- error_report("vhost-user-blk: get block config failed");
- goto reconnect;
+ error_setg(errp, "vhost-user-blk: get block config failed");
+ goto vhost_err;
}
- /* we're fully initialized, now we can operate, so change the handler */
+ /* we're fully initialized, now we can operate, so add the handler */
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL,
- vhost_user_blk_event_oper, NULL, (void *)dev,
+ vhost_user_blk_event, NULL, (void *)dev,
NULL, true);
return;
+vhost_err:
+ vhost_dev_cleanup(&s->dev);
virtio_err:
g_free(s->vhost_vqs);
s->vhost_vqs = NULL;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index d28979efb8..f139cd7cc9 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -40,7 +40,7 @@
* Starting from the discard feature, we can use this array to properly
* set the config size depending on the features enabled.
*/
-static VirtIOFeature feature_sizes[] = {
+static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 83754a4344..674953f1ad 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -728,6 +728,8 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
XenBlockDrive *drive = NULL;
QDict *file_layer;
QDict *driver_layer;
+ struct stat st;
+ int rc;
if (params) {
char **v = g_strsplit(params, ":", 2);
@@ -761,7 +763,17 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
file_layer = qdict_new();
driver_layer = qdict_new();
- qdict_put_str(file_layer, "driver", "file");
+ rc = stat(filename, &st);
+ if (rc) {
+ error_setg_errno(errp, errno, "Could not stat file '%s'", filename);
+ goto done;
+ }
+ if (S_ISBLK(st.st_mode)) {
+ qdict_put_str(file_layer, "driver", "host_device");
+ } else {
+ qdict_put_str(file_layer, "driver", "file");
+ }
+
qdict_put_str(file_layer, "filename", filename);
g_free(filename);
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
deleted file mode 100644
index ce30279650..0000000000
--- a/hw/char/lm32_juart.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * LatticeMico32 JTAG UART model.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "chardev/char-fe.h"
-
-#include "hw/char/lm32_juart.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "qom/object.h"
-
-enum {
- LM32_JUART_MIN_SAVE_VERSION = 0,
- LM32_JUART_CURRENT_SAVE_VERSION = 0,
- LM32_JUART_MAX_SAVE_VERSION = 0,
-};
-
-enum {
- JTX_FULL = (1<<8),
-};
-
-enum {
- JRX_FULL = (1<<8),
-};
-
-OBJECT_DECLARE_SIMPLE_TYPE(LM32JuartState, LM32_JUART)
-
-struct LM32JuartState {
- SysBusDevice parent_obj;
-
- CharBackend chr;
-
- uint32_t jtx;
- uint32_t jrx;
-};
-
-uint32_t lm32_juart_get_jtx(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_get_jtx(s->jtx);
- return s->jtx;
-}
-
-uint32_t lm32_juart_get_jrx(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_get_jrx(s->jrx);
- return s->jrx;
-}
-
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = LM32_JUART(d);
- unsigned char ch = jtx & 0xff;
-
- trace_lm32_juart_set_jtx(s->jtx);
-
- s->jtx = jtx;
- /* 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);
-}
-
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- trace_lm32_juart_set_jrx(s->jrx);
- s->jrx &= ~JRX_FULL;
-}
-
-static void juart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32JuartState *s = opaque;
-
- s->jrx = *buf | JRX_FULL;
-}
-
-static int juart_can_rx(void *opaque)
-{
- LM32JuartState *s = opaque;
-
- return !(s->jrx & JRX_FULL);
-}
-
-static void juart_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static void juart_reset(DeviceState *d)
-{
- LM32JuartState *s = LM32_JUART(d);
-
- s->jtx = 0;
- s->jrx = 0;
-}
-
-static void lm32_juart_realize(DeviceState *dev, Error **errp)
-{
- LM32JuartState *s = LM32_JUART(dev);
-
- qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx,
- juart_event, NULL, s, NULL, true);
-}
-
-static const VMStateDescription vmstate_lm32_juart = {
- .name = "lm32-juart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(jtx, LM32JuartState),
- VMSTATE_UINT32(jrx, LM32JuartState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property lm32_juart_properties[] = {
- DEFINE_PROP_CHR("chardev", LM32JuartState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_juart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = juart_reset;
- dc->vmsd = &vmstate_lm32_juart;
- device_class_set_props(dc, lm32_juart_properties);
- dc->realize = lm32_juart_realize;
-}
-
-static const TypeInfo lm32_juart_info = {
- .name = TYPE_LM32_JUART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32JuartState),
- .class_init = lm32_juart_class_init,
-};
-
-static void lm32_juart_register_types(void)
-{
- type_register_static(&lm32_juart_info);
-}
-
-type_init(lm32_juart_register_types)
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
deleted file mode 100644
index d8e0331311..0000000000
--- a/hw/char/lm32_uart.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * QEMU model of the LatticeMico32 UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://www.latticesemi.com/documents/mico32uart.pdf
- */
-
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "chardev/char-fe.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- R_RXTX = 0,
- R_IER,
- R_IIR,
- R_LCR,
- R_MCR,
- R_LSR,
- R_MSR,
- R_DIV,
- R_MAX
-};
-
-enum {
- IER_RBRI = (1<<0),
- IER_THRI = (1<<1),
- IER_RLSI = (1<<2),
- IER_MSI = (1<<3),
-};
-
-enum {
- IIR_STAT = (1<<0),
- IIR_ID0 = (1<<1),
- IIR_ID1 = (1<<2),
-};
-
-enum {
- LCR_WLS0 = (1<<0),
- LCR_WLS1 = (1<<1),
- LCR_STB = (1<<2),
- LCR_PEN = (1<<3),
- LCR_EPS = (1<<4),
- LCR_SP = (1<<5),
- LCR_SB = (1<<6),
-};
-
-enum {
- MCR_DTR = (1<<0),
- MCR_RTS = (1<<1),
-};
-
-enum {
- LSR_DR = (1<<0),
- LSR_OE = (1<<1),
- LSR_PE = (1<<2),
- LSR_FE = (1<<3),
- LSR_BI = (1<<4),
- LSR_THRE = (1<<5),
- LSR_TEMT = (1<<6),
-};
-
-enum {
- MSR_DCTS = (1<<0),
- MSR_DDSR = (1<<1),
- MSR_TERI = (1<<2),
- MSR_DDCD = (1<<3),
- MSR_CTS = (1<<4),
- MSR_DSR = (1<<5),
- MSR_RI = (1<<6),
- MSR_DCD = (1<<7),
-};
-
-#define TYPE_LM32_UART "lm32-uart"
-OBJECT_DECLARE_SIMPLE_TYPE(LM32UartState, LM32_UART)
-
-struct LM32UartState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- CharBackend chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-
-static void uart_update_irq(LM32UartState *s)
-{
- unsigned int irq;
-
- if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
- && (s->regs[R_IER] & IER_RLSI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
- } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1;
- } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID0;
- } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
- irq = 1;
- s->regs[R_IIR] = 0;
- } else {
- irq = 0;
- s->regs[R_IIR] = IIR_STAT;
- }
-
- trace_lm32_uart_irq_state(irq);
- qemu_set_irq(s->irq, irq);
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LM32UartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[R_RXTX];
- s->regs[R_LSR] &= ~LSR_DR;
- uart_update_irq(s);
- qemu_chr_fe_accept_input(&s->chr);
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- r = s->regs[addr];
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- error_report("lm32_uart: read access to write only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_lm32_uart_memory_read(addr << 2, r);
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LM32UartState *s = opaque;
- unsigned char ch = value;
-
- trace_lm32_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- /* 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);
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- s->regs[addr] = value;
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- error_report("lm32_uart: write access to read only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32UartState *s = opaque;
-
- if (s->regs[R_LSR] & LSR_DR) {
- s->regs[R_LSR] |= LSR_OE;
- }
-
- s->regs[R_LSR] |= LSR_DR;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- LM32UartState *s = opaque;
-
- return !(s->regs[R_LSR] & LSR_DR);
-}
-
-static void uart_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static void uart_reset(DeviceState *d)
-{
- LM32UartState *s = LM32_UART(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
-}
-
-static void lm32_uart_init(Object *obj)
-{
- LM32UartState *s = LM32_UART(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, obj, &uart_ops, s,
- "uart", R_MAX * 4);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void lm32_uart_realize(DeviceState *dev, Error **errp)
-{
- LM32UartState *s = LM32_UART(dev);
-
- qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, NULL, s, NULL, true);
-}
-
-static const VMStateDescription vmstate_lm32_uart = {
- .name = "lm32-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property lm32_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", LM32UartState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = uart_reset;
- dc->vmsd = &vmstate_lm32_uart;
- device_class_set_props(dc, lm32_uart_properties);
- dc->realize = lm32_uart_realize;
-}
-
-static const TypeInfo lm32_uart_info = {
- .name = TYPE_LM32_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32UartState),
- .instance_init = lm32_uart_init,
- .class_init = lm32_uart_class_init,
-};
-
-static void lm32_uart_register_types(void)
-{
- type_register_static(&lm32_uart_info);
-}
-
-type_init(lm32_uart_register_types)
diff --git a/hw/char/meson.build b/hw/char/meson.build
index da5bb8b762..8361d0ab28 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -8,9 +8,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c'))
softmmu_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c'))
softmmu_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c'))
softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c'))
-softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_juart.c'))
-softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_uart.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-uart.c'))
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c'))
softmmu_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c'))
softmmu_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
@@ -19,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
softmmu_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c'))
softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c'))
+softmmu_ss.add(when: 'CONFIG_SHAKTI', if_true: files('shakti_uart.c'))
softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c'))
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
deleted file mode 100644
index cb1b3470ad..0000000000
--- a/hw/char/milkymist-uart.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * QEMU model of the Milkymist UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/uart.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "chardev/char-fe.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- R_RXTX = 0,
- R_DIV,
- R_STAT,
- R_CTRL,
- R_DBG,
- R_MAX
-};
-
-enum {
- STAT_THRE = (1<<0),
- STAT_RX_EVT = (1<<1),
- STAT_TX_EVT = (1<<2),
-};
-
-enum {
- CTRL_RX_IRQ_EN = (1<<0),
- CTRL_TX_IRQ_EN = (1<<1),
- CTRL_THRU_EN = (1<<2),
-};
-
-enum {
- DBG_BREAK_EN = (1<<0),
-};
-
-#define TYPE_MILKYMIST_UART "milkymist-uart"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistUartState, MILKYMIST_UART)
-
-struct MilkymistUartState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- CharBackend chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-
-static void uart_update_irq(MilkymistUartState *s)
-{
- int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
- int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
- int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
- int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
-
- if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
- trace_milkymist_uart_raise_irq();
- qemu_irq_raise(s->irq);
- } else {
- trace_milkymist_uart_lower_irq();
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[addr];
- break;
- case R_DIV:
- case R_STAT:
- case R_CTRL:
- case R_DBG:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_uart_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- unsigned char ch = value;
-
- trace_milkymist_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- s->regs[R_STAT] |= STAT_TX_EVT;
- break;
- case R_DIV:
- case R_CTRL:
- case R_DBG:
- s->regs[addr] = value;
- break;
-
- case R_STAT:
- /* write one to clear bits */
- s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
- qemu_chr_fe_accept_input(&s->chr);
- break;
-
- default:
- error_report("milkymist_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_mmio_ops = {
- .read = uart_read,
- .write = uart_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- MilkymistUartState *s = opaque;
-
- assert(!(s->regs[R_STAT] & STAT_RX_EVT));
-
- s->regs[R_STAT] |= STAT_RX_EVT;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- MilkymistUartState *s = opaque;
-
- return !(s->regs[R_STAT] & STAT_RX_EVT);
-}
-
-static void uart_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static void milkymist_uart_reset(DeviceState *d)
-{
- MilkymistUartState *s = MILKYMIST_UART(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* THRE is always set */
- s->regs[R_STAT] = STAT_THRE;
-}
-
-static void milkymist_uart_realize(DeviceState *dev, Error **errp)
-{
- MilkymistUartState *s = MILKYMIST_UART(dev);
-
- qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx,
- uart_event, NULL, s, NULL, true);
-}
-
-static void milkymist_uart_init(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- MilkymistUartState *s = MILKYMIST_UART(obj);
-
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s,
- "milkymist-uart", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->regs_region);
-}
-
-static const VMStateDescription vmstate_milkymist_uart = {
- .name = "milkymist-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", MilkymistUartState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_uart_realize;
- dc->reset = milkymist_uart_reset;
- dc->vmsd = &vmstate_milkymist_uart;
- device_class_set_props(dc, milkymist_uart_properties);
-}
-
-static const TypeInfo milkymist_uart_info = {
- .name = TYPE_MILKYMIST_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistUartState),
- .instance_init = milkymist_uart_init,
- .class_init = milkymist_uart_class_init,
-};
-
-static void milkymist_uart_register_types(void)
-{
- type_register_static(&milkymist_uart_info);
-}
-
-type_init(milkymist_uart_register_types)
diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c
new file mode 100644
index 0000000000..6870821325
--- /dev/null
+++ b/hw/char/shakti_uart.c
@@ -0,0 +1,185 @@
+/*
+ * SHAKTI UART
+ *
+ * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ * 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 "hw/char/shakti_uart.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "qemu/log.h"
+
+static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size)
+{
+ ShaktiUartState *s = opaque;
+
+ switch (addr) {
+ case SHAKTI_UART_BAUD:
+ return s->uart_baud;
+ case SHAKTI_UART_RX:
+ qemu_chr_fe_accept_input(&s->chr);
+ s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY;
+ return s->uart_rx;
+ case SHAKTI_UART_STATUS:
+ return s->uart_status;
+ case SHAKTI_UART_DELAY:
+ return s->uart_delay;
+ case SHAKTI_UART_CONTROL:
+ return s->uart_control;
+ case SHAKTI_UART_INT_EN:
+ return s->uart_interrupt;
+ case SHAKTI_UART_IQ_CYCLES:
+ return s->uart_iq_cycles;
+ case SHAKTI_UART_RX_THRES:
+ return s->uart_rx_threshold;
+ default:
+ /* Also handles TX REG which is write only */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ }
+
+ return 0;
+}
+
+static void shakti_uart_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ ShaktiUartState *s = opaque;
+ uint32_t value = data;
+ uint8_t ch;
+
+ switch (addr) {
+ case SHAKTI_UART_BAUD:
+ s->uart_baud = value;
+ break;
+ case SHAKTI_UART_TX:
+ ch = value;
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
+ s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL;
+ break;
+ case SHAKTI_UART_STATUS:
+ s->uart_status = value;
+ break;
+ case SHAKTI_UART_DELAY:
+ s->uart_delay = value;
+ break;
+ case SHAKTI_UART_CONTROL:
+ s->uart_control = value;
+ break;
+ case SHAKTI_UART_INT_EN:
+ s->uart_interrupt = value;
+ break;
+ case SHAKTI_UART_IQ_CYCLES:
+ s->uart_iq_cycles = value;
+ break;
+ case SHAKTI_UART_RX_THRES:
+ s->uart_rx_threshold = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps shakti_uart_ops = {
+ .read = shakti_uart_read,
+ .write = shakti_uart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {.min_access_size = 1, .max_access_size = 4},
+ .valid = {.min_access_size = 1, .max_access_size = 4},
+};
+
+static void shakti_uart_reset(DeviceState *dev)
+{
+ ShaktiUartState *s = SHAKTI_UART(dev);
+
+ s->uart_baud = SHAKTI_UART_BAUD_DEFAULT;
+ s->uart_tx = 0x0;
+ s->uart_rx = 0x0;
+ s->uart_status = 0x0000;
+ s->uart_delay = 0x0000;
+ s->uart_control = SHAKTI_UART_CONTROL_DEFAULT;
+ s->uart_interrupt = 0x0000;
+ s->uart_iq_cycles = 0x00;
+ s->uart_rx_threshold = 0x00;
+}
+
+static int shakti_uart_can_receive(void *opaque)
+{
+ ShaktiUartState *s = opaque;
+
+ return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY);
+}
+
+static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ ShaktiUartState *s = opaque;
+
+ s->uart_rx = *buf;
+ s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY;
+}
+
+static void shakti_uart_realize(DeviceState *dev, Error **errp)
+{
+ ShaktiUartState *sus = SHAKTI_UART(dev);
+ qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive,
+ shakti_uart_receive, NULL, NULL, sus, NULL, true);
+}
+
+static void shakti_uart_instance_init(Object *obj)
+{
+ ShaktiUartState *sus = SHAKTI_UART(obj);
+ memory_region_init_io(&sus->mmio,
+ obj,
+ &shakti_uart_ops,
+ sus,
+ TYPE_SHAKTI_UART,
+ 0x1000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio);
+}
+
+static Property shakti_uart_properties[] = {
+ DEFINE_PROP_CHR("chardev", ShaktiUartState, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void shakti_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->reset = shakti_uart_reset;
+ dc->realize = shakti_uart_realize;
+ device_class_set_props(dc, shakti_uart_properties);
+}
+
+static const TypeInfo shakti_uart_info = {
+ .name = TYPE_SHAKTI_UART,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ShaktiUartState),
+ .class_init = shakti_uart_class_init,
+ .instance_init = shakti_uart_instance_init,
+};
+
+static void shakti_uart_register_types(void)
+{
+ type_register_static(&shakti_uart_info);
+}
+type_init(shakti_uart_register_types)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 76d52938ea..2e6e6b119a 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -35,23 +35,6 @@ grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
-# lm32_juart.c
-lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x"
-lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x"
-lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x"
-lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x"
-
-# lm32_uart.c
-lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-lm32_uart_irq_state(int level) "irq state %d"
-
-# milkymist-uart.c
-milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_uart_raise_irq(void) "Raise IRQ"
-milkymist_uart_lower_irq(void) "Lower IRQ"
-
# escc.c
escc_put_queue(char channel, int b) "channel %c put: 0x%02x"
escc_get_queue(char channel, int val) "channel %c get 0x%02x"
@@ -90,6 +73,10 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1"
nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
+# shakti_uart.c
+shakti_uart_read(uint64_t addr, uint16_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx16 " size %u"
+shakti_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
+
# exynos4210_uart.c
exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)"
exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready"
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 0f5ce43d0c..1bf0e687b9 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1234,6 +1234,7 @@ void machine_run_board_init(MachineState *machine)
"on", false);
}
+ accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator));
machine_class->init(machine);
phase_advance(PHASE_MACHINE_INITIALIZED);
}
diff --git a/hw/core/numa.c b/hw/core/numa.c
index ac6bed5817..1058d3697b 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -802,9 +802,27 @@ void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms)
}
}
+static int ram_block_notify_add_single(RAMBlock *rb, void *opaque)
+{
+ const ram_addr_t max_size = qemu_ram_get_max_length(rb);
+ const ram_addr_t size = qemu_ram_get_used_length(rb);
+ void *host = qemu_ram_get_host_addr(rb);
+ RAMBlockNotifier *notifier = opaque;
+
+ if (host) {
+ notifier->ram_block_added(notifier, host, size, max_size);
+ }
+ return 0;
+}
+
void ram_block_notifier_add(RAMBlockNotifier *n)
{
QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next);
+
+ /* Notify about all existing ram blocks. */
+ if (n->ram_block_added) {
+ qemu_ram_foreach_block(ram_block_notify_add_single, n);
+ }
}
void ram_block_notifier_remove(RAMBlockNotifier *n)
@@ -812,20 +830,35 @@ void ram_block_notifier_remove(RAMBlockNotifier *n)
QLIST_REMOVE(n, next);
}
-void ram_block_notify_add(void *host, size_t size)
+void ram_block_notify_add(void *host, size_t size, size_t max_size)
+{
+ RAMBlockNotifier *notifier;
+
+ QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
+ if (notifier->ram_block_added) {
+ notifier->ram_block_added(notifier, host, size, max_size);
+ }
+ }
+}
+
+void ram_block_notify_remove(void *host, size_t size, size_t max_size)
{
RAMBlockNotifier *notifier;
QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
- notifier->ram_block_added(notifier, host, size);
+ if (notifier->ram_block_removed) {
+ notifier->ram_block_removed(notifier, host, size, max_size);
+ }
}
}
-void ram_block_notify_remove(void *host, size_t size)
+void ram_block_notify_resize(void *host, size_t old_size, size_t new_size)
{
RAMBlockNotifier *notifier;
QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) {
- notifier->ram_block_removed(notifier, host, size);
+ if (notifier->ram_block_resized) {
+ notifier->ram_block_resized(notifier, host, old_size, new_size);
+ }
}
}
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index ca46b5830e..a2306b67d8 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -72,10 +72,6 @@ config BLIZZARD
config FRAMEBUFFER
bool
-config MILKYMIST_TMU2
- bool
- depends on OPENGL && X11
-
config SM501
bool
select I2C
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index a1bea9a3aa..f2b874d5e3 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -45,6 +45,35 @@ static const struct edid_mode {
{ .xres = 640, .yres = 480, .byte = 35, .bit = 5 },
};
+typedef struct Timings {
+ uint32_t xfront;
+ uint32_t xsync;
+ uint32_t xblank;
+
+ uint32_t yfront;
+ uint32_t ysync;
+ uint32_t yblank;
+
+ uint64_t clock;
+} Timings;
+
+static void generate_timings(Timings *timings, uint32_t refresh_rate,
+ uint32_t xres, uint32_t yres)
+{
+ /* pull some realistic looking timings out of thin air */
+ timings->xfront = xres * 25 / 100;
+ timings->xsync = xres * 3 / 100;
+ timings->xblank = xres * 35 / 100;
+
+ timings->yfront = yres * 5 / 1000;
+ timings->ysync = yres * 5 / 1000;
+ timings->yblank = yres * 35 / 1000;
+
+ timings->clock = ((uint64_t)refresh_rate *
+ (xres + timings->xblank) *
+ (yres + timings->yblank)) / 10000000;
+}
+
static void edid_ext_dta(uint8_t *dta)
{
dta[0] = 0x02;
@@ -130,20 +159,39 @@ static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta,
}
}
-static void edid_checksum(uint8_t *edid)
+static void edid_checksum(uint8_t *edid, size_t len)
{
uint32_t sum = 0;
int i;
- for (i = 0; i < 127; i++) {
+ for (i = 0; i < len; i++) {
sum += edid[i];
}
sum &= 0xff;
if (sum) {
- edid[127] = 0x100 - sum;
+ edid[len] = 0x100 - sum;
}
}
+static uint8_t *edid_desc_next(uint8_t *edid, uint8_t *dta, uint8_t *desc)
+{
+ if (desc == NULL) {
+ return NULL;
+ }
+ if (desc + 18 + 18 < edid + 127) {
+ return desc + 18;
+ }
+ if (dta) {
+ if (desc < edid + 127) {
+ return dta + dta[2];
+ }
+ if (desc + 18 + 18 < dta + 127) {
+ return desc + 18;
+ }
+ }
+ return NULL;
+}
+
static void edid_desc_type(uint8_t *desc, uint8_t type)
{
desc[0] = 0;
@@ -181,8 +229,8 @@ static void edid_desc_ranges(uint8_t *desc)
desc[7] = 30;
desc[8] = 160;
- /* max dot clock (1200 MHz) */
- desc[9] = 1200 / 10;
+ /* max dot clock (2550 MHz) */
+ desc[9] = 2550 / 10;
/* no extended timing information */
desc[10] = 0x01;
@@ -204,42 +252,33 @@ static void edid_desc_dummy(uint8_t *desc)
edid_desc_type(desc, 0x10);
}
-static void edid_desc_timing(uint8_t *desc,
+static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate,
uint32_t xres, uint32_t yres,
uint32_t xmm, uint32_t ymm)
{
- /* pull some realistic looking timings out of thin air */
- uint32_t xfront = xres * 25 / 100;
- uint32_t xsync = xres * 3 / 100;
- uint32_t xblank = xres * 35 / 100;
-
- uint32_t yfront = yres * 5 / 1000;
- uint32_t ysync = yres * 5 / 1000;
- uint32_t yblank = yres * 35 / 1000;
-
- uint32_t clock = 75 * (xres + xblank) * (yres + yblank);
-
- stl_le_p(desc, clock / 10000);
+ Timings timings;
+ generate_timings(&timings, refresh_rate, xres, yres);
+ stl_le_p(desc, timings.clock);
desc[2] = xres & 0xff;
- desc[3] = xblank & 0xff;
+ desc[3] = timings.xblank & 0xff;
desc[4] = (((xres & 0xf00) >> 4) |
- ((xblank & 0xf00) >> 8));
+ ((timings.xblank & 0xf00) >> 8));
desc[5] = yres & 0xff;
- desc[6] = yblank & 0xff;
+ desc[6] = timings.yblank & 0xff;
desc[7] = (((yres & 0xf00) >> 4) |
- ((yblank & 0xf00) >> 8));
+ ((timings.yblank & 0xf00) >> 8));
- desc[8] = xfront & 0xff;
- desc[9] = xsync & 0xff;
+ desc[8] = timings.xfront & 0xff;
+ desc[9] = timings.xsync & 0xff;
- desc[10] = (((yfront & 0x00f) << 4) |
- ((ysync & 0x00f) << 0));
- desc[11] = (((xfront & 0x300) >> 2) |
- ((xsync & 0x300) >> 4) |
- ((yfront & 0x030) >> 2) |
- ((ysync & 0x030) >> 4));
+ desc[10] = (((timings.yfront & 0x00f) << 4) |
+ ((timings.ysync & 0x00f) << 0));
+ desc[11] = (((timings.xfront & 0x300) >> 2) |
+ ((timings.xsync & 0x300) >> 4) |
+ ((timings.yfront & 0x030) >> 2) |
+ ((timings.ysync & 0x030) >> 4));
desc[12] = xmm & 0xff;
desc[13] = ymm & 0xff;
@@ -297,14 +336,61 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res)
return res * 254 / 10 / dpi;
}
+static void init_displayid(uint8_t *did)
+{
+ did[0] = 0x70; /* display id extension */
+ did[1] = 0x13; /* version 1.3 */
+ did[2] = 4; /* length */
+ did[3] = 0x03; /* product type (0x03 == standalone display device) */
+ edid_checksum(did + 1, did[2] + 4);
+}
+
+static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate,
+ uint32_t xres, uint32_t yres,
+ uint32_t xmm, uint32_t ymm)
+{
+ Timings timings;
+ generate_timings(&timings, refresh_rate, xres, yres);
+
+ did[0] = 0x70; /* display id extension */
+ did[1] = 0x13; /* version 1.3 */
+ did[2] = 23; /* length */
+ did[3] = 0x03; /* product type (0x03 == standalone display device) */
+
+ did[5] = 0x03; /* Detailed Timings Data Block */
+ did[6] = 0x00; /* revision */
+ did[7] = 0x14; /* block length */
+
+ did[8] = timings.clock & 0xff;
+ did[9] = (timings.clock & 0xff00) >> 8;
+ did[10] = (timings.clock & 0xff0000) >> 16;
+
+ did[11] = 0x88; /* leave aspect ratio undefined */
+
+ stw_le_p(did + 12, 0xffff & (xres - 1));
+ stw_le_p(did + 14, 0xffff & (timings.xblank - 1));
+ stw_le_p(did + 16, 0xffff & (timings.xfront - 1));
+ stw_le_p(did + 18, 0xffff & (timings.xsync - 1));
+
+ stw_le_p(did + 20, 0xffff & (yres - 1));
+ stw_le_p(did + 22, 0xffff & (timings.yblank - 1));
+ stw_le_p(did + 24, 0xffff & (timings.yfront - 1));
+ stw_le_p(did + 26, 0xffff & (timings.ysync - 1));
+
+ edid_checksum(did + 1, did[2] + 4);
+}
+
void qemu_edid_generate(uint8_t *edid, size_t size,
qemu_edid_info *info)
{
- uint32_t desc = 54;
+ uint8_t *desc = edid + 54;
uint8_t *xtra3 = NULL;
uint8_t *dta = NULL;
+ uint8_t *did = NULL;
uint32_t width_mm, height_mm;
+ uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000;
uint32_t dpi = 100; /* if no width_mm/height_mm */
+ uint32_t large_screen = 0;
/* =============== set defaults =============== */
@@ -320,6 +406,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
if (!info->prefy) {
info->prefy = 768;
}
+ if (info->prefx >= 4096 || info->prefy >= 4096) {
+ large_screen = 1;
+ }
if (info->width_mm && info->height_mm) {
width_mm = info->width_mm;
height_mm = info->height_mm;
@@ -337,6 +426,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
edid_ext_dta(dta);
}
+ if (size >= 384 && large_screen) {
+ did = edid + 256;
+ edid[126]++;
+ init_displayid(did);
+ }
+
/* =============== header information =============== */
/* fixed */
@@ -401,40 +496,55 @@ void qemu_edid_generate(uint8_t *edid, size_t size,
/* =============== descriptor blocks =============== */
- edid_desc_timing(edid + desc, info->prefx, info->prefy,
- width_mm, height_mm);
- desc += 18;
+ if (!large_screen) {
+ /* The DTD section has only 12 bits to store the resolution */
+ edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy,
+ width_mm, height_mm);
+ desc = edid_desc_next(edid, dta, desc);
+ }
- edid_desc_ranges(edid + desc);
- desc += 18;
+ xtra3 = desc;
+ edid_desc_xtra3_std(xtra3);
+ desc = edid_desc_next(edid, dta, desc);
+ edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy);
+ /*
+ * dta video data block is finished at thus point,
+ * so dta descriptor offsets don't move any more.
+ */
+
+ edid_desc_ranges(desc);
+ desc = edid_desc_next(edid, dta, desc);
- if (info->name) {
- edid_desc_text(edid + desc, 0xfc, info->name);
- desc += 18;
+ if (desc && info->name) {
+ edid_desc_text(desc, 0xfc, info->name);
+ desc = edid_desc_next(edid, dta, desc);
}
- if (info->serial) {
- edid_desc_text(edid + desc, 0xff, info->serial);
- desc += 18;
+ if (desc && info->serial) {
+ edid_desc_text(desc, 0xff, info->serial);
+ desc = edid_desc_next(edid, dta, desc);
}
- if (desc < 126) {
- xtra3 = edid + desc;
- edid_desc_xtra3_std(xtra3);
- desc += 18;
+ while (desc) {
+ edid_desc_dummy(desc);
+ desc = edid_desc_next(edid, dta, desc);
}
- while (desc < 126) {
- edid_desc_dummy(edid + desc);
- desc += 18;
+ /* =============== display id extensions =============== */
+
+ if (did && large_screen) {
+ qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy,
+ width_mm, height_mm);
}
/* =============== finish up =============== */
- edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy);
- edid_checksum(edid);
+ edid_checksum(edid, 127);
if (dta) {
- edid_checksum(dta);
+ edid_checksum(dta, 127);
+ }
+ if (did) {
+ edid_checksum(did, 127);
}
}
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 9d79e3951d..aaf797c5e9 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -48,7 +48,6 @@ endif
softmmu_ss.add(when: 'CONFIG_DPCD', if_true: files('dpcd.c'))
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dp.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-vgafb.c'))
softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c'))
@@ -56,11 +55,14 @@ softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d
if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
virtio_gpu_ss = ss.source_set()
virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU',
- if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl])
- virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'],
- if_true: [files('virtio-gpu-3d.c'), pixman, virgl])
+ if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman])
virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c'))
hw_display_modules += {'virtio-gpu': virtio_gpu_ss}
+
+ virtio_gpu_gl_ss = ss.source_set()
+ virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL', opengl],
+ if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl])
+ hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss}
endif
if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
@@ -70,6 +72,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI')
virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'],
if_true: files('vhost-user-gpu-pci.c'))
hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss}
+
+ virtio_gpu_pci_gl_ss = ss.source_set()
+ virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', 'CONFIG_VIRGL', opengl],
+ if_true: [files('virtio-gpu-pci-gl.c'), pixman])
+ hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss}
endif
if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
@@ -79,9 +86,13 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA')
virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA',
if_true: files('vhost-user-vga.c'))
hw_display_modules += {'virtio-vga': virtio_vga_ss}
+
+ virtio_vga_gl_ss = ss.source_set()
+ virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', 'CONFIG_VIRGL', opengl],
+ if_true: [files('virtio-vga-gl.c'), pixman])
+ hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss}
endif
-specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c'))
specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c'))
modules += { 'hw-display': hw_display_modules }
diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c
deleted file mode 100644
index 02a28c807b..0000000000
--- a/hw/display/milkymist-tmu2.c
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * QEMU model of the Milkymist texture mapping unit.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- * Copyright (c) 2010 Sebastien Bourdeauducq
- * <sebastien.bourdeauducq@lekernel.net>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/tmu2.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qapi/error.h"
-#include "hw/display/milkymist_tmu2.h"
-
-#include <X11/Xlib.h>
-#include <epoxy/gl.h>
-#include <epoxy/glx.h>
-#include "qom/object.h"
-
-enum {
- R_CTL = 0,
- R_HMESHLAST,
- R_VMESHLAST,
- R_BRIGHTNESS,
- R_CHROMAKEY,
- R_VERTICESADDR,
- R_TEXFBUF,
- R_TEXHRES,
- R_TEXVRES,
- R_TEXHMASK,
- R_TEXVMASK,
- R_DSTFBUF,
- R_DSTHRES,
- R_DSTVRES,
- R_DSTHOFFSET,
- R_DSTVOFFSET,
- R_DSTSQUAREW,
- R_DSTSQUAREH,
- R_ALPHA,
- R_MAX
-};
-
-enum {
- CTL_START_BUSY = (1<<0),
- CTL_CHROMAKEY = (1<<1),
-};
-
-enum {
- MAX_BRIGHTNESS = 63,
- MAX_ALPHA = 63,
-};
-
-enum {
- MESH_MAXSIZE = 128,
-};
-
-struct vertex {
- int x;
- int y;
-} QEMU_PACKED;
-
-#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistTMU2State, MILKYMIST_TMU2)
-
-struct MilkymistTMU2State {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- Chardev *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-
- Display *dpy;
- GLXFBConfig glx_fb_config;
- GLXContext glx_context;
-};
-
-static const int glx_fbconfig_attr[] = {
- GLX_GREEN_SIZE, 5,
- GLX_GREEN_SIZE, 6,
- GLX_BLUE_SIZE, 5,
- None
-};
-
-static int tmu2_glx_init(MilkymistTMU2State *s)
-{
- GLXFBConfig *configs;
- int nelements;
-
- s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
- if (s->dpy == NULL) {
- return 1;
- }
-
- configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- return 1;
- }
-
- s->glx_fb_config = *configs;
- XFree(configs);
-
- /* FIXME: call glXDestroyContext() */
- s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
- GLX_RGBA_TYPE, NULL, 1);
- if (s->glx_context == NULL) {
- return 1;
- }
-
- return 0;
-}
-
-static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
- int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
-{
- int x, y;
- int x0, y0, x1, y1;
- int u0, v0, u1, v1, u2, v2, u3, v3;
- double xscale = 1.0 / ((double)(64 * texhres));
- double yscale = 1.0 / ((double)(64 * texvres));
-
- glLoadIdentity();
- glTranslatef(ho, vo, 0);
- glEnable(GL_TEXTURE_2D);
- glBegin(GL_QUADS);
-
- for (y = 0; y < vmeshlast; y++) {
- y0 = y * sh;
- y1 = y0 + sh;
- for (x = 0; x < hmeshlast; x++) {
- x0 = x * sw;
- x1 = x0 + sw;
-
- u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
- v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
- u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
- v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
- u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
- v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
- u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
- v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
-
- glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
- glVertex3i(x0, y0, 0);
- glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
- glVertex3i(x1, y0, 0);
- glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
- glVertex3i(x1, y1, 0);
- glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
- glVertex3i(x0, y1, 0);
- }
- }
-
- glEnd();
-}
-
-static void tmu2_start(MilkymistTMU2State *s)
-{
- int pbuffer_attrib[6] = {
- GLX_PBUFFER_WIDTH,
- 0,
- GLX_PBUFFER_HEIGHT,
- 0,
- GLX_PRESERVED_CONTENTS,
- True
- };
-
- GLXPbuffer pbuffer;
- GLuint texture;
- void *fb;
- hwaddr fb_len;
- void *mesh;
- hwaddr mesh_len;
- float m;
-
- trace_milkymist_tmu2_start();
-
- /* Create and set up a suitable OpenGL context */
- pbuffer_attrib[1] = s->regs[R_DSTHRES];
- pbuffer_attrib[3] = s->regs[R_DSTVRES];
- pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
- glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
-
- /* Fixup endianness. TODO: would it work on BE hosts? */
- glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
- glPixelStorei(GL_PACK_SWAP_BYTES, 1);
-
- /* Row alignment */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
- glPixelStorei(GL_PACK_ALIGNMENT, 2);
-
- /* Read the QEMU source framebuffer into an OpenGL texture */
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- fb_len = 2ULL * s->regs[R_TEXHRES] * s->regs[R_TEXVRES];
- fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, false);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-
- /* Set up texturing options */
- /* WARNING:
- * Many cases of TMU2 masking are not supported by OpenGL.
- * We only implement the most common ones:
- * - full bilinear filtering vs. nearest texel
- * - texture clamping vs. texture wrapping
- */
- if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- }
- if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- }
- if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- } else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
-
- /* Translucency and decay */
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
- glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
-
- /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
- fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, false);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
- glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
-
- /* Map the texture */
- mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
- mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, false);
- if (mesh == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- tmu2_gl_map((struct vertex *)mesh,
- s->regs[R_TEXHRES], s->regs[R_TEXVRES],
- s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
- s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
- s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
- cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
-
- /* Write back the OpenGL framebuffer to the QEMU framebuffer */
- fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
- fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, true);
- if (fb == NULL) {
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
- return;
- }
-
- glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
- GL_UNSIGNED_SHORT_5_6_5, fb);
- cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
-
- /* Free OpenGL allocs */
- glDeleteTextures(1, &texture);
- glXMakeContextCurrent(s->dpy, None, None, NULL);
- glXDestroyPbuffer(s->dpy, pbuffer);
-
- s->regs[R_CTL] &= ~CTL_START_BUSY;
-
- trace_milkymist_tmu2_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static uint64_t tmu2_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_BRIGHTNESS:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_tmu2: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_tmu2_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void tmu2_check_registers(MilkymistTMU2State *s)
-{
- if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
- error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
- }
-
- if (s->regs[R_ALPHA] > MAX_ALPHA) {
- error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
- }
-
- if (s->regs[R_VERTICESADDR] & 0x07) {
- error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
- "aligned");
- }
-
- if (s->regs[R_TEXFBUF] & 0x01) {
- error_report("milkymist_tmu2: texture buffer address has to be "
- "16-bit aligned");
- }
-}
-
-static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistTMU2State *s = opaque;
-
- trace_milkymist_tmu2_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- s->regs[addr] = value;
- if (value & CTL_START_BUSY) {
- tmu2_start(s);
- }
- break;
- case R_BRIGHTNESS:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CHROMAKEY:
- case R_VERTICESADDR:
- case R_TEXFBUF:
- case R_TEXHRES:
- case R_TEXVRES:
- case R_TEXHMASK:
- case R_TEXVMASK:
- case R_DSTFBUF:
- case R_DSTHRES:
- case R_DSTVRES:
- case R_DSTHOFFSET:
- case R_DSTVOFFSET:
- case R_DSTSQUAREW:
- case R_DSTSQUAREH:
- case R_ALPHA:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_tmu2: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- tmu2_check_registers(s);
-}
-
-static const MemoryRegionOps tmu2_mmio_ops = {
- .read = tmu2_read,
- .write = tmu2_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_tmu2_reset(DeviceState *d)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-}
-
-static void milkymist_tmu2_init(Object *obj)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s,
- "milkymist-tmu2", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_tmu2_realize(DeviceState *dev, Error **errp)
-{
- MilkymistTMU2State *s = MILKYMIST_TMU2(dev);
-
- if (tmu2_glx_init(s)) {
- error_setg(errp, "tmu2_glx_init failed");
- }
-}
-
-static const VMStateDescription vmstate_milkymist_tmu2 = {
- .name = "milkymist-tmu2",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_tmu2_realize;
- dc->reset = milkymist_tmu2_reset;
- dc->vmsd = &vmstate_milkymist_tmu2;
-}
-
-static const TypeInfo milkymist_tmu2_info = {
- .name = TYPE_MILKYMIST_TMU2,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistTMU2State),
- .instance_init = milkymist_tmu2_init,
- .class_init = milkymist_tmu2_class_init,
-};
-
-static void milkymist_tmu2_register_types(void)
-{
- type_register_static(&milkymist_tmu2_info);
-}
-
-type_init(milkymist_tmu2_register_types)
-
-DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
- Display *d;
- GLXFBConfig *configs;
- int nelements;
- int ver_major, ver_minor;
-
- /* check that GLX will work */
- d = XOpenDisplay(NULL);
- if (d == NULL) {
- return NULL;
- }
-
- if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
- /*
- * Yeah, sometimes getting the GLX version can fail.
- * Isn't X beautiful?
- */
- XCloseDisplay(d);
- return NULL;
- }
-
- if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
- printf("Your GLX version is %d.%d,"
- "but TMU emulation needs at least 1.3. TMU disabled.\n",
- ver_major, ver_minor);
- XCloseDisplay(d);
- return NULL;
- }
-
- configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
- if (configs == NULL) {
- XCloseDisplay(d);
- return NULL;
- }
-
- XFree(configs);
- XCloseDisplay(d);
-
- dev = qdev_new(TYPE_MILKYMIST_TMU2);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
deleted file mode 100644
index e2c587e2df..0000000000
--- a/hw/display/milkymist-vgafb.c
+++ /dev/null
@@ -1,360 +0,0 @@
-
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/vgafb.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define BITS 8
-#include "migration/vmstate.h"
-#include "milkymist-vgafb_template.h"
-#define BITS 15
-#include "milkymist-vgafb_template.h"
-#define BITS 16
-#include "milkymist-vgafb_template.h"
-#define BITS 24
-#include "milkymist-vgafb_template.h"
-#define BITS 32
-#include "milkymist-vgafb_template.h"
-
-enum {
- R_CTRL = 0,
- R_HRES,
- R_HSYNC_START,
- R_HSYNC_END,
- R_HSCAN,
- R_VRES,
- R_VSYNC_START,
- R_VSYNC_END,
- R_VSCAN,
- R_BASEADDRESS,
- R_BASEADDRESS_ACT,
- R_BURST_COUNT,
- R_DDC,
- R_SOURCE_CLOCK,
- R_MAX
-};
-
-enum {
- CTRL_RESET = (1<<0),
-};
-
-#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistVgafbState, MILKYMIST_VGAFB)
-
-struct MilkymistVgafbState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- MemoryRegionSection fbsection;
- QemuConsole *con;
-
- int invalidate;
- uint32_t fb_offset;
- uint32_t fb_mask;
-
- uint32_t regs[R_MAX];
-};
-
-static int vgafb_enabled(MilkymistVgafbState *s)
-{
- return !(s->regs[R_CTRL] & CTRL_RESET);
-}
-
-static void vgafb_update_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- SysBusDevice *sbd;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width;
- int first = 0;
- int last = 0;
- drawfn fn;
-
- if (!vgafb_enabled(s)) {
- return;
- }
-
- sbd = SYS_BUS_DEVICE(s);
- int dest_width = s->regs[R_HRES];
-
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
- case 8:
- fn = draw_line_8;
- break;
- case 15:
- fn = draw_line_15;
- dest_width *= 2;
- break;
- case 16:
- fn = draw_line_16;
- dest_width *= 2;
- break;
- case 24:
- fn = draw_line_24;
- dest_width *= 3;
- break;
- case 32:
- fn = draw_line_32;
- dest_width *= 4;
- break;
- default:
- hw_error("milkymist_vgafb: bad color depth\n");
- break;
- }
-
- src_width = s->regs[R_HRES] * 2;
- if (s->invalidate) {
- framebuffer_update_memory_section(&s->fbsection,
- sysbus_address_space(sbd),
- s->regs[R_BASEADDRESS] + s->fb_offset,
- s->regs[R_VRES], src_width);
- }
-
- framebuffer_update_display(surface, &s->fbsection,
- s->regs[R_HRES],
- s->regs[R_VRES],
- src_width,
- dest_width,
- 0,
- s->invalidate,
- fn,
- NULL,
- &first, &last);
-
- if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
- }
- s->invalidate = 0;
-}
-
-static void vgafb_invalidate_display(void *opaque)
-{
- MilkymistVgafbState *s = opaque;
- s->invalidate = 1;
-}
-
-static void vgafb_resize(MilkymistVgafbState *s)
-{
- if (!vgafb_enabled(s)) {
- return;
- }
-
- qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
- s->invalidate = 1;
-}
-
-static uint64_t vgafb_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- case R_HRES:
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VRES:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BASEADDRESS:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- r = s->regs[addr];
- break;
- case R_BASEADDRESS_ACT:
- r = s->regs[R_BASEADDRESS];
- break;
-
- default:
- error_report("milkymist_vgafb: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_vgafb_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistVgafbState *s = opaque;
-
- trace_milkymist_vgafb_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_HSYNC_START:
- case R_HSYNC_END:
- case R_HSCAN:
- case R_VSYNC_START:
- case R_VSYNC_END:
- case R_VSCAN:
- case R_BURST_COUNT:
- case R_DDC:
- case R_SOURCE_CLOCK:
- s->regs[addr] = value;
- break;
- case R_BASEADDRESS:
- if (value & 0x1f) {
- error_report("milkymist_vgafb: framebuffer base address have to "
- "be 32 byte aligned");
- break;
- }
- s->regs[addr] = value & s->fb_mask;
- s->invalidate = 1;
- break;
- case R_HRES:
- case R_VRES:
- s->regs[addr] = value;
- vgafb_resize(s);
- break;
- case R_BASEADDRESS_ACT:
- error_report("milkymist_vgafb: write to read-only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
-
- default:
- error_report("milkymist_vgafb: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps vgafb_mmio_ops = {
- .read = vgafb_read,
- .write = vgafb_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_vgafb_reset(DeviceState *d)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_CTRL] = CTRL_RESET;
- s->regs[R_HRES] = 640;
- s->regs[R_VRES] = 480;
- s->regs[R_BASEADDRESS] = 0;
-}
-
-static const GraphicHwOps vgafb_ops = {
- .invalidate = vgafb_invalidate_display,
- .gfx_update = vgafb_update_display,
-};
-
-static void milkymist_vgafb_init(Object *obj)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s,
- "milkymist-vgafb", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_vgafb_realize(DeviceState *dev, Error **errp)
-{
- MilkymistVgafbState *s = MILKYMIST_VGAFB(dev);
-
- s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
-}
-
-static int vgafb_post_load(void *opaque, int version_id)
-{
- vgafb_invalidate_display(opaque);
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_vgafb = {
- .name = "milkymist-vgafb",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = vgafb_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_vgafb_properties[] = {
- DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
- DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = milkymist_vgafb_reset;
- dc->vmsd = &vmstate_milkymist_vgafb;
- device_class_set_props(dc, milkymist_vgafb_properties);
- dc->realize = milkymist_vgafb_realize;
-}
-
-static const TypeInfo milkymist_vgafb_info = {
- .name = TYPE_MILKYMIST_VGAFB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistVgafbState),
- .instance_init = milkymist_vgafb_init,
- .class_init = milkymist_vgafb_class_init,
-};
-
-static void milkymist_vgafb_register_types(void)
-{
- type_register_static(&milkymist_vgafb_info);
-}
-
-type_init(milkymist_vgafb_register_types)
diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h
deleted file mode 100644
index 96137f9709..0000000000
--- a/hw/display/milkymist-vgafb_template.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * QEMU model of the Milkymist VGA framebuffer.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- */
-
-#if BITS == 8
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *to = rgb_to_pixel8(r, g, b); \
- to += 1; \
- } while (0)
-#elif BITS == 15
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 16
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
- to += 2; \
- } while (0)
-#elif BITS == 24
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- uint32_t tmp = rgb_to_pixel24(r, g, b); \
- *(to++) = tmp & 0xff; \
- *(to++) = (tmp >> 8) & 0xff; \
- *(to++) = (tmp >> 16) & 0xff; \
- } while (0)
-#elif BITS == 32
-#define COPY_PIXEL(to, r, g, b) \
- do { \
- *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
- to += 4; \
- } while (0)
-#else
-#error unknown bit depth
-#endif
-
-static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
- int width, int deststep)
-{
- uint16_t rgb565;
- uint8_t r, g, b;
-
- while (width--) {
- rgb565 = lduw_be_p(s);
- r = ((rgb565 >> 11) & 0x1f) << 3;
- g = ((rgb565 >> 5) & 0x3f) << 2;
- b = ((rgb565 >> 0) & 0x1f) << 3;
- COPY_PIXEL(d, r, g, b);
- s += 2;
- }
-}
-
-#undef BITS
-#undef COPY_PIXEL
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 957b8ba994..9fccca18a1 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -13,16 +13,6 @@ xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d"
g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x"
g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x"
-# milkymist-tmu2.c
-milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_tmu2_start(void) "Start TMU"
-milkymist_tmu2_pulse_irq(void) "Pulse IRQ"
-
-# milkymist-vgafb.c
-milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-
# vmware_vga.c
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 48d29630ab..62fb5c38c1 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -49,7 +49,7 @@ struct PCIVGAState {
qemu_edid_info edid_info;
MemoryRegion mmio;
MemoryRegion mrs[4];
- uint8_t edid[256];
+ uint8_t edid[384];
};
#define TYPE_PCI_VGA "pci-vga"
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 836ad50c7b..28a90e30d0 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -39,6 +39,8 @@
//#define DEBUG_VGA_MEM
//#define DEBUG_VGA_REG
+bool have_vga = true;
+
/* 16 state changes per vertical frame @60 Hz */
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 25f8920fdb..afb3ee7d9a 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -25,7 +25,6 @@ virtio_gpu_base_reset(VirtIOGPUBase *g)
int i;
g->enable = 0;
- g->use_virgl_renderer = false;
for (i = 0; i < g->conf.max_outputs; i++) {
g->scanout[i].resource_id = 0;
@@ -162,7 +161,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
return false;
}
- g->use_virgl_renderer = false;
if (virtio_gpu_virgl_enabled(g->conf)) {
error_setg(&g->migration_blocker, "virgl is not yet migratable");
if (migrate_add_blocker(g->migration_blocker, errp) < 0) {
@@ -218,10 +216,8 @@ static void
virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features)
{
static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
- VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
- g->use_virgl_renderer = ((features & virgl) == virgl);
- trace_virtio_gpu_features(g->use_virgl_renderer);
+ trace_virtio_gpu_features(((features & virgl) == virgl));
}
static void
diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
new file mode 100644
index 0000000000..d971b48080
--- /dev/null
+++ b/hw/display/virtio-gpu-gl.c
@@ -0,0 +1,163 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ * Dave Airlie <airlied@redhat.com>
+ * Gerd Hoffmann <kraxel@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 "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-gpu-bswap.h"
+#include "hw/virtio/virtio-gpu-pixman.h"
+#include "hw/qdev-properties.h"
+
+#include <virglrenderer.h>
+
+static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g,
+ struct virtio_gpu_scanout *s,
+ uint32_t resource_id)
+{
+ uint32_t width, height;
+ uint32_t pixels, *data;
+
+ data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
+ if (!data) {
+ return;
+ }
+
+ if (width != s->current_cursor->width ||
+ height != s->current_cursor->height) {
+ free(data);
+ return;
+ }
+
+ pixels = s->current_cursor->width * s->current_cursor->height;
+ memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
+ free(data);
+}
+
+static void virtio_gpu_gl_flushed(VirtIOGPUBase *b)
+{
+ VirtIOGPU *g = VIRTIO_GPU(b);
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(b);
+
+ if (gl->renderer_reset) {
+ gl->renderer_reset = false;
+ virtio_gpu_virgl_reset(g);
+ }
+ virtio_gpu_process_cmdq(g);
+}
+
+static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIOGPU *g = VIRTIO_GPU(vdev);
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev);
+ struct virtio_gpu_ctrl_command *cmd;
+
+ if (!virtio_queue_ready(vq)) {
+ return;
+ }
+
+ if (!gl->renderer_inited) {
+ virtio_gpu_virgl_init(g);
+ gl->renderer_inited = true;
+ }
+
+ cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
+ while (cmd) {
+ cmd->vq = vq;
+ cmd->error = 0;
+ cmd->finished = false;
+ QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
+ cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
+ }
+
+ virtio_gpu_process_cmdq(g);
+ virtio_gpu_virgl_fence_poll(g);
+}
+
+static void virtio_gpu_gl_reset(VirtIODevice *vdev)
+{
+ VirtIOGPU *g = VIRTIO_GPU(vdev);
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev);
+
+ virtio_gpu_reset(vdev);
+
+ if (gl->renderer_inited) {
+ if (g->parent_obj.renderer_blocked) {
+ gl->renderer_reset = true;
+ } else {
+ virtio_gpu_virgl_reset(g);
+ }
+ }
+}
+
+static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
+{
+ VirtIOGPU *g = VIRTIO_GPU(qdev);
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ error_setg(errp, "virgl is not supported on bigendian platforms");
+ return;
+#endif
+
+ if (!display_opengl) {
+ error_setg(errp, "opengl is not available");
+ return;
+ }
+
+ g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
+ VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
+ virtio_gpu_virgl_get_num_capsets(g);
+
+ virtio_gpu_device_realize(qdev, errp);
+}
+
+static Property virtio_gpu_gl_properties[] = {
+ DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
+ VIRTIO_GPU_FLAG_STATS_ENABLED, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass);
+ VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
+
+ vbc->gl_flushed = virtio_gpu_gl_flushed;
+ vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl;
+ vgc->process_cmd = virtio_gpu_virgl_process_cmd;
+ vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data;
+
+ vdc->realize = virtio_gpu_gl_device_realize;
+ vdc->reset = virtio_gpu_gl_reset;
+ device_class_set_props(dc, virtio_gpu_gl_properties);
+}
+
+static const TypeInfo virtio_gpu_gl_info = {
+ .name = TYPE_VIRTIO_GPU_GL,
+ .parent = TYPE_VIRTIO_GPU,
+ .instance_size = sizeof(VirtIOGPUGL),
+ .class_init = virtio_gpu_gl_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_gpu_gl_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c
new file mode 100644
index 0000000000..902dda3452
--- /dev/null
+++ b/hw/display/virtio-gpu-pci-gl.c
@@ -0,0 +1,55 @@
+/*
+ * Virtio video device
+ *
+ * Copyright Red Hat
+ *
+ * Authors:
+ * Dave Airlie
+ *
+ * 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 "qemu/module.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-gpu-pci.h"
+#include "qom/object.h"
+
+#define TYPE_VIRTIO_GPU_GL_PCI "virtio-gpu-gl-pci"
+typedef struct VirtIOGPUGLPCI VirtIOGPUGLPCI;
+DECLARE_INSTANCE_CHECKER(VirtIOGPUGLPCI, VIRTIO_GPU_GL_PCI,
+ TYPE_VIRTIO_GPU_GL_PCI)
+
+struct VirtIOGPUGLPCI {
+ VirtIOGPUPCIBase parent_obj;
+ VirtIOGPUGL vdev;
+};
+
+static void virtio_gpu_gl_initfn(Object *obj)
+{
+ VirtIOGPUGLPCI *dev = VIRTIO_GPU_GL_PCI(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_GPU_GL);
+ VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
+}
+
+static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = {
+ .generic_name = TYPE_VIRTIO_GPU_GL_PCI,
+ .parent = TYPE_VIRTIO_GPU_PCI_BASE,
+ .instance_size = sizeof(VirtIOGPUGLPCI),
+ .instance_init = virtio_gpu_gl_initfn,
+};
+
+static void virtio_gpu_gl_pci_register_types(void)
+{
+ virtio_pci_types_register(&virtio_gpu_gl_pci_info);
+}
+
+type_init(virtio_gpu_gl_pci_register_types)
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-virgl.c
index d98964858e..72c14d9132 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g,
{
struct virtio_gpu_resource_attach_backing att_rb;
struct iovec *res_iovs;
+ uint32_t res_niov;
int ret;
VIRTIO_GPU_FILL_CMD(att_rb);
trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
- ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs);
+ ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov);
if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
}
ret = virgl_renderer_resource_attach_iov(att_rb.resource_id,
- res_iovs, att_rb.nr_entries);
+ res_iovs, res_niov);
if (ret != 0)
- virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries);
+ virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov);
}
static void virgl_resource_detach_backing(VirtIOGPU *g,
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index c9f5e36fd0..db56f0454a 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -39,26 +39,9 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
static void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
struct virtio_gpu_simple_resource *res);
-#ifdef CONFIG_VIRGL
-#include <virglrenderer.h>
-#define VIRGL(_g, _virgl, _simple, ...) \
- do { \
- if (_g->parent_obj.use_virgl_renderer) { \
- _virgl(__VA_ARGS__); \
- } else { \
- _simple(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define VIRGL(_g, _virgl, _simple, ...) \
- do { \
- _simple(__VA_ARGS__); \
- } while (0)
-#endif
-
-static void update_cursor_data_simple(VirtIOGPU *g,
- struct virtio_gpu_scanout *s,
- uint32_t resource_id)
+void virtio_gpu_update_cursor_data(VirtIOGPU *g,
+ struct virtio_gpu_scanout *s,
+ uint32_t resource_id)
{
struct virtio_gpu_simple_resource *res;
uint32_t pixels;
@@ -79,36 +62,10 @@ static void update_cursor_data_simple(VirtIOGPU *g,
pixels * sizeof(uint32_t));
}
-#ifdef CONFIG_VIRGL
-
-static void update_cursor_data_virgl(VirtIOGPU *g,
- struct virtio_gpu_scanout *s,
- uint32_t resource_id)
-{
- uint32_t width, height;
- uint32_t pixels, *data;
-
- data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
- if (!data) {
- return;
- }
-
- if (width != s->current_cursor->width ||
- height != s->current_cursor->height) {
- free(data);
- return;
- }
-
- pixels = s->current_cursor->width * s->current_cursor->height;
- memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t));
- free(data);
-}
-
-#endif
-
static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
{
struct virtio_gpu_scanout *s;
+ VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) {
@@ -131,8 +88,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
s->current_cursor->hot_y = cursor->hot_y;
if (cursor->resource_id > 0) {
- VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple,
- g, s, cursor->resource_id);
+ vgc->update_cursor_data(g, s, cursor->resource_id);
}
dpy_cursor_define(s->con, s->current_cursor);
@@ -608,11 +564,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd,
- uint64_t **addr, struct iovec **iov)
+ uint64_t **addr, struct iovec **iov,
+ uint32_t *niov)
{
struct virtio_gpu_mem_entry *ents;
size_t esize, s;
- int i;
+ int e, v;
if (ab->nr_entries > 16384) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -633,37 +590,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
return -1;
}
- *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
+ *iov = NULL;
if (addr) {
- *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries);
+ *addr = NULL;
}
- for (i = 0; i < ab->nr_entries; i++) {
- uint64_t a = le64_to_cpu(ents[i].addr);
- uint32_t l = le32_to_cpu(ents[i].length);
- hwaddr len = l;
- (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
- a, &len, DMA_DIRECTION_TO_DEVICE);
- (*iov)[i].iov_len = len;
- if (addr) {
- (*addr)[i] = a;
- }
- if (!(*iov)[i].iov_base || len != l) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
- " resource %d element %d\n",
- __func__, ab->resource_id, i);
- if ((*iov)[i].iov_base) {
- i++; /* cleanup the 'i'th map */
+ for (e = 0, v = 0; e < ab->nr_entries; e++) {
+ uint64_t a = le64_to_cpu(ents[e].addr);
+ uint32_t l = le32_to_cpu(ents[e].length);
+ hwaddr len;
+ void *map;
+
+ do {
+ len = l;
+ map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as,
+ a, &len, DMA_DIRECTION_TO_DEVICE);
+ if (!map) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
+ " resource %d element %d\n",
+ __func__, ab->resource_id, e);
+ virtio_gpu_cleanup_mapping_iov(g, *iov, v);
+ g_free(ents);
+ *iov = NULL;
+ if (addr) {
+ g_free(*addr);
+ *addr = NULL;
+ }
+ return -1;
}
- virtio_gpu_cleanup_mapping_iov(g, *iov, i);
- g_free(ents);
- *iov = NULL;
+
+ if (!(v % 16)) {
+ *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16));
+ if (addr) {
+ *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16));
+ }
+ }
+ (*iov)[v].iov_base = map;
+ (*iov)[v].iov_len = len;
if (addr) {
- g_free(*addr);
- *addr = NULL;
+ (*addr)[v] = a;
}
- return -1;
- }
+
+ a += len;
+ l -= len;
+ v += 1;
+ } while (l > 0);
}
+ *niov = v;
+
g_free(ents);
return 0;
}
@@ -717,13 +690,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g,
return;
}
- ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov);
+ ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs,
+ &res->iov, &res->iov_cnt);
if (ret != 0) {
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
return;
}
-
- res->iov_cnt = ab.nr_entries;
}
static void
@@ -747,8 +719,8 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
virtio_gpu_cleanup_mapping(g, res);
}
-static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
+void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
{
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
@@ -806,6 +778,7 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
void virtio_gpu_process_cmdq(VirtIOGPU *g)
{
struct virtio_gpu_ctrl_command *cmd;
+ VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
if (g->processing_cmdq) {
return;
@@ -819,8 +792,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
}
/* process command */
- VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd,
- g, cmd);
+ vgc->process_cmd(g, cmd);
QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
@@ -843,19 +815,6 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
g->processing_cmdq = false;
}
-static void virtio_gpu_gl_flushed(VirtIOGPUBase *b)
-{
- VirtIOGPU *g = VIRTIO_GPU(b);
-
-#ifdef CONFIG_VIRGL
- if (g->renderer_reset) {
- g->renderer_reset = false;
- virtio_gpu_virgl_reset(g);
- }
-#endif
- virtio_gpu_process_cmdq(g);
-}
-
static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
@@ -865,13 +824,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
return;
}
-#ifdef CONFIG_VIRGL
- if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) {
- virtio_gpu_virgl_init(g);
- g->renderer_inited = true;
- }
-#endif
-
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
while (cmd) {
cmd->vq = vq;
@@ -882,18 +834,14 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
}
virtio_gpu_process_cmdq(g);
-
-#ifdef CONFIG_VIRGL
- if (g->parent_obj.use_virgl_renderer) {
- virtio_gpu_virgl_fence_poll(g);
- }
-#endif
}
static void virtio_gpu_ctrl_bh(void *opaque)
{
VirtIOGPU *g = opaque;
- virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq);
+ VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
+
+ vgc->handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq);
}
static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
@@ -1105,25 +1053,10 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
return 0;
}
-static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
+void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
VirtIOGPU *g = VIRTIO_GPU(qdev);
- bool have_virgl;
-
-#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN)
- have_virgl = false;
-#else
- have_virgl = display_opengl;
-#endif
- if (!have_virgl) {
- g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED);
- } else {
-#if defined(CONFIG_VIRGL)
- VIRTIO_GPU_BASE(g)->virtio_config.num_capsets =
- virtio_gpu_virgl_get_num_capsets(g);
-#endif
- }
if (!virtio_gpu_base_device_realize(qdev,
virtio_gpu_handle_ctrl_cb,
@@ -1141,18 +1074,12 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
QTAILQ_INIT(&g->fenceq);
}
-static void virtio_gpu_reset(VirtIODevice *vdev)
+void virtio_gpu_reset(VirtIODevice *vdev)
{
VirtIOGPU *g = VIRTIO_GPU(vdev);
struct virtio_gpu_simple_resource *res, *tmp;
struct virtio_gpu_ctrl_command *cmd;
-#ifdef CONFIG_VIRGL
- if (g->parent_obj.use_virgl_renderer) {
- virtio_gpu_virgl_reset(g);
- }
-#endif
-
QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
virtio_gpu_resource_destroy(g, res);
}
@@ -1170,17 +1097,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev)
g_free(cmd);
}
-#ifdef CONFIG_VIRGL
- if (g->parent_obj.use_virgl_renderer) {
- if (g->parent_obj.renderer_blocked) {
- g->renderer_reset = true;
- } else {
- virtio_gpu_virgl_reset(g);
- }
- g->parent_obj.use_virgl_renderer = false;
- }
-#endif
-
virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
}
@@ -1235,12 +1151,6 @@ static Property virtio_gpu_properties[] = {
VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
256 * MiB),
-#ifdef CONFIG_VIRGL
- DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags,
- VIRTIO_GPU_FLAG_VIRGL_ENABLED, true),
- DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
- VIRTIO_GPU_FLAG_STATS_ENABLED, false),
-#endif
DEFINE_PROP_END_OF_LIST(),
};
@@ -1248,9 +1158,12 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
- VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass);
+ VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
+
+ vgc->handle_ctrl = virtio_gpu_handle_ctrl;
+ vgc->process_cmd = virtio_gpu_simple_process_cmd;
+ vgc->update_cursor_data = virtio_gpu_update_cursor_data;
- vgc->gl_flushed = virtio_gpu_gl_flushed;
vdc->realize = virtio_gpu_device_realize;
vdc->reset = virtio_gpu_reset;
vdc->get_config = virtio_gpu_get_config;
@@ -1264,6 +1177,7 @@ static const TypeInfo virtio_gpu_info = {
.name = TYPE_VIRTIO_GPU,
.parent = TYPE_VIRTIO_GPU_BASE,
.instance_size = sizeof(VirtIOGPU),
+ .class_size = sizeof(VirtIOGPUClass),
.class_init = virtio_gpu_class_init,
};
diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c
new file mode 100644
index 0000000000..c971340ebb
--- /dev/null
+++ b/hw/display/virtio-vga-gl.c
@@ -0,0 +1,47 @@
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/display/vga.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "virtio-vga.h"
+#include "qom/object.h"
+
+#define TYPE_VIRTIO_VGA_GL "virtio-vga-gl"
+
+typedef struct VirtIOVGAGL VirtIOVGAGL;
+DECLARE_INSTANCE_CHECKER(VirtIOVGAGL, VIRTIO_VGA_GL,
+ TYPE_VIRTIO_VGA_GL)
+
+struct VirtIOVGAGL {
+ VirtIOVGABase parent_obj;
+
+ VirtIOGPUGL vdev;
+};
+
+static void virtio_vga_gl_inst_initfn(Object *obj)
+{
+ VirtIOVGAGL *dev = VIRTIO_VGA_GL(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VIRTIO_GPU_GL);
+ VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev);
+}
+
+
+static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = {
+ .generic_name = TYPE_VIRTIO_VGA_GL,
+ .parent = TYPE_VIRTIO_VGA_BASE,
+ .instance_size = sizeof(VirtIOVGAGL),
+ .instance_init = virtio_vga_gl_inst_initfn,
+};
+
+static void virtio_vga_register_types(void)
+{
+ if (have_vga) {
+ virtio_pci_types_register(&virtio_vga_gl_info);
+ }
+}
+
+type_init(virtio_vga_register_types)
diff --git a/hw/dma/meson.build b/hw/dma/meson.build
index 5c78a4e05f..f3f0661bc3 100644
--- a/hw/dma/meson.build
+++ b/hw/dma/meson.build
@@ -1,4 +1,3 @@
-softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_dma.c'))
softmmu_ss.add(when: 'CONFIG_RC4030', if_true: files('rc4030.c'))
softmmu_ss.add(when: 'CONFIG_PL080', if_true: files('pl080.c'))
softmmu_ss.add(when: 'CONFIG_PL330', if_true: files('pl330.c'))
diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c
deleted file mode 100644
index cca1e9ec21..0000000000
--- a/hw/dma/puv3_dma.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * DMA device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-
-#define PUV3_DMA_CH_NR (6)
-#define PUV3_DMA_CH_MASK (0xff)
-#define PUV3_DMA_CH(offset) ((offset) >> 8)
-
-#define TYPE_PUV3_DMA "puv3_dma"
-OBJECT_DECLARE_SIMPLE_TYPE(PUV3DMAState, PUV3_DMA)
-
-struct PUV3DMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t reg_CFG[PUV3_DMA_CH_NR];
-};
-
-static uint64_t puv3_dma_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3DMAState *s = opaque;
- uint32_t ret = 0;
-
- assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
- switch (offset & PUV3_DMA_CH_MASK) {
- case 0x10:
- ret = s->reg_CFG[PUV3_DMA_CH(offset)];
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_dma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3DMAState *s = opaque;
-
- assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
- switch (offset & PUV3_DMA_CH_MASK) {
- case 0x10:
- s->reg_CFG[PUV3_DMA_CH(offset)] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_dma_ops = {
- .read = puv3_dma_read,
- .write = puv3_dma_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_dma_realize(DeviceState *dev, Error **errp)
-{
- PUV3DMAState *s = PUV3_DMA(dev);
- int i;
-
- for (i = 0; i < PUV3_DMA_CH_NR; i++) {
- s->reg_CFG[i] = 0x0;
- }
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-}
-
-static void puv3_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = puv3_dma_realize;
-}
-
-static const TypeInfo puv3_dma_info = {
- .name = TYPE_PUV3_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3DMAState),
- .class_init = puv3_dma_class_init,
-};
-
-static void puv3_dma_register_type(void)
-{
- type_register_static(&puv3_dma_info);
-}
-
-type_init(puv3_dma_register_type)
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 985a259e05..34d8acb0e3 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -170,7 +170,7 @@
/* AST2600 only - 1.8V gpios */
/*
* The AST2600 has same 3.6V gpios as the AST2400 (memory offsets 0x0-0x198)
- * and addtional 1.8V gpios (memory offsets 0x800-0x9D4).
+ * and additional 1.8V gpios (memory offsets 0x800-0x9D4).
*/
#define GPIO_1_8V_REG_OFFSET 0x800
#define GPIO_1_8V_ABCD_DATA_VALUE ((0x800 - GPIO_1_8V_REG_OFFSET) >> 2)
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
index 79568f00ce..7bd6a57264 100644
--- a/hw/gpio/meson.build
+++ b/hw/gpio/meson.build
@@ -3,7 +3,6 @@ softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
-softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c
deleted file mode 100644
index e003ae505c..0000000000
--- a/hw/gpio/puv3_gpio.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * GPIO device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-
-#define TYPE_PUV3_GPIO "puv3_gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(PUV3GPIOState, PUV3_GPIO)
-
-struct PUV3GPIOState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq[9];
-
- uint32_t reg_GPLR;
- uint32_t reg_GPDR;
- uint32_t reg_GPIR;
-};
-
-static uint64_t puv3_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3GPIOState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x00:
- ret = s->reg_GPLR;
- break;
- case 0x04:
- ret = s->reg_GPDR;
- break;
- case 0x20:
- ret = s->reg_GPIR;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3GPIOState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x04:
- s->reg_GPDR = value;
- break;
- case 0x08:
- if (s->reg_GPDR & value) {
- s->reg_GPLR |= value;
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n",
- __func__);
- }
- break;
- case 0x0c:
- if (s->reg_GPDR & value) {
- s->reg_GPLR &= ~value;
- } else {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n",
- __func__);
- }
- break;
- case 0x10: /* GRER */
- case 0x14: /* GFER */
- case 0x18: /* GEDR */
- break;
- case 0x20: /* GPIR */
- s->reg_GPIR = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps puv3_gpio_ops = {
- .read = puv3_gpio_read,
- .write = puv3_gpio_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-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(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(sbd, &s->iomem);
-}
-
-static void puv3_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = puv3_gpio_realize;
-}
-
-static const TypeInfo puv3_gpio_info = {
- .name = TYPE_PUV3_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3GPIOState),
- .class_init = puv3_gpio_class_init,
-};
-
-static void puv3_gpio_register_type(void)
-{
- type_register_static(&puv3_gpio_info);
-}
-
-type_init(puv3_gpio_register_type)
diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig
index 09642a6dcb..8d120a25d5 100644
--- a/hw/i2c/Kconfig
+++ b/hw/i2c/Kconfig
@@ -28,3 +28,7 @@ config IMX_I2C
config MPC_I2C
bool
select I2C
+
+config PCA954X
+ bool
+ select I2C
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index 21ec52ac5a..3a7bae311d 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -77,6 +77,30 @@ int i2c_bus_busy(I2CBus *bus)
return !QLIST_EMPTY(&bus->current_devs);
}
+bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
+ I2CNodeList *current_devs)
+{
+ BusChild *kid;
+
+ QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ I2CSlave *candidate = I2C_SLAVE(qdev);
+ I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(candidate);
+
+ if (sc->match_and_add(candidate, address, broadcast, current_devs)) {
+ if (!broadcast) {
+ return true;
+ }
+ }
+ }
+
+ /*
+ * If broadcast was true, and the list was full or empty, return true. If
+ * broadcast was false, return false.
+ */
+ return broadcast;
+}
+
/* TODO: Make this handle multiple masters. */
/*
* Start or continue an i2c transaction. When this is called for the
@@ -93,7 +117,6 @@ int i2c_bus_busy(I2CBus *bus)
*/
int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
{
- BusChild *kid;
I2CSlaveClass *sc;
I2CNode *node;
bool bus_scanned = false;
@@ -115,18 +138,8 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
* terminating the previous transaction.
*/
if (QLIST_EMPTY(&bus->current_devs)) {
- QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- I2CSlave *candidate = I2C_SLAVE(qdev);
- if ((candidate->address == address) || (bus->broadcast)) {
- node = g_malloc(sizeof(struct I2CNode));
- node->elt = candidate;
- QLIST_INSERT_HEAD(&bus->current_devs, node, next);
- if (!bus->broadcast) {
- break;
- }
- }
- }
+ /* Disregard whether devices were found. */
+ (void)i2c_scan_bus(bus, address, bus->broadcast, &bus->current_devs);
bus_scanned = true;
}
@@ -290,12 +303,28 @@ I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr)
return dev;
}
+static bool i2c_slave_match(I2CSlave *candidate, uint8_t address,
+ bool broadcast, I2CNodeList *current_devs)
+{
+ if ((candidate->address == address) || (broadcast)) {
+ I2CNode *node = g_malloc(sizeof(struct I2CNode));
+ node->elt = candidate;
+ QLIST_INSERT_HEAD(current_devs, node, next);
+ return true;
+ }
+
+ /* Not found and not broadcast. */
+ return false;
+}
+
static void i2c_slave_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
set_bit(DEVICE_CATEGORY_MISC, k->categories);
k->bus_type = TYPE_I2C_BUS;
device_class_set_props(k, i2c_props);
+ sc->match_and_add = i2c_slave_match;
}
static const TypeInfo i2c_slave_type_info = {
diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c
new file mode 100644
index 0000000000..847c59921c
--- /dev/null
+++ b/hw/i2c/i2c_mux_pca954x.c
@@ -0,0 +1,290 @@
+/*
+ * I2C multiplexer for PCA954x series of I2C multiplexer/switch chips.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/i2c_mux_pca954x.h"
+#include "hw/i2c/smbus_slave.h"
+#include "hw/qdev-core.h"
+#include "hw/sysbus.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/queue.h"
+#include "qom/object.h"
+#include "trace.h"
+
+#define PCA9548_CHANNEL_COUNT 8
+#define PCA9546_CHANNEL_COUNT 4
+
+/*
+ * struct Pca954xChannel - The i2c mux device will have N of these states
+ * that own the i2c channel bus.
+ * @bus: The owned channel bus.
+ * @enabled: Is this channel active?
+ */
+typedef struct Pca954xChannel {
+ SysBusDevice parent;
+
+ I2CBus *bus;
+
+ bool enabled;
+} Pca954xChannel;
+
+#define TYPE_PCA954X_CHANNEL "pca954x-channel"
+#define PCA954X_CHANNEL(obj) \
+ OBJECT_CHECK(Pca954xChannel, (obj), TYPE_PCA954X_CHANNEL)
+
+/*
+ * struct Pca954xState - The pca954x state object.
+ * @control: The value written to the mux control.
+ * @channel: The set of i2c channel buses that act as channels which own the
+ * i2c children.
+ */
+typedef struct Pca954xState {
+ SMBusDevice parent;
+
+ uint8_t control;
+
+ /* The channel i2c buses. */
+ Pca954xChannel channel[PCA9548_CHANNEL_COUNT];
+} Pca954xState;
+
+/*
+ * struct Pca954xClass - The pca954x class object.
+ * @nchans: The number of i2c channels this device has.
+ */
+typedef struct Pca954xClass {
+ SMBusDeviceClass parent;
+
+ uint8_t nchans;
+} Pca954xClass;
+
+#define TYPE_PCA954X "pca954x"
+OBJECT_DECLARE_TYPE(Pca954xState, Pca954xClass, PCA954X)
+
+/*
+ * For each channel, if it's enabled, recursively call match on those children.
+ */
+static bool pca954x_match(I2CSlave *candidate, uint8_t address,
+ bool broadcast,
+ I2CNodeList *current_devs)
+{
+ Pca954xState *mux = PCA954X(candidate);
+ Pca954xClass *mc = PCA954X_GET_CLASS(mux);
+ int i;
+
+ /* They are talking to the mux itself (or all devices enabled). */
+ if ((candidate->address == address) || broadcast) {
+ I2CNode *node = g_malloc(sizeof(struct I2CNode));
+ node->elt = candidate;
+ QLIST_INSERT_HEAD(current_devs, node, next);
+ if (!broadcast) {
+ return true;
+ }
+ }
+
+ for (i = 0; i < mc->nchans; i++) {
+ if (!mux->channel[i].enabled) {
+ continue;
+ }
+
+ if (i2c_scan_bus(mux->channel[i].bus, address, broadcast,
+ current_devs)) {
+ if (!broadcast) {
+ return true;
+ }
+ }
+ }
+
+ /* If we arrived here we didn't find a match, return broadcast. */
+ return broadcast;
+}
+
+static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask)
+{
+ Pca954xClass *mc = PCA954X_GET_CLASS(s);
+ int i;
+
+ /*
+ * For each channel, check if their bit is set in enable_mask and if yes,
+ * enable it, otherwise disable, hide it.
+ */
+ for (i = 0; i < mc->nchans; i++) {
+ if (enable_mask & (1 << i)) {
+ s->channel[i].enabled = true;
+ } else {
+ s->channel[i].enabled = false;
+ }
+ }
+}
+
+static void pca954x_write(Pca954xState *s, uint8_t data)
+{
+ s->control = data;
+ pca954x_enable_channel(s, data);
+
+ trace_pca954x_write_bytes(data);
+}
+
+static int pca954x_write_data(SMBusDevice *d, uint8_t *buf, uint8_t len)
+{
+ Pca954xState *s = PCA954X(d);
+
+ if (len == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
+ return -1;
+ }
+
+ /*
+ * len should be 1, because they write one byte to enable/disable channels.
+ */
+ if (len > 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: extra data after channel selection mask\n",
+ __func__);
+ return -1;
+ }
+
+ pca954x_write(s, buf[0]);
+ return 0;
+}
+
+static uint8_t pca954x_read_byte(SMBusDevice *d)
+{
+ Pca954xState *s = PCA954X(d);
+ uint8_t data = s->control;
+ trace_pca954x_read_data(data);
+ return data;
+}
+
+static void pca954x_enter_reset(Object *obj, ResetType type)
+{
+ Pca954xState *s = PCA954X(obj);
+ /* Reset will disable all channels. */
+ pca954x_write(s, 0);
+}
+
+I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel)
+{
+ Pca954xClass *pc = PCA954X_GET_CLASS(mux);
+ Pca954xState *pca954x = PCA954X(mux);
+
+ g_assert(channel < pc->nchans);
+ return I2C_BUS(qdev_get_child_bus(DEVICE(&pca954x->channel[channel]),
+ "i2c-bus"));
+}
+
+static void pca954x_channel_init(Object *obj)
+{
+ Pca954xChannel *s = PCA954X_CHANNEL(obj);
+ s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
+
+ /* Start all channels as disabled. */
+ s->enabled = false;
+}
+
+static void pca954x_channel_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->desc = "Pca954x Channel";
+}
+
+static void pca9546_class_init(ObjectClass *klass, void *data)
+{
+ Pca954xClass *s = PCA954X_CLASS(klass);
+ s->nchans = PCA9546_CHANNEL_COUNT;
+}
+
+static void pca9548_class_init(ObjectClass *klass, void *data)
+{
+ Pca954xClass *s = PCA954X_CLASS(klass);
+ s->nchans = PCA9548_CHANNEL_COUNT;
+}
+
+static void pca954x_realize(DeviceState *dev, Error **errp)
+{
+ Pca954xState *s = PCA954X(dev);
+ Pca954xClass *c = PCA954X_GET_CLASS(s);
+ int i;
+
+ /* SMBus modules. Cannot fail. */
+ for (i = 0; i < c->nchans; i++) {
+ sysbus_realize(SYS_BUS_DEVICE(&s->channel[i]), &error_abort);
+ }
+}
+
+static void pca954x_init(Object *obj)
+{
+ Pca954xState *s = PCA954X(obj);
+ Pca954xClass *c = PCA954X_GET_CLASS(obj);
+ int i;
+
+ /* Only initialize the children we expect. */
+ for (i = 0; i < c->nchans; i++) {
+ object_initialize_child(obj, "channel[*]", &s->channel[i],
+ TYPE_PCA954X_CHANNEL);
+ }
+}
+
+static void pca954x_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass);
+
+ sc->match_and_add = pca954x_match;
+
+ rc->phases.enter = pca954x_enter_reset;
+
+ dc->desc = "Pca954x i2c-mux";
+ dc->realize = pca954x_realize;
+
+ k->write_data = pca954x_write_data;
+ k->receive_byte = pca954x_read_byte;
+}
+
+static const TypeInfo pca954x_info[] = {
+ {
+ .name = TYPE_PCA954X,
+ .parent = TYPE_SMBUS_DEVICE,
+ .instance_size = sizeof(Pca954xState),
+ .instance_init = pca954x_init,
+ .class_size = sizeof(Pca954xClass),
+ .class_init = pca954x_class_init,
+ .abstract = true,
+ },
+ {
+ .name = TYPE_PCA9546,
+ .parent = TYPE_PCA954X,
+ .class_init = pca9546_class_init,
+ },
+ {
+ .name = TYPE_PCA9548,
+ .parent = TYPE_PCA954X,
+ .class_init = pca9548_class_init,
+ },
+ {
+ .name = TYPE_PCA954X_CHANNEL,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = pca954x_channel_class_init,
+ .instance_size = sizeof(Pca954xChannel),
+ .instance_init = pca954x_channel_init,
+ }
+};
+
+DEFINE_TYPES(pca954x_info)
diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build
index cdcd694a7f..dd3aef02b2 100644
--- a/hw/i2c/meson.build
+++ b/hw/i2c/meson.build
@@ -14,4 +14,5 @@ i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c'))
i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c'))
+i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c'))
softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss)
diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
index 82fe6f965f..82f19e6a2d 100644
--- a/hw/i2c/trace-events
+++ b/hw/i2c/trace-events
@@ -26,3 +26,8 @@ npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x"
npcm7xx_smbus_stop(const char *id) "%s stopping"
npcm7xx_smbus_nack(const char *id) "%s nacking"
npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s recv fifo: received %u, expected %u"
+
+# i2c-mux-pca954x.c
+
+pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x"
+pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x"
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index bfecb0038c..80bee00da6 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1815,6 +1815,7 @@ build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id,
const char *oem_table_id)
{
Acpi20Hpet *hpet;
+ int hpet_start = table_data->len;
hpet = acpi_data_push(table_data, sizeof(*hpet));
/* Note timer_block_id value must be kept in sync with value advertised by
@@ -1823,13 +1824,15 @@ build_hpet(GArray *table_data, BIOSLinker *linker, const char *oem_id,
hpet->timer_block_id = cpu_to_le32(0x8086a201);
hpet->addr.address = cpu_to_le64(HPET_BASE);
build_header(linker, table_data,
- (void *)hpet, "HPET", sizeof(*hpet), 1, oem_id, oem_table_id);
+ (void *)(table_data->data + hpet_start),
+ "HPET", sizeof(*hpet), 1, oem_id, oem_table_id);
}
static void
build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
const char *oem_id, const char *oem_table_id)
{
+ int tcpa_start = table_data->len;
Acpi20Tcpa *tcpa = acpi_data_push(table_data, sizeof *tcpa);
unsigned log_addr_size = sizeof(tcpa->log_area_start_address);
unsigned log_addr_offset =
@@ -1848,7 +1851,8 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog,
ACPI_BUILD_TPMLOG_FILE, 0);
build_header(linker, table_data,
- (void *)tcpa, "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id);
+ (void *)(table_data->data + tcpa_start),
+ "TCPA", sizeof(*tcpa), 2, oem_id, oem_table_id);
}
#define HOLE_640K_START (640 * KiB)
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 74a93a5d93..2801dff97c 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -99,7 +99,7 @@ static uint64_t amdvi_readq(AMDVIState *s, hwaddr addr)
}
/* internal write */
-static void amdvi_writeq_raw(AMDVIState *s, uint64_t val, hwaddr addr)
+static void amdvi_writeq_raw(AMDVIState *s, hwaddr addr, uint64_t val)
{
stq_le_p(&s->mmior[addr], val);
}
@@ -382,7 +382,7 @@ static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd)
}
/* set completion interrupt */
if (extract64(cmd[0], 1, 1)) {
- amdvi_test_mask(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT);
+ amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT);
/* generate interrupt */
amdvi_generate_msi_interrupt(s);
}
@@ -553,7 +553,7 @@ static void amdvi_cmdbuf_run(AMDVIState *s)
trace_amdvi_command_exec(s->cmdbuf_head, s->cmdbuf_tail, s->cmdbuf);
amdvi_cmdbuf_exec(s);
s->cmdbuf_head += AMDVI_COMMAND_SIZE;
- amdvi_writeq_raw(s, s->cmdbuf_head, AMDVI_MMIO_COMMAND_HEAD);
+ amdvi_writeq_raw(s, AMDVI_MMIO_COMMAND_HEAD, s->cmdbuf_head);
/* wrap head pointer */
if (s->cmdbuf_head >= s->cmdbuf_len * AMDVI_COMMAND_SIZE) {
@@ -860,8 +860,8 @@ static inline uint8_t get_pte_translation_mode(uint64_t pte)
static inline uint64_t pte_override_page_mask(uint64_t pte)
{
- uint8_t page_mask = 12;
- uint64_t addr = (pte & AMDVI_DEV_PT_ROOT_MASK) ^ AMDVI_DEV_PT_ROOT_MASK;
+ uint8_t page_mask = 13;
+ uint64_t addr = (pte & AMDVI_DEV_PT_ROOT_MASK) >> 12;
/* find the first zero bit */
while (addr & 1) {
page_mask++;
diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c
index e48a54fa36..4e68d5dea4 100644
--- a/hw/i386/fw_cfg.c
+++ b/hw/i386/fw_cfg.c
@@ -22,6 +22,7 @@
#include "hw/nvram/fw_cfg.h"
#include "e820_memory_layout.h"
#include "kvm/kvm_i386.h"
+#include "qapi/error.h"
#include CONFIG_DEVICES
struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
@@ -78,7 +79,8 @@ void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg)
}
smbios_get_tables(ms, mem_array, array_count,
&smbios_tables, &smbios_tables_len,
- &smbios_anchor, &smbios_anchor_len);
+ &smbios_anchor, &smbios_anchor_len,
+ &error_fatal);
g_free(mem_array);
if (smbios_anchor) {
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 5ac2edbf1f..30b8bd6ea9 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -61,6 +61,7 @@
#include "hw/hyperv/vmbus-bridge.h"
#include "hw/mem/nvdimm.h"
#include "hw/i386/acpi-build.h"
+#include "kvm/kvm-cpu.h"
#define MAX_IDE_BUS 2
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index c53fa17c50..9b432773f0 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -108,6 +108,7 @@ typedef struct XenIOState {
shared_iopage_t *shared_page;
shared_vmport_iopage_t *shared_vmport_page;
buffered_iopage_t *buffered_io_page;
+ xenforeignmemory_resource_handle *fres;
QEMUTimer *buffered_io_timer;
CPUState **cpu_by_vcpu_id;
/* the evtchn port for polling the notification, */
@@ -1253,6 +1254,9 @@ static void xen_exit_notifier(Notifier *n, void *data)
XenIOState *state = container_of(n, XenIOState, exit);
xen_destroy_ioreq_server(xen_domid, state->ioservid);
+ if (state->fres != NULL) {
+ xenforeignmemory_unmap_resource(xen_fmem, state->fres);
+ }
xenevtchn_close(state->xce_handle);
xs_daemon_close(state->xenstore);
@@ -1320,7 +1324,6 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data)
static int xen_map_ioreq_server(XenIOState *state)
{
void *addr = NULL;
- xenforeignmemory_resource_handle *fres;
xen_pfn_t ioreq_pfn;
xen_pfn_t bufioreq_pfn;
evtchn_port_t bufioreq_evtchn;
@@ -1332,12 +1335,12 @@ static int xen_map_ioreq_server(XenIOState *state)
*/
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0);
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1);
- fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
+ state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
XENMEM_resource_ioreq_server,
state->ioservid, 0, 2,
&addr,
PROT_READ | PROT_WRITE, 0);
- if (fres != NULL) {
+ if (state->fres != NULL) {
trace_xen_map_resource_ioreq(state->ioservid, addr);
state->buffered_io_page = addr;
state->shared_page = addr + TARGET_PAGE_SIZE;
diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c
index 5b120ed44b..bd47c3d672 100644
--- a/hw/i386/xen/xen-mapcache.c
+++ b/hw/i386/xen/xen-mapcache.c
@@ -169,9 +169,23 @@ static void xen_remap_bucket(MapCacheEntry *entry,
if (entry->vaddr_base != NULL) {
if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
- ram_block_notify_remove(entry->vaddr_base, entry->size);
+ ram_block_notify_remove(entry->vaddr_base, entry->size,
+ entry->size);
}
- if (munmap(entry->vaddr_base, entry->size) != 0) {
+
+ /*
+ * If an entry is being replaced by another mapping and we're using
+ * MAP_FIXED flag for it - there is possibility of a race for vaddr
+ * address with another thread doing an mmap call itself
+ * (see man 2 mmap). To avoid that we skip explicit unmapping here
+ * and allow the kernel to destroy the previous mappings by replacing
+ * them in mmap call later.
+ *
+ * Non-identical replacements are not allowed therefore.
+ */
+ assert(!vaddr || (entry->vaddr_base == vaddr && entry->size == size));
+
+ if (!vaddr && munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
}
@@ -211,7 +225,7 @@ static void xen_remap_bucket(MapCacheEntry *entry,
}
if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) {
- ram_block_notify_add(vaddr_base, size);
+ ram_block_notify_add(vaddr_base, size, size);
}
entry->vaddr_base = vaddr_base;
@@ -452,7 +466,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer)
}
pentry->next = entry->next;
- ram_block_notify_remove(entry->vaddr_base, entry->size);
+ ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size);
if (munmap(entry->vaddr_base, entry->size) != 0) {
perror("unmap fails");
exit(-1);
diff --git a/hw/input/meson.build b/hw/input/meson.build
index 0042c3f0dc..8deb011d4a 100644
--- a/hw/input/meson.build
+++ b/hw/input/meson.build
@@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c')
softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c'))
softmmu_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-softusb.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
softmmu_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
softmmu_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
deleted file mode 100644
index d885c708d7..0000000000
--- a/hw/input/milkymist-softusb.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * QEMU model of the Milkymist SoftUSB block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * not available yet
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/input/hid.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- R_CTRL = 0,
- R_MAX
-};
-
-enum {
- CTRL_RESET = (1<<0),
-};
-
-#define COMLOC_DEBUG_PRODUCE 0x1000
-#define COMLOC_DEBUG_BASE 0x1001
-#define COMLOC_MEVT_PRODUCE 0x1101
-#define COMLOC_MEVT_BASE 0x1102
-#define COMLOC_KEVT_PRODUCE 0x1142
-#define COMLOC_KEVT_BASE 0x1143
-
-#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSoftUsbState, MILKYMIST_SOFTUSB)
-
-struct MilkymistSoftUsbState {
- SysBusDevice parent_obj;
-
- HIDState hid_kbd;
- HIDState hid_mouse;
-
- MemoryRegion regs_region;
- MemoryRegion pmem;
- MemoryRegion dmem;
- qemu_irq irq;
-
- void *pmem_ptr;
- void *dmem_ptr;
-
- /* device properties */
- uint32_t pmem_size;
- uint32_t dmem_size;
-
- /* device registers */
- uint32_t regs[R_MAX];
-
- /* mouse state */
- uint8_t mouse_hid_buffer[4];
-
- /* keyboard state */
- uint8_t kbd_hid_buffer[8];
-};
-
-static uint64_t softusb_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistSoftUsbState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_softusb: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_softusb_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void
-softusb_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistSoftUsbState *s = opaque;
-
- trace_milkymist_softusb_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTRL:
- s->regs[addr] = value;
- break;
-
- default:
- error_report("milkymist_softusb: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps softusb_mmio_ops = {
- .read = softusb_read,
- .write = softusb_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
- uint32_t offset, uint8_t *buf, uint32_t len)
-{
- if (offset + len >= s->dmem_size) {
- error_report("milkymist_softusb: read dmem out of bounds "
- "at offset 0x%x, len %d", offset, len);
- memset(buf, 0, len);
- return;
- }
-
- memcpy(buf, s->dmem_ptr + offset, len);
-}
-
-static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
- uint32_t offset, uint8_t *buf, uint32_t len)
-{
- if (offset + len >= s->dmem_size) {
- error_report("milkymist_softusb: write dmem out of bounds "
- "at offset 0x%x, len %d", offset, len);
- return;
- }
-
- memcpy(s->dmem_ptr + offset, buf, len);
-}
-
-static void softusb_mouse_changed(MilkymistSoftUsbState *s)
-{
- uint8_t m;
-
- softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
- trace_milkymist_softusb_mevt(m);
- softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
- m = (m + 1) & 0xf;
- softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-
- trace_milkymist_softusb_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_changed(MilkymistSoftUsbState *s)
-{
- uint8_t m;
-
- softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
- trace_milkymist_softusb_kevt(m);
- softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
- m = (m + 1) & 0x7;
- softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-
- trace_milkymist_softusb_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_hid_datain(HIDState *hs)
-{
- MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
- int len;
-
- /* if device is in reset, do nothing */
- if (s->regs[R_CTRL] & CTRL_RESET) {
- return;
- }
-
- while (hid_has_events(hs)) {
- len = hid_keyboard_poll(hs, s->kbd_hid_buffer,
- sizeof(s->kbd_hid_buffer));
-
- if (len == 8) {
- softusb_kbd_changed(s);
- }
- }
-}
-
-static void softusb_mouse_hid_datain(HIDState *hs)
-{
- MilkymistSoftUsbState *s =
- container_of(hs, MilkymistSoftUsbState, hid_mouse);
- int len;
-
- /* if device is in reset, do nothing */
- if (s->regs[R_CTRL] & CTRL_RESET) {
- return;
- }
-
- while (hid_has_events(hs)) {
- len = hid_pointer_poll(hs, s->mouse_hid_buffer,
- sizeof(s->mouse_hid_buffer));
-
- if (len == 4) {
- softusb_mouse_changed(s);
- }
- }
-}
-
-static void milkymist_softusb_reset(DeviceState *d)
-{
- MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
- memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
-
- hid_reset(&s->hid_kbd);
- hid_reset(&s->hid_mouse);
-
- /* defaults */
- s->regs[R_CTRL] = CTRL_RESET;
-}
-
-static void milkymist_softusb_realize(DeviceState *dev, Error **errp)
-{
- MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- 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(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(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(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);
-}
-
-static const VMStateDescription vmstate_milkymist_softusb = {
- .name = "milkymist-softusb",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
- VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
- VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
- VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
- VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_softusb_properties[] = {
- DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
- DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_softusb_realize;
- dc->reset = milkymist_softusb_reset;
- dc->vmsd = &vmstate_milkymist_softusb;
- device_class_set_props(dc, milkymist_softusb_properties);
-}
-
-static const TypeInfo milkymist_softusb_info = {
- .name = TYPE_MILKYMIST_SOFTUSB,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistSoftUsbState),
- .class_init = milkymist_softusb_class_init,
-};
-
-static void milkymist_softusb_register_types(void)
-{
- type_register_static(&milkymist_softusb_info);
-}
-
-type_init(milkymist_softusb_register_types)
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 1dd8ad6018..33741e74f5 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -44,13 +44,6 @@ ps2_mouse_reset(void *opaque) "%p"
ps2_kbd_init(void *s) "%p"
ps2_mouse_init(void *s) "%p"
-# milkymist-softusb.c
-milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_softusb_mevt(uint8_t m) "m %d"
-milkymist_softusb_kevt(uint8_t m) "m %d"
-milkymist_softusb_pulse_irq(void) "Pulse IRQ"
-
# hid.c
hid_kbd_queue_full(void) "queue full"
hid_kbd_queue_empty(void) "queue empty"
diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c
index 85daf73f1a..137efba57b 100644
--- a/hw/input/virtio-input-host.c
+++ b/hw/input/virtio-input-host.c
@@ -193,13 +193,16 @@ static void virtio_input_host_handle_status(VirtIOInput *vinput,
{
VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput);
struct input_event evdev;
+ struct timeval tval;
int rc;
- if (gettimeofday(&evdev.time, NULL)) {
+ if (gettimeofday(&tval, NULL)) {
perror("virtio_input_host_handle_status: gettimeofday");
return;
}
+ evdev.input_event_sec = tval.tv_sec;
+ evdev.input_event_usec = tval.tv_usec;
evdev.type = le16_to_cpu(event->type);
evdev.code = le16_to_cpu(event->code);
evdev.value = le32_to_cpu(event->value);
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
index c1b72fcab0..edf76e4f61 100644
--- a/hw/intc/ibex_plic.c
+++ b/hw/intc/ibex_plic.c
@@ -225,23 +225,23 @@ static void ibex_plic_irq_request(void *opaque, int irq, int level)
static Property ibex_plic_properties[] = {
DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1),
- DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80),
+ DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 176),
DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0),
- DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3),
+ DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 6),
- DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c),
- DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3),
+ DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x18),
+ DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 6),
- DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18),
- DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80),
+ DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x30),
+ DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177),
- DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200),
- DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3),
+ DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x300),
+ DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 6),
- DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c),
+ DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x318),
- DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210),
+ DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c
deleted file mode 100644
index 991a90bc99..0000000000
--- a/hw/intc/lm32_pic.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * LatticeMico32 CPU interrupt controller logic.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "migration/vmstate.h"
-#include "monitor/monitor.h"
-#include "qemu/module.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/lm32/lm32_pic.h"
-#include "hw/intc/intc.h"
-#include "hw/irq.h"
-#include "qom/object.h"
-
-#define TYPE_LM32_PIC "lm32-pic"
-OBJECT_DECLARE_SIMPLE_TYPE(LM32PicState, LM32_PIC)
-
-struct LM32PicState {
- SysBusDevice parent_obj;
-
- qemu_irq parent_irq;
- uint32_t im; /* interrupt mask */
- uint32_t ip; /* interrupt pending */
- uint32_t irq_state;
-
- /* statistics */
- uint64_t stats_irq_count[32];
-};
-
-static void update_irq(LM32PicState *s)
-{
- s->ip |= s->irq_state;
-
- if (s->ip & s->im) {
- trace_lm32_pic_raise_irq();
- qemu_irq_raise(s->parent_irq);
- } else {
- trace_lm32_pic_lower_irq();
- qemu_irq_lower(s->parent_irq);
- }
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- LM32PicState *s = opaque;
-
- assert(irq < 32);
- trace_lm32_pic_interrupt(irq, level);
-
- if (level) {
- s->irq_state |= (1 << irq);
- s->stats_irq_count[irq]++;
- } else {
- s->irq_state &= ~(1 << irq);
- }
-
- update_irq(s);
-}
-
-void lm32_pic_set_im(DeviceState *d, uint32_t im)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_set_im(im);
- s->im = im;
-
- update_irq(s);
-}
-
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_set_ip(ip);
-
- /* ack interrupt */
- s->ip &= ~ip;
-
- update_irq(s);
-}
-
-uint32_t lm32_pic_get_im(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_get_im(s->im);
- return s->im;
-}
-
-uint32_t lm32_pic_get_ip(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
-
- trace_lm32_pic_get_ip(s->ip);
- return s->ip;
-}
-
-static void pic_reset(DeviceState *d)
-{
- LM32PicState *s = LM32_PIC(d);
- int i;
-
- s->im = 0;
- s->ip = 0;
- s->irq_state = 0;
- for (i = 0; i < 32; i++) {
- s->stats_irq_count[i] = 0;
- }
-}
-
-static bool lm32_get_statistics(InterruptStatsProvider *obj,
- uint64_t **irq_counts, unsigned int *nb_irqs)
-{
- LM32PicState *s = LM32_PIC(obj);
- *irq_counts = s->stats_irq_count;
- *nb_irqs = ARRAY_SIZE(s->stats_irq_count);
- return true;
-}
-
-static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon)
-{
- LM32PicState *s = LM32_PIC(obj);
- monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
- s->im, s->ip, s->irq_state);
-}
-
-static void lm32_pic_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- LM32PicState *s = LM32_PIC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- qdev_init_gpio_in(dev, irq_handler, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
-}
-
-static const VMStateDescription vmstate_lm32_pic = {
- .name = "lm32-pic",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(im, LM32PicState),
- VMSTATE_UINT32(ip, LM32PicState),
- VMSTATE_UINT32(irq_state, LM32PicState),
- VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
-
- dc->reset = pic_reset;
- dc->vmsd = &vmstate_lm32_pic;
- ic->get_statistics = lm32_get_statistics;
- ic->print_info = lm32_print_info;
-}
-
-static const TypeInfo lm32_pic_info = {
- .name = TYPE_LM32_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32PicState),
- .instance_init = lm32_pic_init,
- .class_init = lm32_pic_class_init,
- .interfaces = (InterfaceInfo[]) {
- { TYPE_INTERRUPT_STATS_PROVIDER },
- { }
- },
-};
-
-static void lm32_pic_register_types(void)
-{
- type_register_static(&lm32_pic_info);
-}
-
-type_init(lm32_pic_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 1c299039f6..6e52a166e3 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -14,10 +14,8 @@ softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c'))
softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c'))
-softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_pic.c'))
softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c'))
softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c'))
-softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_intc.c'))
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c'))
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c'))
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c'))
diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c
deleted file mode 100644
index 65226f5e7c..0000000000
--- a/hw/intc/puv3_intc.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * INTC device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-
-#define TYPE_PUV3_INTC "puv3_intc"
-OBJECT_DECLARE_SIMPLE_TYPE(PUV3INTCState, PUV3_INTC)
-
-struct PUV3INTCState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq parent_irq;
-
- uint32_t reg_ICMR;
- uint32_t reg_ICPR;
-};
-
-/* Update interrupt status after enabled or pending bits have been changed. */
-static void puv3_intc_update(PUV3INTCState *s)
-{
- if (s->reg_ICMR & s->reg_ICPR) {
- qemu_irq_raise(s->parent_irq);
- } else {
- qemu_irq_lower(s->parent_irq);
- }
-}
-
-/* Process a change in an external INTC input. */
-static void puv3_intc_handler(void *opaque, int irq, int level)
-{
- PUV3INTCState *s = opaque;
-
- DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
- if (level) {
- s->reg_ICPR |= (1 << irq);
- } else {
- s->reg_ICPR &= ~(1 << irq);
- }
- puv3_intc_update(s);
-}
-
-static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3INTCState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x04: /* INTC_ICMR */
- ret = s->reg_ICMR;
- break;
- case 0x0c: /* INTC_ICIP */
- ret = s->reg_ICPR; /* the same value with ICPR */
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
- return ret;
-}
-
-static void puv3_intc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3INTCState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x00: /* INTC_ICLR */
- case 0x14: /* INTC_ICCR */
- break;
- case 0x04: /* INTC_ICMR */
- s->reg_ICMR = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- return;
- }
- puv3_intc_update(s);
-}
-
-static const MemoryRegionOps puv3_intc_ops = {
- .read = puv3_intc_read,
- .write = puv3_intc_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_intc_realize(DeviceState *dev, Error **errp)
-{
- 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);
-
- s->reg_ICMR = 0;
- s->reg_ICPR = 0;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void puv3_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = puv3_intc_realize;
-}
-
-static const TypeInfo puv3_intc_info = {
- .name = TYPE_PUV3_INTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3INTCState),
- .class_init = puv3_intc_class_init,
-};
-
-static void puv3_intc_register_type(void)
-{
- type_register_static(&puv3_intc_info);
-}
-
-type_init(puv3_intc_register_type)
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index c9ab17234b..626bb554b2 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -51,15 +51,6 @@ grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d"
grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64
grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
-# lm32_pic.c
-lm32_pic_raise_irq(void) "Raise CPU interrupt"
-lm32_pic_lower_irq(void) "Lower CPU interrupt"
-lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
-lm32_pic_set_im(uint32_t im) "im 0x%08x"
-lm32_pic_set_ip(uint32_t ip) "ip 0x%08x"
-lm32_pic_get_im(uint32_t im) "im 0x%08x"
-lm32_pic_get_ip(uint32_t ip) "ip 0x%08x"
-
# xics.c
xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=0x%x"
xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx32"->0x%"PRIx32
diff --git a/hw/lm32/Kconfig b/hw/lm32/Kconfig
deleted file mode 100644
index 8ac94205d7..0000000000
--- a/hw/lm32/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config LM32_DEVICES
- bool
- select PTIMER
-
-config MILKYMIST
- bool
- # FIXME: disabling it results in compile-time errors
- select MILKYMIST_TMU2 if OPENGL && X11
- select PFLASH_CFI01
- select FRAMEBUFFER
- select SD
- select USB_OHCI
- select LM32_DEVICES
-
-config LM32_EVR
- bool
- select LM32_DEVICES
- select PFLASH_CFI02
diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h
deleted file mode 100644
index 7b4f6255b9..0000000000
--- a/hw/lm32/lm32.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef HW_LM32_H
-#define HW_LM32_H
-
-#include "hw/char/lm32_juart.h"
-#include "hw/qdev-properties.h"
-#include "qapi/error.h"
-
-static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
-{
- DeviceState *dev;
- SysBusDevice *d;
-
- dev = qdev_new("lm32-pic");
- d = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(d, &error_fatal);
- sysbus_connect_irq(d, 0, cpu_irq);
-
- return dev;
-}
-
-static inline DeviceState *lm32_juart_init(Chardev *chr)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_LM32_JUART);
- qdev_prop_set_chr(dev, "chardev", chr);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-
- return dev;
-}
-
-static inline DeviceState *lm32_uart_create(hwaddr addr,
- qemu_irq irq,
- Chardev *chr)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_new("lm32-uart");
- s = SYS_BUS_DEVICE(dev);
- qdev_prop_set_chr(dev, "chardev", chr);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, addr);
- sysbus_connect_irq(s, 0, irq);
- return dev;
-}
-
-#endif
diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c
deleted file mode 100644
index 2961e4c2b4..0000000000
--- a/hw/lm32/lm32_boards.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * QEMU models for LatticeMico32 uclinux and evr32 boards.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "qemu/units.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/irq.h"
-#include "hw/block/flash.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "lm32_hwsetup.h"
-#include "lm32.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
-
-typedef struct {
- LM32CPU *cpu;
- hwaddr bootstrap_pc;
- hwaddr flash_base;
- hwaddr hwsetup_base;
- hwaddr initrd_base;
- size_t initrd_size;
- hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
- LM32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetInfo *reset_info = opaque;
- CPULM32State *env = &reset_info->cpu->env;
-
- cpu_reset(CPU(reset_info->cpu));
-
- /* init defaults */
- env->pc = (uint32_t)reset_info->bootstrap_pc;
- env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base;
- env->regs[R_R2] = (uint32_t)reset_info->cmdline_base;
- env->regs[R_R3] = (uint32_t)reset_info->initrd_base;
- env->regs[R_R4] = (uint32_t)(reset_info->initrd_base +
- reset_info->initrd_size);
- env->eba = reset_info->flash_base;
- env->deba = reset_info->flash_base;
-}
-
-static void lm32_evr_init(MachineState *machine)
-{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- const char *kernel_filename = machine->kernel_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- qemu_irq irq[32];
- ResetInfo *reset_info;
- int i;
-
- if (machine->ram_size != mc->default_ram_size) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
- }
-
- /* memory map */
- hwaddr flash_base = 0x04000000;
- size_t flash_sector_size = 256 * KiB;
- size_t flash_size = 32 * MiB;
- hwaddr ram_base = 0x08000000;
- hwaddr timer0_base = 0x80002000;
- hwaddr uart0_base = 0x80006000;
- hwaddr timer1_base = 0x8000a000;
- int uart0_irq = 0;
- int timer0_irq = 1;
- int timer1_irq = 3;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- cpu = LM32_CPU(cpu_create(machine->cpu_type));
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- reset_info->flash_base = flash_base;
-
- memory_region_add_subregion(address_space_mem, ram_base, machine->ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size,
- 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0));
- sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
- sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init(serial_hd(1));
-
- reset_info->bootstrap_pc = flash_base;
-
- if (kernel_filename) {
- uint64_t entry;
- int kernel_size;
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &entry, NULL, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, ram_base,
- machine->ram_size);
- reset_info->bootstrap_pc = ram_base;
- }
-
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void lm32_uclinux_init(MachineState *machine)
-{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- qemu_irq irq[32];
- HWSetup *hw;
- ResetInfo *reset_info;
- int i;
-
- if (machine->ram_size != mc->default_ram_size) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
- }
-
- /* memory map */
- hwaddr flash_base = 0x04000000;
- size_t flash_sector_size = 256 * KiB;
- size_t flash_size = 32 * MiB;
- hwaddr ram_base = 0x08000000;
- hwaddr uart0_base = 0x80000000;
- hwaddr timer0_base = 0x80002000;
- hwaddr timer1_base = 0x80010000;
- hwaddr timer2_base = 0x80012000;
- int uart0_irq = 0;
- int timer0_irq = 1;
- int timer1_irq = 20;
- int timer2_irq = 21;
- hwaddr hwsetup_base = 0x0bffe000;
- hwaddr cmdline_base = 0x0bfff000;
- hwaddr initrd_base = 0x08400000;
- size_t initrd_max = 0x01000000;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- cpu = LM32_CPU(cpu_create(machine->cpu_type));
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- reset_info->flash_base = flash_base;
-
- memory_region_add_subregion(address_space_mem, ram_base, machine->ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Spansion S29NS128P */
- pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size,
- 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0));
- sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
- sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
- sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init(serial_hd(1));
-
- reset_info->bootstrap_pc = flash_base;
-
- if (kernel_filename) {
- uint64_t entry;
- int kernel_size;
-
- kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &entry, NULL, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, ram_base,
- machine->ram_size);
- reset_info->bootstrap_pc = ram_base;
- }
-
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- }
-
- /* generate a rom with the hardware description */
- hw = hwsetup_init();
- hwsetup_add_cpu(hw, "LM32", 75000000);
- hwsetup_add_flash(hw, "flash", flash_base, flash_size);
- hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, machine->ram_size);
- hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
- hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
- hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
- hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
- hwsetup_add_trailer(hw);
- hwsetup_create_rom(hw, hwsetup_base);
- hwsetup_free(hw);
-
- reset_info->hwsetup_base = hwsetup_base;
-
- if (kernel_cmdline && strlen(kernel_cmdline)) {
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
- kernel_cmdline);
- reset_info->cmdline_base = cmdline_base;
- }
-
- if (initrd_filename) {
- size_t initrd_size;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- initrd_max);
- reset_info->initrd_base = initrd_base;
- reset_info->initrd_size = initrd_size;
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void lm32_evr_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "LatticeMico32 EVR32 eval system";
- mc->init = lm32_evr_init;
- mc->is_default = true;
- mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
- mc->default_ram_size = 64 * MiB;
- mc->default_ram_id = "lm32_evr.sdram";
-}
-
-static const TypeInfo lm32_evr_type = {
- .name = MACHINE_TYPE_NAME("lm32-evr"),
- .parent = TYPE_MACHINE,
- .class_init = lm32_evr_class_init,
-};
-
-static void lm32_uclinux_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems";
- mc->init = lm32_uclinux_init;
- mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
- mc->default_ram_size = 64 * MiB;
- mc->default_ram_id = "lm32_uclinux.sdram";
-}
-
-static const TypeInfo lm32_uclinux_type = {
- .name = MACHINE_TYPE_NAME("lm32-uclinux"),
- .parent = TYPE_MACHINE,
- .class_init = lm32_uclinux_class_init,
-};
-
-static void lm32_machine_init(void)
-{
- type_register_static(&lm32_evr_type);
- type_register_static(&lm32_uclinux_type);
-}
-
-type_init(lm32_machine_init)
diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
deleted file mode 100644
index e6cd30ad68..0000000000
--- a/hw/lm32/lm32_hwsetup.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * LatticeMico32 hwsetup helper functions.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- */
-
-/*
- * These are helper functions for creating the hardware description blob used
- * in the Theobroma's uClinux port.
- */
-
-#ifndef QEMU_HW_LM32_HWSETUP_H
-#define QEMU_HW_LM32_HWSETUP_H
-
-#include "qemu/cutils.h"
-#include "hw/loader.h"
-
-typedef struct {
- void *data;
- void *ptr;
-} HWSetup;
-
-enum hwsetup_tag {
- HWSETUP_TAG_EOL = 0,
- HWSETUP_TAG_CPU = 1,
- HWSETUP_TAG_ASRAM = 2,
- HWSETUP_TAG_FLASH = 3,
- HWSETUP_TAG_SDRAM = 4,
- HWSETUP_TAG_OCM = 5,
- HWSETUP_TAG_DDR_SDRAM = 6,
- HWSETUP_TAG_DDR2_SDRAM = 7,
- HWSETUP_TAG_TIMER = 8,
- HWSETUP_TAG_UART = 9,
- HWSETUP_TAG_GPIO = 10,
- HWSETUP_TAG_TRISPEEDMAC = 11,
- HWSETUP_TAG_I2CM = 12,
- HWSETUP_TAG_LEDS = 13,
- HWSETUP_TAG_7SEG = 14,
- HWSETUP_TAG_SPI_S = 15,
- HWSETUP_TAG_SPI_M = 16,
-};
-
-static inline HWSetup *hwsetup_init(void)
-{
- HWSetup *hw;
-
- hw = g_malloc(sizeof(HWSetup));
- hw->data = g_malloc0(TARGET_PAGE_SIZE);
- hw->ptr = hw->data;
-
- return hw;
-}
-
-static inline void hwsetup_free(HWSetup *hw)
-{
- g_free(hw->data);
- g_free(hw);
-}
-
-static inline void hwsetup_create_rom(HWSetup *hw,
- hwaddr base)
-{
- rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE,
- TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true);
-}
-
-static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
-{
- stb_p(hw->ptr, u);
- hw->ptr += 1;
-}
-
-static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
-{
- stl_p(hw->ptr, u);
- hw->ptr += 4;
-}
-
-static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
-{
- stl_p(hw->ptr, t);
- hw->ptr += 4;
-}
-
-static inline void hwsetup_add_str(HWSetup *hw, const char *str)
-{
- pstrcpy(hw->ptr, 32, str);
- hw->ptr += 32;
-}
-
-static inline void hwsetup_add_trailer(HWSetup *hw)
-{
- hwsetup_add_u32(hw, 8); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
-}
-
-static inline void hwsetup_add_cpu(HWSetup *hw,
- const char *name, uint32_t frequency)
-{
- hwsetup_add_u32(hw, 44); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, frequency);
-}
-
-static inline void hwsetup_add_flash(HWSetup *hw,
- const char *name, uint32_t base, uint32_t size)
-{
- hwsetup_add_u32(hw, 52); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, size);
- hwsetup_add_u8(hw, 8); /* read latency */
- hwsetup_add_u8(hw, 8); /* write latency */
- hwsetup_add_u8(hw, 25); /* address width */
- hwsetup_add_u8(hw, 32); /* data width */
-}
-
-static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
- const char *name, uint32_t base, uint32_t size)
-{
- hwsetup_add_u32(hw, 48); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, size);
-}
-
-static inline void hwsetup_add_timer(HWSetup *hw,
- const char *name, uint32_t base, uint32_t irq)
-{
- hwsetup_add_u32(hw, 56); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u8(hw, 1); /* wr_tickcount */
- hwsetup_add_u8(hw, 1); /* rd_tickcount */
- hwsetup_add_u8(hw, 1); /* start_stop_control */
- hwsetup_add_u8(hw, 32); /* counter_width */
- hwsetup_add_u32(hw, 20); /* reload_ticks */
- hwsetup_add_u8(hw, irq);
- hwsetup_add_u8(hw, 0); /* padding */
- hwsetup_add_u8(hw, 0); /* padding */
- hwsetup_add_u8(hw, 0); /* padding */
-}
-
-static inline void hwsetup_add_uart(HWSetup *hw,
- const char *name, uint32_t base, uint32_t irq)
-{
- hwsetup_add_u32(hw, 56); /* size */
- hwsetup_add_tag(hw, HWSETUP_TAG_UART);
- hwsetup_add_str(hw, name);
- hwsetup_add_u32(hw, base);
- hwsetup_add_u32(hw, 115200); /* baudrate */
- hwsetup_add_u8(hw, 8); /* databits */
- hwsetup_add_u8(hw, 1); /* stopbits */
- hwsetup_add_u8(hw, 1); /* use_interrupt */
- hwsetup_add_u8(hw, 1); /* block_on_transmit */
- hwsetup_add_u8(hw, 1); /* block_on_receive */
- hwsetup_add_u8(hw, 4); /* rx_buffer_size */
- hwsetup_add_u8(hw, 4); /* tx_buffer_size */
- hwsetup_add_u8(hw, irq);
-}
-
-#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/hw/lm32/meson.build b/hw/lm32/meson.build
deleted file mode 100644
index 42d6f8db3d..0000000000
--- a/hw/lm32/meson.build
+++ /dev/null
@@ -1,6 +0,0 @@
-lm32_ss = ss.source_set()
-# LM32 boards
-lm32_ss.add(when: 'CONFIG_LM32_EVR', if_true: files('lm32_boards.c'))
-lm32_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist.c'))
-
-hw_arch += {'lm32': lm32_ss}
diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h
deleted file mode 100644
index 5dca5d52f5..0000000000
--- a/hw/lm32/milkymist-hw.h
+++ /dev/null
@@ -1,133 +0,0 @@
-#ifndef QEMU_HW_MILKYMIST_HW_H
-#define QEMU_HW_MILKYMIST_HW_H
-
-#include "hw/qdev-core.h"
-#include "net/net.h"
-#include "qapi/error.h"
-
-static inline DeviceState *milkymist_uart_create(hwaddr base,
- qemu_irq irq,
- Chardev *chr)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-uart");
- qdev_prop_set_chr(dev, "chardev", chr);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-hpdmc");
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_vgafb_create(hwaddr base,
- uint32_t fb_offset, uint32_t fb_mask)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-vgafb");
- qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
- qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_sysctl_create(hwaddr base,
- qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
- uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
- uint32_t gpio_strappings)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-sysctl");
- qdev_prop_set_uint32(dev, "frequency", freq_hz);
- qdev_prop_set_uint32(dev, "systemid", system_id);
- qdev_prop_set_uint32(dev, "capabilities", capabilities);
- qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_pfpu_create(hwaddr base,
- qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-pfpu");
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
- return dev;
-}
-
-static inline DeviceState *milkymist_ac97_create(hwaddr base,
- qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
- qemu_irq dmaw_irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-ac97");
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_minimac2_create(hwaddr base,
- hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
-{
- DeviceState *dev;
-
- qemu_check_nic_model(&nd_table[0], "minimac2");
- dev = qdev_new("milkymist-minimac2");
- qdev_set_nic_properties(dev, &nd_table[0]);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
-
- return dev;
-}
-
-static inline DeviceState *milkymist_softusb_create(hwaddr base,
- qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
- uint32_t dmem_base, uint32_t dmem_size)
-{
- DeviceState *dev;
-
- dev = qdev_new("milkymist-softusb");
- qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
- qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
- return dev;
-}
-
-#endif /* QEMU_HW_MILKYMIST_HW_H */
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
deleted file mode 100644
index bef7855328..0000000000
--- a/hw/lm32/milkymist.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * QEMU model for the Milkymist board.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "qemu/units.h"
-#include "qemu/error-report.h"
-#include "qemu-common.h"
-#include "qemu/datadir.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "hw/irq.h"
-#include "hw/block/flash.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/qdev-properties.h"
-#include "elf.h"
-#include "milkymist-hw.h"
-#include "hw/display/milkymist_tmu2.h"
-#include "hw/sd/sd.h"
-#include "lm32.h"
-#include "qemu/cutils.h"
-
-#define BIOS_FILENAME "mmone-bios.bin"
-#define BIOS_OFFSET 0x00860000
-#define BIOS_SIZE (512 * KiB)
-#define KERNEL_LOAD_ADDR 0x40000000
-
-typedef struct {
- LM32CPU *cpu;
- hwaddr bootstrap_pc;
- hwaddr flash_base;
- hwaddr initrd_base;
- size_t initrd_size;
- hwaddr cmdline_base;
-} ResetInfo;
-
-static void cpu_irq_handler(void *opaque, int irq, int level)
-{
- LM32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- ResetInfo *reset_info = opaque;
- CPULM32State *env = &reset_info->cpu->env;
-
- cpu_reset(CPU(reset_info->cpu));
-
- /* init defaults */
- env->pc = reset_info->bootstrap_pc;
- env->regs[R_R1] = reset_info->cmdline_base;
- env->regs[R_R2] = reset_info->initrd_base;
- env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size;
- env->eba = reset_info->flash_base;
- env->deba = reset_info->flash_base;
-}
-
-static DeviceState *milkymist_memcard_create(hwaddr base)
-{
- DeviceState *dev;
- DriveInfo *dinfo;
-
- dev = qdev_new("milkymist-memcard");
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- dinfo = drive_get_next(IF_SD);
- if (dinfo) {
- DeviceState *card;
-
- card = qdev_new(TYPE_SD_CARD);
- qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
- &error_fatal);
- qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"),
- &error_fatal);
- }
-
- return dev;
-}
-
-static void
-milkymist_init(MachineState *machine)
-{
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- const char *bios_name = machine->firmware ?: BIOS_FILENAME;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- LM32CPU *cpu;
- CPULM32State *env;
- int kernel_size;
- DriveInfo *dinfo;
- MemoryRegion *address_space_mem = get_system_memory();
- qemu_irq irq[32];
- int i;
- char *bios_filename;
- ResetInfo *reset_info;
-
- if (machine->ram_size != mc->default_ram_size) {
- char *sz = size_to_str(mc->default_ram_size);
- error_report("Invalid RAM size, should be %s", sz);
- g_free(sz);
- exit(EXIT_FAILURE);
- }
-
- /* memory map */
- hwaddr flash_base = 0x00000000;
- size_t flash_sector_size = 128 * KiB;
- size_t flash_size = 32 * MiB;
- hwaddr sdram_base = 0x40000000;
-
- hwaddr initrd_base = sdram_base + 0x1002000;
- hwaddr cmdline_base = sdram_base + 0x1000000;
- size_t initrd_max = machine->ram_size - 0x1002000;
-
- reset_info = g_malloc0(sizeof(ResetInfo));
-
- cpu = LM32_CPU(cpu_create(machine->cpu_type));
-
- env = &cpu->env;
- reset_info->cpu = cpu;
-
- cpu_lm32_set_phys_msb_ignore(env, 1);
-
- memory_region_add_subregion(address_space_mem, sdram_base, machine->ram);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- /* Numonyx JS28F256J3F105 */
- pflash_cfi01_register(flash_base, "milkymist.flash", flash_size,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1);
-
- /* create irq lines */
- env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0));
- for (i = 0; i < 32; i++) {
- irq[i] = qdev_get_gpio_in(env->pic_state, i);
- }
-
- /* load bios rom */
- bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-
- if (bios_filename) {
- if (load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE) < 0) {
- error_report("could not load bios '%s'", bios_filename);
- exit(1);
- }
- }
-
- reset_info->bootstrap_pc = BIOS_OFFSET;
-
- /* if no kernel is given no valid bios rom is a fatal error */
- if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) {
- error_report("could not load Milkymist One bios '%s'", bios_name);
- exit(1);
- }
- g_free(bios_filename);
-
- milkymist_uart_create(0x60000000, irq[0], serial_hd(0));
- milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3],
- 80000000, 0x10014d31, 0x0000041f, 0x00000001);
- milkymist_hpdmc_create(0x60002000);
- milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff);
- milkymist_memcard_create(0x60004000);
- milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
- milkymist_pfpu_create(0x60006000, irq[8]);
- if (machine->enable_graphics) {
- milkymist_tmu2_create(0x60007000, irq[9]);
- }
- milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
- milkymist_softusb_create(0x6000f000, irq[15],
- 0x20000000, 0x1000, 0x20020000, 0x2000);
-
- /* make sure juart isn't the first chardev */
- env->juart_state = lm32_juart_init(serial_hd(1));
-
- if (kernel_filename) {
- uint64_t entry;
-
- /* Boots a kernel elf binary. */
- kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
- &entry, NULL, NULL, NULL,
- 1, EM_LATTICEMICO32, 0, 0);
- reset_info->bootstrap_pc = entry;
-
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename, sdram_base,
- machine->ram_size);
- reset_info->bootstrap_pc = sdram_base;
- }
-
- if (kernel_size < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- }
-
- if (kernel_cmdline && strlen(kernel_cmdline)) {
- pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
- kernel_cmdline);
- reset_info->cmdline_base = (uint32_t)cmdline_base;
- }
-
- if (initrd_filename) {
- size_t initrd_size;
- initrd_size = load_image_targphys(initrd_filename, initrd_base,
- initrd_max);
- reset_info->initrd_base = (uint32_t)initrd_base;
- reset_info->initrd_size = (uint32_t)initrd_size;
- }
-
- qemu_register_reset(main_cpu_reset, reset_info);
-}
-
-static void milkymist_machine_init(MachineClass *mc)
-{
- mc->desc = "Milkymist One";
- mc->init = milkymist_init;
- mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full");
- mc->default_ram_size = 128 * MiB;
- mc->default_ram_id = "milkymist.sdram";
-}
-
-DEFINE_MACHINE("milkymist", milkymist_machine_init)
diff --git a/hw/mem/meson.build b/hw/mem/meson.build
index ef79e04678..3c8fdef9f9 100644
--- a/hw/mem/meson.build
+++ b/hw/mem/meson.build
@@ -1,8 +1,9 @@
mem_ss = ss.source_set()
mem_ss.add(files('memory-device.c'))
-mem_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c'))
mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss)
+
+softmmu_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c'))
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 12b655eda8..a3a2560301 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -34,6 +34,16 @@
static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp);
+static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp)
+{
+ if (!dimm->hostmem) {
+ error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set");
+ return NULL;
+ }
+
+ return host_memory_backend_get_memory(dimm->hostmem);
+}
+
void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine,
const uint64_t *legacy_align, Error **errp)
{
@@ -66,9 +76,8 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine,
void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine)
{
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
- &error_abort);
+ MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm,
+ &error_abort);
memory_device_plug(MEMORY_DEVICE(dimm), machine);
vmstate_register_ram(vmstate_mr, DEVICE(dimm));
@@ -76,9 +85,8 @@ void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine)
void pc_dimm_unplug(PCDIMMDevice *dimm, MachineState *machine)
{
- PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
- MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm,
- &error_abort);
+ MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm,
+ &error_abort);
memory_device_unplug(MEMORY_DEVICE(dimm), machine);
vmstate_unregister_ram(vmstate_mr, DEVICE(dimm));
@@ -205,16 +213,6 @@ static void pc_dimm_unrealize(DeviceState *dev)
host_memory_backend_set_mapped(dimm->hostmem, false);
}
-static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp)
-{
- if (!dimm->hostmem) {
- error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set");
- return NULL;
- }
-
- return host_memory_backend_get_memory(dimm->hostmem);
-}
-
static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md)
{
return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP,
@@ -266,7 +264,6 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md,
static void pc_dimm_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
dc->realize = pc_dimm_realize;
@@ -274,8 +271,6 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, pc_dimm_properties);
dc->desc = "DIMM memory module";
- ddc->get_vmstate_memory_region = pc_dimm_get_memory_region;
-
mdc->get_addr = pc_dimm_md_get_addr;
mdc->set_addr = pc_dimm_md_set_addr;
/* for a dimm plugged_size == region_size */
diff --git a/hw/meson.build b/hw/meson.build
index 8ba79b1a52..ba0601e36e 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -21,6 +21,7 @@ subdir('mem')
subdir('misc')
subdir('net')
subdir('nubus')
+subdir('nvme')
subdir('nvram')
subdir('pci')
subdir('pci-bridge')
@@ -47,11 +48,9 @@ subdir('avr')
subdir('cris')
subdir('hppa')
subdir('i386')
-subdir('lm32')
subdir('m68k')
subdir('microblaze')
subdir('mips')
-subdir('moxie')
subdir('nios2')
subdir('openrisc')
subdir('ppc')
@@ -63,5 +62,4 @@ subdir('sh4')
subdir('sparc')
subdir('sparc64')
subdir('tricore')
-subdir('unicore32')
subdir('xtensa')
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 1e7b8b064b..66e1648533 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -36,9 +36,6 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
-# PKUnity SoC devices
-softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c'))
-
subdir('macio')
softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c'))
@@ -63,7 +60,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-hpdmc.c', 'milkymist-pfpu.c'))
softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
'npcm7xx_clk.c',
diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c
deleted file mode 100644
index 09a3875f02..0000000000
--- a/hw/misc/milkymist-hpdmc.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * QEMU model of the Milkymist High Performance Dynamic Memory Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/hpdmc.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- R_SYSTEM = 0,
- R_BYPASS,
- R_TIMING,
- R_IODELAY,
- R_MAX
-};
-
-enum {
- IODELAY_DQSDELAY_RDY = (1<<5),
- IODELAY_PLL1_LOCKED = (1<<6),
- IODELAY_PLL2_LOCKED = (1<<7),
-};
-
-#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistHpdmcState, MILKYMIST_HPDMC)
-
-struct MilkymistHpdmcState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- uint32_t regs[R_MAX];
-};
-
-static uint64_t hpdmc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistHpdmcState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SYSTEM:
- case R_BYPASS:
- case R_TIMING:
- case R_IODELAY:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_hpdmc: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_hpdmc_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistHpdmcState *s = opaque;
-
- trace_milkymist_hpdmc_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_SYSTEM:
- case R_BYPASS:
- case R_TIMING:
- s->regs[addr] = value;
- break;
- case R_IODELAY:
- /* ignore writes */
- break;
-
- default:
- error_report("milkymist_hpdmc: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps hpdmc_mmio_ops = {
- .read = hpdmc_read,
- .write = hpdmc_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_hpdmc_reset(DeviceState *d)
-{
- MilkymistHpdmcState *s = MILKYMIST_HPDMC(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
- | IODELAY_PLL2_LOCKED;
-}
-
-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(SYS_BUS_DEVICE(dev), &s->regs_region);
-}
-
-static const VMStateDescription vmstate_milkymist_hpdmc = {
- .name = "milkymist-hpdmc",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_hpdmc_realize;
- dc->reset = milkymist_hpdmc_reset;
- dc->vmsd = &vmstate_milkymist_hpdmc;
-}
-
-static const TypeInfo milkymist_hpdmc_info = {
- .name = TYPE_MILKYMIST_HPDMC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistHpdmcState),
- .class_init = milkymist_hpdmc_class_init,
-};
-
-static void milkymist_hpdmc_register_types(void)
-{
- type_register_static(&milkymist_hpdmc_info);
-}
-
-type_init(milkymist_hpdmc_register_types)
diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c
deleted file mode 100644
index e4ee209c10..0000000000
--- a/hw/misc/milkymist-pfpu.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * QEMU model of the Milkymist programmable FPU.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/pfpu.pdf
- *
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/error-report.h"
-#include <math.h>
-#include "qom/object.h"
-
-/* #define TRACE_EXEC */
-
-#ifdef TRACE_EXEC
-# define D_EXEC(x) x
-#else
-# define D_EXEC(x)
-#endif
-
-enum {
- R_CTL = 0,
- R_MESHBASE,
- R_HMESHLAST,
- R_VMESHLAST,
- R_CODEPAGE,
- R_VERTICES,
- R_COLLISIONS,
- R_STRAYWRITES,
- R_LASTDMA,
- R_PC,
- R_DREGBASE,
- R_CODEBASE,
- R_MAX
-};
-
-enum {
- CTL_START_BUSY = (1<<0),
-};
-
-enum {
- OP_NOP = 0,
- OP_FADD,
- OP_FSUB,
- OP_FMUL,
- OP_FABS,
- OP_F2I,
- OP_I2F,
- OP_VECTOUT,
- OP_SIN,
- OP_COS,
- OP_ABOVE,
- OP_EQUAL,
- OP_COPY,
- OP_IF,
- OP_TSIGN,
- OP_QUAKE,
-};
-
-enum {
- GPR_X = 0,
- GPR_Y = 1,
- GPR_FLAGS = 2,
-};
-
-enum {
- LATENCY_FADD = 5,
- LATENCY_FSUB = 5,
- LATENCY_FMUL = 7,
- LATENCY_FABS = 2,
- LATENCY_F2I = 2,
- LATENCY_I2F = 3,
- LATENCY_VECTOUT = 0,
- LATENCY_SIN = 4,
- LATENCY_COS = 4,
- LATENCY_ABOVE = 2,
- LATENCY_EQUAL = 2,
- LATENCY_COPY = 2,
- LATENCY_IF = 2,
- LATENCY_TSIGN = 2,
- LATENCY_QUAKE = 2,
- MAX_LATENCY = 7
-};
-
-#define GPR_BEGIN 0x100
-#define GPR_END 0x17f
-#define MICROCODE_BEGIN 0x200
-#define MICROCODE_END 0x3ff
-#define MICROCODE_WORDS 2048
-
-#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
-
-#ifdef TRACE_EXEC
-static const char *opcode_to_str[] = {
- "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
- "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
-};
-#endif
-
-#define TYPE_MILKYMIST_PFPU "milkymist-pfpu"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistPFPUState, MILKYMIST_PFPU)
-
-struct MilkymistPFPUState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- Chardev *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
- uint32_t gp_regs[128];
- uint32_t microcode[MICROCODE_WORDS];
-
- int output_queue_pos;
- uint32_t output_queue[MAX_LATENCY];
-};
-
-static inline uint32_t
-get_dma_address(uint32_t base, uint32_t x, uint32_t y)
-{
- return base + 8 * (128 * y + x);
-}
-
-static inline void
-output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
-{
- s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
-}
-
-static inline uint32_t
-output_queue_remove(MilkymistPFPUState *s)
-{
- return s->output_queue[s->output_queue_pos];
-}
-
-static inline void
-output_queue_advance(MilkymistPFPUState *s)
-{
- s->output_queue[s->output_queue_pos] = 0;
- s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
-}
-
-static int pfpu_decode_insn(MilkymistPFPUState *s)
-{
- uint32_t pc = s->regs[R_PC];
- uint32_t insn = s->microcode[pc];
- uint32_t reg_a = (insn >> 18) & 0x7f;
- uint32_t reg_b = (insn >> 11) & 0x7f;
- uint32_t op = (insn >> 7) & 0xf;
- uint32_t reg_d = insn & 0x7f;
- uint32_t r = 0;
- int latency = 0;
-
- switch (op) {
- case OP_NOP:
- break;
- case OP_FADD:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a + b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FADD;
- D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FSUB:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a - b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FSUB;
- D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FMUL:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = a * b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FMUL;
- D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_FABS:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float t = fabsf(a);
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_FABS;
- D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_F2I:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- int32_t t = a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_F2I;
- D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
- } break;
- case OP_I2F:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_I2F;
- D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_VECTOUT:
- {
- uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
- uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
- hwaddr dma_ptr =
- get_dma_address(s->regs[R_MESHBASE],
- s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
- cpu_physical_memory_write(dma_ptr, &a, 4);
- cpu_physical_memory_write(dma_ptr + 4, &b, 4);
- s->regs[R_LASTDMA] = dma_ptr + 4;
- D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
- trace_milkymist_pfpu_vectout(a, b, dma_ptr);
- } break;
- case OP_SIN:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_SIN;
- D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_COS:
- {
- int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
- float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_COS;
- D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
- } break;
- case OP_ABOVE:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (a > b) ? 1.0f : 0.0f;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_ABOVE;
- D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_EQUAL:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (a == b) ? 1.0f : 0.0f;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_EQUAL;
- D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_COPY:
- {
- r = s->gp_regs[reg_a];
- latency = LATENCY_COPY;
- D_EXEC(qemu_log("COPY"));
- } break;
- case OP_IF:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- uint32_t f = s->gp_regs[GPR_FLAGS];
- float t = (f != 0) ? a : b;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_IF;
- D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
- } break;
- case OP_TSIGN:
- {
- float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
- float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
- float t = (b < 0) ? -a : a;
- r = REINTERPRET_CAST(uint32_t, t);
- latency = LATENCY_TSIGN;
- D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
- } break;
- case OP_QUAKE:
- {
- uint32_t a = s->gp_regs[reg_a];
- r = 0x5f3759df - (a >> 1);
- latency = LATENCY_QUAKE;
- D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
- } break;
-
- default:
- error_report("milkymist_pfpu: unknown opcode %d", op);
- break;
- }
-
- if (!reg_d) {
- D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
- s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
- s->regs[R_PC] + latency));
- } else {
- D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
- s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
- s->regs[R_PC] + latency, reg_d));
- }
-
- if (op == OP_VECTOUT) {
- return 0;
- }
-
- /* store output for this cycle */
- if (reg_d) {
- uint32_t val = output_queue_remove(s);
- D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
- s->gp_regs[reg_d] = val;
- }
-
- output_queue_advance(s);
-
- /* store op output */
- if (op != OP_NOP) {
- output_queue_insert(s, r, latency-1);
- }
-
- /* advance PC */
- s->regs[R_PC]++;
-
- return 1;
-};
-
-static void pfpu_start(MilkymistPFPUState *s)
-{
- int x, y;
- int i;
-
- for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
- for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
- D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
-
- /* set current position */
- s->gp_regs[GPR_X] = x;
- s->gp_regs[GPR_Y] = y;
-
- /* run microcode on this position */
- i = 0;
- while (pfpu_decode_insn(s)) {
- /* decode at most MICROCODE_WORDS instructions */
- if (++i >= MICROCODE_WORDS) {
- error_report("milkymist_pfpu: too many instructions "
- "executed in microcode. No VECTOUT?");
- break;
- }
- }
-
- /* reset pc for next run */
- s->regs[R_PC] = 0;
- }
- }
-
- s->regs[R_VERTICES] = x * y;
-
- trace_milkymist_pfpu_pulse_irq();
- qemu_irq_pulse(s->irq);
-}
-
-static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
-{
- return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
-}
-
-static uint64_t pfpu_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistPFPUState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- case R_MESHBASE:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CODEPAGE:
- case R_VERTICES:
- case R_COLLISIONS:
- case R_STRAYWRITES:
- case R_LASTDMA:
- case R_PC:
- case R_DREGBASE:
- case R_CODEBASE:
- r = s->regs[addr];
- break;
- case GPR_BEGIN ... GPR_END:
- r = s->gp_regs[addr - GPR_BEGIN];
- break;
- case MICROCODE_BEGIN ... MICROCODE_END:
- r = s->microcode[get_microcode_address(s, addr)];
- break;
-
- default:
- error_report("milkymist_pfpu: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_pfpu_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void pfpu_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistPFPUState *s = opaque;
-
- trace_milkymist_pfpu_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_CTL:
- if (value & CTL_START_BUSY) {
- pfpu_start(s);
- }
- break;
- case R_MESHBASE:
- case R_HMESHLAST:
- case R_VMESHLAST:
- case R_CODEPAGE:
- case R_VERTICES:
- case R_COLLISIONS:
- case R_STRAYWRITES:
- case R_LASTDMA:
- case R_PC:
- case R_DREGBASE:
- case R_CODEBASE:
- s->regs[addr] = value;
- break;
- case GPR_BEGIN ... GPR_END:
- s->gp_regs[addr - GPR_BEGIN] = value;
- break;
- case MICROCODE_BEGIN ... MICROCODE_END:
- s->microcode[get_microcode_address(s, addr)] = value;
- break;
-
- default:
- error_report("milkymist_pfpu: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps pfpu_mmio_ops = {
- .read = pfpu_read,
- .write = pfpu_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_pfpu_reset(DeviceState *d)
-{
- MilkymistPFPUState *s = MILKYMIST_PFPU(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- for (i = 0; i < 128; i++) {
- s->gp_regs[i] = 0;
- }
- for (i = 0; i < MICROCODE_WORDS; i++) {
- s->microcode[i] = 0;
- }
- s->output_queue_pos = 0;
- for (i = 0; i < MAX_LATENCY; i++) {
- s->output_queue[i] = 0;
- }
-}
-
-static void milkymist_pfpu_realize(DeviceState *dev, Error **errp)
-{
- MilkymistPFPUState *s = MILKYMIST_PFPU(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- 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(sbd, &s->regs_region);
-}
-
-static const VMStateDescription vmstate_milkymist_pfpu = {
- .name = "milkymist-pfpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
- VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
- VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
- VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
- VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_pfpu_realize;
- dc->reset = milkymist_pfpu_reset;
- dc->vmsd = &vmstate_milkymist_pfpu;
-}
-
-static const TypeInfo milkymist_pfpu_info = {
- .name = TYPE_MILKYMIST_PFPU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistPFPUState),
- .class_init = milkymist_pfpu_class_init,
-};
-
-static void milkymist_pfpu_register_types(void)
-{
- type_register_static(&milkymist_pfpu_info);
-}
-
-type_init(milkymist_pfpu_register_types)
diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c
deleted file mode 100644
index 676c23f7db..0000000000
--- a/hw/misc/puv3_pm.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Power Management device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-
-#define TYPE_PUV3_PM "puv3_pm"
-OBJECT_DECLARE_SIMPLE_TYPE(PUV3PMState, PUV3_PM)
-
-struct PUV3PMState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- uint32_t reg_PMCR;
- uint32_t reg_PCGR;
- uint32_t reg_PLL_SYS_CFG;
- uint32_t reg_PLL_DDR_CFG;
- uint32_t reg_PLL_VGA_CFG;
- uint32_t reg_DIVCFG;
-};
-
-static uint64_t puv3_pm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3PMState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x14:
- ret = s->reg_PCGR;
- break;
- case 0x18:
- ret = s->reg_PLL_SYS_CFG;
- break;
- case 0x1c:
- ret = s->reg_PLL_DDR_CFG;
- break;
- case 0x20:
- ret = s->reg_PLL_VGA_CFG;
- break;
- case 0x24:
- ret = s->reg_DIVCFG;
- break;
- case 0x28: /* PLL SYS STATUS */
- ret = 0x00002401;
- break;
- case 0x2c: /* PLL DDR STATUS */
- ret = 0x00100c00;
- break;
- case 0x30: /* PLL VGA STATUS */
- ret = 0x00003801;
- break;
- case 0x34: /* DIV STATUS */
- ret = 0x22f52015;
- break;
- case 0x38: /* SW RESET */
- ret = 0x0;
- break;
- case 0x44: /* PLL DFC DONE */
- ret = 0x7;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
- return ret;
-}
-
-static void puv3_pm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3PMState *s = opaque;
-
- switch (offset) {
- case 0x0:
- s->reg_PMCR = value;
- break;
- case 0x14:
- s->reg_PCGR = value;
- break;
- case 0x18:
- s->reg_PLL_SYS_CFG = value;
- break;
- case 0x1c:
- s->reg_PLL_DDR_CFG = value;
- break;
- case 0x20:
- s->reg_PLL_VGA_CFG = value;
- break;
- case 0x24:
- case 0x38:
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_pm_ops = {
- .read = puv3_pm_read,
- .write = puv3_pm_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_pm_realize(DeviceState *dev, Error **errp)
-{
- PUV3PMState *s = PUV3_PM(dev);
-
- s->reg_PCGR = 0x0;
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-}
-
-static void puv3_pm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = puv3_pm_realize;
-}
-
-static const TypeInfo puv3_pm_info = {
- .name = TYPE_PUV3_PM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3PMState),
- .class_init = puv3_pm_class_init,
-};
-
-static void puv3_pm_register_type(void)
-{
- type_register_static(&puv3_pm_info);
-}
-
-type_init(puv3_pm_register_type)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index d0a89eb059..0752217636 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -67,16 +67,6 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control 0x%08x"
slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x"
slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
-# milkymist-hpdmc.c
-milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x"
-milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x"
-
-# milkymist-pfpu.c
-milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a 0x%08x b 0x%08x dma_ptr 0x%08x"
-milkymist_pfpu_pulse_irq(void) "Pulse IRQ"
-
# aspeed_scu.c
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
diff --git a/hw/moxie/Kconfig b/hw/moxie/Kconfig
deleted file mode 100644
index 3793ef0372..0000000000
--- a/hw/moxie/Kconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-config MOXIESIM
- bool
- select SERIAL
diff --git a/hw/moxie/meson.build b/hw/moxie/meson.build
deleted file mode 100644
index 05a7c2e00f..0000000000
--- a/hw/moxie/meson.build
+++ /dev/null
@@ -1,4 +0,0 @@
-moxie_ss = ss.source_set()
-moxie_ss.add(when: 'CONFIG_MOXIESIM', if_true: files('moxiesim.c'))
-
-hw_arch += {'moxie': moxie_ss}
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
deleted file mode 100644
index 3d255d4879..0000000000
--- a/hw/moxie/moxiesim.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * QEMU/moxiesim emulation
- *
- * Emulates a very simple machine model similar to the one used by the
- * GDB moxie simulator.
- *
- * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green
- *
- * 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/error-report.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "net/net.h"
-#include "sysemu/reset.h"
-#include "sysemu/sysemu.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "hw/char/serial.h"
-#include "elf.h"
-
-#define PHYS_MEM_BASE 0x80000000
-#define FIRMWARE_BASE 0x1000
-#define FIRMWARE_SIZE (128 * 0x1000)
-
-typedef struct {
- uint64_t ram_size;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
-} LoaderParams;
-
-static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
-{
- uint64_t entry, kernel_high;
- int64_t initrd_size;
- long kernel_size;
- ram_addr_t initrd_offset;
-
- kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, NULL,
- &entry, NULL, &kernel_high, NULL, 1, EM_MOXIE,
- 0, 0);
-
- if (kernel_size <= 0) {
- error_report("could not load kernel '%s'",
- loader_params->kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- initrd_offset = 0;
- if (loader_params->initrd_filename) {
- initrd_size = get_image_size(loader_params->initrd_filename);
- if (initrd_size > 0) {
- initrd_offset = (kernel_high + ~TARGET_PAGE_MASK)
- & TARGET_PAGE_MASK;
- if (initrd_offset + initrd_size > loader_params->ram_size) {
- error_report("memory too small for initial ram disk '%s'",
- loader_params->initrd_filename);
- exit(1);
- }
- initrd_size = load_image_targphys(loader_params->initrd_filename,
- initrd_offset,
- loader_params->ram_size);
- }
- if (initrd_size == (target_ulong)-1) {
- error_report("could not load initial ram disk '%s'",
- loader_params->initrd_filename);
- exit(1);
- }
- }
-}
-
-static void main_cpu_reset(void *opaque)
-{
- MoxieCPU *cpu = opaque;
-
- cpu_reset(CPU(cpu));
-}
-
-static void moxiesim_init(MachineState *machine)
-{
- MoxieCPU *cpu = NULL;
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- const char *initrd_filename = machine->initrd_filename;
- CPUMoxieState *env;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- hwaddr ram_base = 0x200000;
- LoaderParams loader_params;
-
- /* Init CPUs. */
- cpu = MOXIE_CPU(cpu_create(machine->cpu_type));
- env = &cpu->env;
-
- qemu_register_reset(main_cpu_reset, cpu);
-
- /* Allocate RAM. */
- memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal);
- memory_region_add_subregion(address_space_mem, ram_base, ram);
-
- memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal);
- memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom);
-
- if (kernel_filename) {
- loader_params.ram_size = ram_size;
- loader_params.kernel_filename = kernel_filename;
- loader_params.kernel_cmdline = kernel_cmdline;
- loader_params.initrd_filename = initrd_filename;
- load_kernel(cpu, &loader_params);
- }
- if (machine->firmware) {
- if (load_image_targphys(machine->firmware, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) {
- error_report("Failed to load firmware '%s'", machine->firmware);
- }
- }
-
- /* A single 16450 sits at offset 0x3f8. */
- if (serial_hd(0)) {
- serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4],
- 8000000/16, serial_hd(0), DEVICE_LITTLE_ENDIAN);
- }
-}
-
-static void moxiesim_machine_init(MachineClass *mc)
-{
- mc->desc = "Moxie simulator platform";
- mc->init = moxiesim_init;
- mc->is_default = true;
- mc->default_cpu_type = MOXIE_CPU_TYPE_NAME("MoxieLite");
-}
-
-DEFINE_MACHINE("moxiesim", moxiesim_machine_init)
diff --git a/hw/net/meson.build b/hw/net/meson.build
index af0749c42b..bdf71f1f40 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -39,7 +39,6 @@ softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c'))
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
-specific_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-minimac2.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c'))
specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c'))
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
deleted file mode 100644
index 5826944fd5..0000000000
--- a/hw/net/milkymist-minimac2.c
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * QEMU model of the Milkymist minimac2 block.
- *
- * Copyright (c) 2011 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * not available yet
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qom/object.h"
-#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "net/net.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/error-report.h"
-
-#include <zlib.h>
-
-enum {
- R_SETUP = 0,
- R_MDIO,
- R_STATE0,
- R_COUNT0,
- R_STATE1,
- R_COUNT1,
- R_TXCOUNT,
- R_MAX
-};
-
-enum {
- SETUP_PHY_RST = (1<<0),
-};
-
-enum {
- MDIO_DO = (1<<0),
- MDIO_DI = (1<<1),
- MDIO_OE = (1<<2),
- MDIO_CLK = (1<<3),
-};
-
-enum {
- STATE_EMPTY = 0,
- STATE_LOADED = 1,
- STATE_PENDING = 2,
-};
-
-enum {
- MDIO_OP_WRITE = 1,
- MDIO_OP_READ = 2,
-};
-
-enum mdio_state {
- MDIO_STATE_IDLE,
- MDIO_STATE_READING,
- MDIO_STATE_WRITING,
-};
-
-enum {
- R_PHY_ID1 = 2,
- R_PHY_ID2 = 3,
- R_PHY_MAX = 32
-};
-
-#define MINIMAC2_MTU 1530
-#define MINIMAC2_BUFFER_SIZE 2048
-
-struct MilkymistMinimac2MdioState {
- int last_clk;
- int count;
- uint32_t data;
- uint16_t data_out;
- int state;
-
- uint8_t phy_addr;
- uint8_t reg_addr;
-};
-typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
-
-#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMinimac2State, MILKYMIST_MINIMAC2)
-
-struct MilkymistMinimac2State {
- SysBusDevice parent_obj;
-
- NICState *nic;
- NICConf conf;
- char *phy_model;
- MemoryRegion buffers;
- MemoryRegion regs_region;
-
- qemu_irq rx_irq;
- qemu_irq tx_irq;
-
- uint32_t regs[R_MAX];
-
- MilkymistMinimac2MdioState mdio;
-
- uint16_t phy_regs[R_PHY_MAX];
-
- uint8_t *rx0_buf;
- uint8_t *rx1_buf;
- uint8_t *tx_buf;
-};
-
-static const uint8_t preamble_sfd[] = {
- 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
-};
-
-static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
- uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
-{
- trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
-
- /* nop */
-}
-
-static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
- uint8_t phy_addr, uint8_t reg_addr)
-{
- uint16_t r = s->phy_regs[reg_addr];
-
- trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
-
- return r;
-}
-
-static void minimac2_update_mdio(MilkymistMinimac2State *s)
-{
- MilkymistMinimac2MdioState *m = &s->mdio;
-
- /* detect rising clk edge */
- if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
- /* shift data in */
- int bit = ((s->regs[R_MDIO] & MDIO_DO)
- && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
- m->data = (m->data << 1) | bit;
-
- /* check for sync */
- if (m->data == 0xffffffff) {
- m->count = 32;
- }
-
- if (m->count == 16) {
- uint8_t start = (m->data >> 14) & 0x3;
- uint8_t op = (m->data >> 12) & 0x3;
- uint8_t ta = (m->data) & 0x3;
-
- if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
- m->state = MDIO_STATE_WRITING;
- } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
- m->state = MDIO_STATE_READING;
- } else {
- m->state = MDIO_STATE_IDLE;
- }
-
- if (m->state != MDIO_STATE_IDLE) {
- m->phy_addr = (m->data >> 7) & 0x1f;
- m->reg_addr = (m->data >> 2) & 0x1f;
- }
-
- if (m->state == MDIO_STATE_READING) {
- m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
- m->reg_addr);
- }
- }
-
- if (m->count < 16 && m->state == MDIO_STATE_READING) {
- int bit = (m->data_out & 0x8000) ? 1 : 0;
- m->data_out <<= 1;
-
- if (bit) {
- s->regs[R_MDIO] |= MDIO_DI;
- } else {
- s->regs[R_MDIO] &= ~MDIO_DI;
- }
- }
-
- if (m->count == 0 && m->state) {
- if (m->state == MDIO_STATE_WRITING) {
- uint16_t data = m->data & 0xffff;
- minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
- }
- m->state = MDIO_STATE_IDLE;
- }
- m->count--;
- }
-
- m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
-}
-
-static size_t assemble_frame(uint8_t *buf, size_t size,
- const uint8_t *payload, size_t payload_size)
-{
- uint32_t crc;
-
- if (size < payload_size + 12) {
- qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big "
- "(%zd bytes)\n", payload_size);
- return 0;
- }
-
- /* prepend preamble and sfd */
- memcpy(buf, preamble_sfd, 8);
-
- /* now copy the payload */
- memcpy(buf + 8, payload, payload_size);
-
- /* pad frame if needed */
- if (payload_size < 60) {
- memset(buf + payload_size + 8, 0, 60 - payload_size);
- payload_size = 60;
- }
-
- /* append fcs */
- crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
- memcpy(buf + payload_size + 8, &crc, 4);
-
- return payload_size + 12;
-}
-
-static void minimac2_tx(MilkymistMinimac2State *s)
-{
- uint32_t txcount = s->regs[R_TXCOUNT];
- uint8_t *buf = s->tx_buf;
-
- if (txcount < 64) {
- error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
- txcount, 64);
- goto err;
- }
-
- if (txcount > MINIMAC2_MTU) {
- error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
- txcount, MINIMAC2_MTU);
- goto err;
- }
-
- if (memcmp(buf, preamble_sfd, 8) != 0) {
- error_report("milkymist_minimac2: frame doesn't contain the preamble "
- "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
- goto err;
- }
-
- trace_milkymist_minimac2_tx_frame(txcount - 12);
-
- /* send packet, skipping preamble and sfd */
- qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
-
- s->regs[R_TXCOUNT] = 0;
-
-err:
- trace_milkymist_minimac2_pulse_irq_tx();
- qemu_irq_pulse(s->tx_irq);
-}
-
-static void update_rx_interrupt(MilkymistMinimac2State *s)
-{
- if (s->regs[R_STATE0] == STATE_PENDING
- || s->regs[R_STATE1] == STATE_PENDING) {
- trace_milkymist_minimac2_raise_irq_rx();
- qemu_irq_raise(s->rx_irq);
- } else {
- trace_milkymist_minimac2_lower_irq_rx();
- qemu_irq_lower(s->rx_irq);
- }
-}
-
-static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
- uint32_t r_count;
- uint32_t r_state;
- uint8_t *rx_buf;
-
- size_t frame_size;
-
- trace_milkymist_minimac2_rx_frame(buf, size);
-
- /* choose appropriate slot */
- if (s->regs[R_STATE0] == STATE_LOADED) {
- r_count = R_COUNT0;
- r_state = R_STATE0;
- rx_buf = s->rx0_buf;
- } else if (s->regs[R_STATE1] == STATE_LOADED) {
- r_count = R_COUNT1;
- r_state = R_STATE1;
- rx_buf = s->rx1_buf;
- } else {
- return 0;
- }
-
- /* assemble frame */
- frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
-
- if (frame_size == 0) {
- return size;
- }
-
- trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
-
- /* update slot */
- s->regs[r_count] = frame_size;
- s->regs[r_state] = STATE_PENDING;
-
- update_rx_interrupt(s);
-
- return size;
-}
-
-static uint64_t
-minimac2_read(void *opaque, hwaddr addr, unsigned size)
-{
- MilkymistMinimac2State *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SETUP:
- case R_MDIO:
- case R_STATE0:
- case R_COUNT0:
- case R_STATE1:
- case R_COUNT1:
- case R_TXCOUNT:
- r = s->regs[addr];
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n",
- size, addr << 2);
- break;
- }
-
- trace_milkymist_minimac2_memory_read(addr << 2, r);
-
- return r;
-}
-
-static int minimac2_can_rx(MilkymistMinimac2State *s)
-{
- if (s->regs[R_STATE0] == STATE_LOADED) {
- return 1;
- }
- if (s->regs[R_STATE1] == STATE_LOADED) {
- return 1;
- }
-
- return 0;
-}
-
-static void
-minimac2_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistMinimac2State *s = opaque;
-
- trace_milkymist_minimac2_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_MDIO:
- {
- /* MDIO_DI is read only */
- int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
- s->regs[R_MDIO] = value;
- if (mdio_di) {
- s->regs[R_MDIO] |= mdio_di;
- } else {
- s->regs[R_MDIO] &= ~mdio_di;
- }
-
- minimac2_update_mdio(s);
- } break;
- case R_TXCOUNT:
- s->regs[addr] = value;
- if (value > 0) {
- minimac2_tx(s);
- }
- break;
- case R_STATE0:
- case R_STATE1:
- s->regs[addr] = value;
- update_rx_interrupt(s);
- if (minimac2_can_rx(s)) {
- qemu_flush_queued_packets(qemu_get_queue(s->nic));
- }
- break;
- case R_SETUP:
- case R_COUNT0:
- case R_COUNT1:
- s->regs[addr] = value;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx
- " = 0x%" PRIx64 "\n",
- size, addr << 2, value);
- break;
- }
-}
-
-static const MemoryRegionOps minimac2_ops = {
- .read = minimac2_read,
- .write = minimac2_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_minimac2_reset(DeviceState *d)
-{
- MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- for (i = 0; i < R_PHY_MAX; i++) {
- s->phy_regs[i] = 0;
- }
-
- /* defaults */
- s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
- s->phy_regs[R_PHY_ID2] = 0x161a;
-}
-
-static NetClientInfo net_milkymist_minimac2_info = {
- .type = NET_CLIENT_DRIVER_NIC,
- .size = sizeof(NICState),
- .receive = minimac2_rx,
-};
-
-static void milkymist_minimac2_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev);
- size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
-
- sysbus_init_irq(sbd, &s->rx_irq);
- sysbus_init_irq(sbd, &s->tx_irq);
-
- memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s,
- "milkymist-minimac2", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->regs_region);
-
- /* register buffers memory */
- memory_region_init_ram_nomigrate(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers",
- buffers_size, &error_fatal);
- vmstate_register_ram_global(&s->buffers);
- s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
- s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
- s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
-
- sysbus_init_mmio(sbd, &s->buffers);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->id, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
- .name = "milkymist-minimac2-mdio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
- VMSTATE_INT32(count, MilkymistMinimac2MdioState),
- VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
- VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
- VMSTATE_INT32(state, MilkymistMinimac2MdioState),
- VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
- VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_milkymist_minimac2 = {
- .name = "milkymist-minimac2",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
- VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
- VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
- vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_minimac2_properties[] = {
- DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
- DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_minimac2_realize;
- dc->reset = milkymist_minimac2_reset;
- dc->vmsd = &vmstate_milkymist_minimac2;
- device_class_set_props(dc, milkymist_minimac2_properties);
-}
-
-static const TypeInfo milkymist_minimac2_info = {
- .name = TYPE_MILKYMIST_MINIMAC2,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistMinimac2State),
- .class_init = milkymist_minimac2_class_init,
-};
-
-static void milkymist_minimac2_register_types(void)
-{
- type_register_static(&milkymist_minimac2_info);
-}
-
-type_init(milkymist_minimac2_register_types)
diff --git a/hw/net/trace-events b/hw/net/trace-events
index baf25ffa7e..314e21fa99 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -19,18 +19,6 @@ mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) "
lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x"
lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x"
-# milkymist-minimac2.c
-milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x"
-milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x"
-milkymist_minimac2_tx_frame(uint32_t length) "length %u"
-milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u"
-milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d"
-milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX"
-milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX"
-milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX"
-
# mipsnet.c
mipsnet_send(uint32_t size) "sending len=%u"
mipsnet_receive(uint32_t size) "receiving len=%u"
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 66b9ff4511..6b7e8dd04e 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -89,7 +89,7 @@
VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
-static VirtIOFeature feature_sizes[] = {
+static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_NET_F_MAC,
.end = endof(struct virtio_net_config, mac)},
{.flags = 1ULL << VIRTIO_NET_F_STATUS,
diff --git a/hw/nvme/Kconfig b/hw/nvme/Kconfig
new file mode 100644
index 0000000000..8ac90942e5
--- /dev/null
+++ b/hw/nvme/Kconfig
@@ -0,0 +1,4 @@
+config NVME_PCI
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
diff --git a/hw/block/nvme.c b/hw/nvme/ctrl.c
index 5fe082ec34..0bcaf7192f 100644
--- a/hw/block/nvme.c
+++ b/hw/nvme/ctrl.c
@@ -12,10 +12,19 @@
* Reference Specs: http://www.nvmexpress.org, 1.4, 1.3, 1.2, 1.1, 1.0e
*
* https://nvmexpress.org/developers/nvme-specification/
- */
-
-/**
- * Usage: add options:
+ *
+ *
+ * Notes on coding style
+ * ---------------------
+ * While QEMU coding style prefers lowercase hexadecimals in constants, the
+ * NVMe subsystem use thes format from the NVMe specifications in the comments
+ * (i.e. 'h' suffix instead of '0x' prefix).
+ *
+ * Usage
+ * -----
+ * See docs/system/nvme.rst for extensive documentation.
+ *
+ * Add options:
* -drive file=<file>,if=none,id=<drive_id>
* -device nvme-subsys,id=<subsys_id>,nqn=<nqn_id>
* -device nvme,serial=<serial>,id=<bus_name>, \
@@ -135,26 +144,20 @@
*/
#include "qemu/osdep.h"
-#include "qemu/units.h"
+#include "qemu/cutils.h"
#include "qemu/error-report.h"
-#include "hw/block/block.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+#include "qemu/units.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
-#include "sysemu/hostmem.h"
+#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
-#include "exec/memory.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qemu/cutils.h"
-#include "trace.h"
+#include "sysemu/hostmem.h"
+#include "hw/pci/msix.h"
+#include "migration/vmstate.h"
+
#include "nvme.h"
-#include "nvme-ns.h"
-#include "nvme-dif.h"
+#include "trace.h"
#define NVME_MAX_IOQPAIRS 0xffff
#define NVME_DB_SIZE 4
@@ -165,6 +168,7 @@
#define NVME_TEMPERATURE_WARNING 0x157
#define NVME_TEMPERATURE_CRITICAL 0x175
#define NVME_NUM_FW_SLOTS 1
+#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB)
#define NVME_GUEST_ERR(trace, fmt, ...) \
do { \
@@ -185,6 +189,7 @@ static const bool nvme_feature_support[NVME_FID_MAX] = {
[NVME_WRITE_ATOMICITY] = true,
[NVME_ASYNCHRONOUS_EVENT_CONF] = true,
[NVME_TIMESTAMP] = true,
+ [NVME_COMMAND_SET_PROFILE] = true,
};
static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
@@ -194,6 +199,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
[NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE,
[NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE,
[NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE,
+ [NVME_COMMAND_SET_PROFILE] = NVME_FEAT_CAP_CHANGE,
};
static const uint32_t nvme_cse_acs[256] = {
@@ -387,7 +393,8 @@ static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, void *buf, int size)
static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid)
{
- return nsid && (nsid == NVME_NSID_BROADCAST || nsid <= n->num_namespaces);
+ return nsid &&
+ (nsid == NVME_NSID_BROADCAST || nsid <= NVME_MAX_NAMESPACES);
}
static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid)
@@ -511,9 +518,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data,
NvmeSg *mdata)
{
NvmeSg *dst = data;
- size_t size = nvme_lsize(ns);
- size_t msize = nvme_msize(ns);
- uint32_t trans_len, count = size;
+ uint32_t trans_len, count = ns->lbasz;
uint64_t offset = 0;
bool dma = sg->flags & NVME_SG_DMA;
size_t sge_len;
@@ -545,7 +550,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data,
if (count == 0) {
dst = (dst == data) ? mdata : data;
- count = (dst == data) ? size : msize;
+ count = (dst == data) ? ns->lbasz : ns->lbaf.ms;
}
if (sge_len == offset) {
@@ -574,7 +579,7 @@ static uint16_t nvme_map_addr_cmb(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr,
}
static uint16_t nvme_map_addr_pmr(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr,
- size_t len)
+ size_t len)
{
if (!len) {
return NVME_SUCCESS;
@@ -1004,7 +1009,7 @@ static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req)
uint16_t status;
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) &&
- (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) {
+ (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) {
goto out;
}
@@ -1187,12 +1192,9 @@ uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
uint16_t ctrl = le16_to_cpu(rw->control);
if (nvme_ns_ext(ns) &&
- !(ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) {
- size_t lsize = nvme_lsize(ns);
- size_t msize = nvme_msize(ns);
-
- return nvme_tx_interleaved(n, &req->sg, ptr, len, lsize, msize, 0,
- dir);
+ !(ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) {
+ return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbasz,
+ ns->lbaf.ms, 0, dir);
}
return nvme_tx(n, &req->sg, ptr, len, dir);
@@ -1205,11 +1207,8 @@ uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
uint16_t status;
if (nvme_ns_ext(ns)) {
- size_t lsize = nvme_lsize(ns);
- size_t msize = nvme_msize(ns);
-
- return nvme_tx_interleaved(n, &req->sg, ptr, len, msize, lsize, lsize,
- dir);
+ return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbaf.ms,
+ ns->lbasz, ns->lbasz, dir);
}
nvme_sg_unmap(&req->sg);
@@ -1426,6 +1425,7 @@ static inline uint16_t nvme_check_bounds(NvmeNamespace *ns, uint64_t slba,
uint64_t nsze = le64_to_cpu(ns->id_ns.nsze);
if (unlikely(UINT64_MAX - slba < nlb || slba + nlb > nsze)) {
+ trace_pci_nvme_err_invalid_lba_range(slba, nlb, nsze);
return NVME_LBA_RANGE | NVME_DNR;
}
@@ -1682,8 +1682,12 @@ static void nvme_zrm_auto_transition_zone(NvmeNamespace *ns)
}
}
-static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone,
- bool implicit)
+enum {
+ NVME_ZRM_AUTO = 1 << 0,
+};
+
+static uint16_t nvme_zrm_open_flags(NvmeNamespace *ns, NvmeZone *zone,
+ int flags)
{
int act = 0;
uint16_t status;
@@ -1707,7 +1711,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone,
nvme_aor_inc_open(ns);
- if (implicit) {
+ if (flags & NVME_ZRM_AUTO) {
nvme_assign_zone_state(ns, zone, NVME_ZONE_STATE_IMPLICITLY_OPEN);
return NVME_SUCCESS;
}
@@ -1715,7 +1719,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone,
/* fallthrough */
case NVME_ZONE_STATE_IMPLICITLY_OPEN:
- if (implicit) {
+ if (flags & NVME_ZRM_AUTO) {
return NVME_SUCCESS;
}
@@ -1733,16 +1737,16 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone,
static inline uint16_t nvme_zrm_auto(NvmeNamespace *ns, NvmeZone *zone)
{
- return __nvme_zrm_open(ns, zone, true);
+ return nvme_zrm_open_flags(ns, zone, NVME_ZRM_AUTO);
}
static inline uint16_t nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone)
{
- return __nvme_zrm_open(ns, zone, false);
+ return nvme_zrm_open_flags(ns, zone, 0);
}
-static void __nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone,
- uint32_t nlb)
+static void nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone,
+ uint32_t nlb)
{
zone->d.wp += nlb;
@@ -1762,7 +1766,7 @@ static void nvme_finalize_zoned_write(NvmeNamespace *ns, NvmeRequest *req)
nlb = le16_to_cpu(rw->nlb) + 1;
zone = nvme_get_zone_by_slba(ns, slba);
- __nvme_advance_zone_wp(ns, zone, nlb);
+ nvme_advance_zone_wp(ns, zone, nlb);
}
static inline bool nvme_is_write(NvmeRequest *req)
@@ -1832,11 +1836,11 @@ static void nvme_rw_cb(void *opaque, int ret)
goto out;
}
- if (nvme_msize(ns)) {
+ if (ns->lbaf.ms) {
NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd;
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1;
- uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ uint64_t offset = nvme_moff(ns, slba);
if (req->cmd.opcode == NVME_CMD_WRITE_ZEROES) {
size_t mlen = nvme_m2b(ns, nlb);
@@ -2002,7 +2006,7 @@ static void nvme_verify_mdata_in_cb(void *opaque, int ret)
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
size_t mlen = nvme_m2b(ns, nlb);
- uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ uint64_t offset = nvme_moff(ns, slba);
BlockBackend *blk = ns->blkconf.blk;
trace_pci_nvme_verify_mdata_in_cb(nvme_cid(req), blk_name(blk));
@@ -2104,8 +2108,8 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret)
goto out;
}
- if (nvme_msize(ns)) {
- int64_t offset = ns->mdata_offset + nvme_m2b(ns, zone->d.zslba);
+ if (ns->lbaf.ms) {
+ int64_t offset = nvme_moff(ns, zone->d.zslba);
blk_aio_pwrite_zeroes(ns->blkconf.blk, offset,
nvme_m2b(ns, ns->zone_size), BDRV_REQ_MAY_UNMAP,
@@ -2151,7 +2155,7 @@ out:
uint64_t sdlba = le64_to_cpu(copy->sdlba);
NvmeZone *zone = nvme_get_zone_by_slba(ns, sdlba);
- __nvme_advance_zone_wp(ns, zone, ctx->nlb);
+ nvme_advance_zone_wp(ns, zone, ctx->nlb);
}
g_free(ctx->bounce);
@@ -2173,10 +2177,10 @@ static void nvme_copy_cb(void *opaque, int ret)
goto out;
}
- if (nvme_msize(ns)) {
+ if (ns->lbaf.ms) {
NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
uint64_t sdlba = le64_to_cpu(copy->sdlba);
- int64_t offset = ns->mdata_offset + nvme_m2b(ns, sdlba);
+ int64_t offset = nvme_moff(ns, sdlba);
qemu_iovec_reset(&req->sg.iov);
qemu_iovec_add(&req->sg.iov, ctx->mbounce, nvme_m2b(ns, ctx->nlb));
@@ -2268,7 +2272,6 @@ static void nvme_copy_in_complete(NvmeRequest *req)
status = nvme_check_bounds(ns, sdlba, ctx->nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(sdlba, ctx->nlb, ns->id_ns.nsze);
goto invalid;
}
@@ -2369,10 +2372,19 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
uint32_t reftag = le32_to_cpu(rw->reftag);
struct nvme_compare_ctx *ctx = req->opaque;
g_autofree uint8_t *buf = NULL;
+ BlockBackend *blk = ns->blkconf.blk;
+ BlockAcctCookie *acct = &req->acct;
+ BlockAcctStats *stats = blk_get_stats(blk);
uint16_t status = NVME_SUCCESS;
trace_pci_nvme_compare_mdata_cb(nvme_cid(req));
+ if (ret) {
+ block_acct_failed(stats, acct);
+ nvme_aio_err(req, ret);
+ goto out;
+ }
+
buf = g_malloc(ctx->mdata.iov.size);
status = nvme_bounce_mdata(n, buf, ctx->mdata.iov.size,
@@ -2387,7 +2399,6 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
uint8_t *bufp;
uint8_t *mbufp = ctx->mdata.bounce;
uint8_t *end = mbufp + ctx->mdata.iov.size;
- size_t msize = nvme_msize(ns);
int16_t pil = 0;
status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size,
@@ -2403,11 +2414,11 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
* tuple.
*/
if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) {
- pil = nvme_msize(ns) - sizeof(NvmeDifTuple);
+ pil = ns->lbaf.ms - sizeof(NvmeDifTuple);
}
- for (bufp = buf; mbufp < end; bufp += msize, mbufp += msize) {
- if (memcmp(bufp + pil, mbufp + pil, msize - pil)) {
+ for (bufp = buf; mbufp < end; bufp += ns->lbaf.ms, mbufp += ns->lbaf.ms) {
+ if (memcmp(bufp + pil, mbufp + pil, ns->lbaf.ms - pil)) {
req->status = NVME_CMP_FAILURE;
goto out;
}
@@ -2421,6 +2432,8 @@ static void nvme_compare_mdata_cb(void *opaque, int ret)
goto out;
}
+ block_acct_done(stats, acct);
+
out:
qemu_iovec_destroy(&ctx->data.iov);
g_free(ctx->data.bounce);
@@ -2468,12 +2481,12 @@ static void nvme_compare_data_cb(void *opaque, int ret)
goto out;
}
- if (nvme_msize(ns)) {
+ if (ns->lbaf.ms) {
NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd;
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
size_t mlen = nvme_m2b(ns, nlb);
- uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ uint64_t offset = nvme_moff(ns, slba);
ctx->mdata.bounce = g_malloc(mlen);
@@ -2530,8 +2543,6 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req)
uint32_t nlb = le32_to_cpu(range[i].nlb);
if (nvme_check_bounds(ns, slba, nlb)) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb,
- ns->id_ns.nsze);
continue;
}
@@ -2604,7 +2615,6 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req)
status = nvme_check_bounds(ns, slba, nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
return status;
}
@@ -2689,7 +2699,6 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
status = nvme_check_bounds(ns, slba, _nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(slba, _nlb, ns->id_ns.nsze);
goto out;
}
@@ -2716,7 +2725,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
}
bounce = bouncep = g_malloc(nvme_l2b(ns, nlb));
- if (nvme_msize(ns)) {
+ if (ns->lbaf.ms) {
mbounce = mbouncep = g_malloc(nvme_m2b(ns, nlb));
}
@@ -2752,9 +2761,9 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
bouncep += len;
- if (nvme_msize(ns)) {
+ if (ns->lbaf.ms) {
len = nvme_m2b(ns, nlb);
- offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ offset = nvme_moff(ns, slba);
in_ctx = g_new(struct nvme_copy_in_ctx, 1);
in_ctx->req = req;
@@ -2818,7 +2827,6 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req)
status = nvme_check_bounds(ns, slba, nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
return status;
}
@@ -2875,7 +2883,7 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req)
/* 1-initialize; see comment in nvme_dsm */
*num_flushes = 1;
- for (int i = 1; i <= n->num_namespaces; i++) {
+ for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -2923,7 +2931,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req)
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
bool pract = ctrl & NVME_RW_PRINFO_PRACT;
- if (pract && nvme_msize(ns) == 8) {
+ if (pract && ns->lbaf.ms == 8) {
mapped_size = data_size;
}
}
@@ -2938,7 +2946,6 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req)
status = nvme_check_bounds(ns, slba, nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
goto invalid;
}
@@ -3000,7 +3007,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append,
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
bool pract = ctrl & NVME_RW_PRINFO_PRACT;
- if (pract && nvme_msize(ns) == 8) {
+ if (pract && ns->lbaf.ms == 8) {
mapped_size -= nvme_m2b(ns, nlb);
}
}
@@ -3018,7 +3025,6 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append,
status = nvme_check_bounds(ns, slba, nlb);
if (status) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
goto invalid;
}
@@ -3595,8 +3601,8 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req)
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
{
+ NvmeNamespace *ns;
uint32_t nsid = le32_to_cpu(req->cmd.nsid);
- uint16_t status;
trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
@@ -3607,18 +3613,18 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
/*
* In the base NVM command set, Flush may apply to all namespaces
- * (indicated by NSID being set to 0xFFFFFFFF). But if that feature is used
+ * (indicated by NSID being set to FFFFFFFFh). But if that feature is used
* along with TP 4056 (Namespace Types), it may be pretty screwed up.
*
- * If NSID is indeed set to 0xFFFFFFFF, we simply cannot associate the
+ * If NSID is indeed set to FFFFFFFFh, we simply cannot associate the
* opcode with a specific command since we cannot determine a unique I/O
- * command set. Opcode 0x0 could have any other meaning than something
+ * command set. Opcode 0h could have any other meaning than something
* equivalent to flushing and say it DOES have completely different
- * semantics in some other command set - does an NSID of 0xFFFFFFFF then
+ * semantics in some other command set - does an NSID of FFFFFFFFh then
* mean "for all namespaces, apply whatever command set specific command
- * that uses the 0x0 opcode?" Or does it mean "for all namespaces, apply
- * whatever command that uses the 0x0 opcode if, and only if, it allows
- * NSID to be 0xFFFFFFFF"?
+ * that uses the 0h opcode?" Or does it mean "for all namespaces, apply
+ * whatever command that uses the 0h opcode if, and only if, it allows NSID
+ * to be FFFFFFFFh"?
*
* Anyway (and luckily), for now, we do not care about this since the
* device only supports namespace types that includes the NVM Flush command
@@ -3628,21 +3634,22 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
return nvme_flush(n, req);
}
- req->ns = nvme_ns(n, nsid);
- if (unlikely(!req->ns)) {
+ ns = nvme_ns(n, nsid);
+ if (unlikely(!ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
- if (!(req->ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
+ if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
}
- status = nvme_ns_status(req->ns);
- if (unlikely(status)) {
- return status;
+ if (ns->status) {
+ return ns->status;
}
+ req->ns = ns;
+
switch (req->cmd.opcode) {
case NVME_CMD_WRITE_ZEROES:
return nvme_write_zeroes(n, req);
@@ -3844,7 +3851,7 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
} else {
int i;
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -3934,7 +3941,7 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len,
NVME_CHANGED_NSID_SIZE) {
/*
* If more than 1024 namespaces, the first entry in the log page should
- * be set to 0xffffffff and the others to 0 as spec.
+ * be set to FFFFFFFFh and the others to 0 as spec.
*/
if (i == ARRAY_SIZE(nslist)) {
memset(nslist, 0x0, sizeof(nslist));
@@ -4332,7 +4339,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req,
trace_pci_nvme_identify_nslist(min_nsid);
/*
- * Both 0xffffffff (NVME_NSID_BROADCAST) and 0xfffffffe are invalid values
+ * Both FFFFFFFFh (NVME_NSID_BROADCAST) and FFFFFFFFEh are invalid values
* since the Active Namespace ID List should return namespaces with ids
* *higher* than the NSID specified in the command. This is also specified
* in the spec (NVM Express v1.3d, Section 5.15.4).
@@ -4341,7 +4348,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req,
return NVME_INVALID_NSID | NVME_DNR;
}
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
if (!active) {
@@ -4379,7 +4386,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req,
trace_pci_nvme_identify_nslist_csi(min_nsid, c->csi);
/*
- * Same as in nvme_identify_nslist(), 0xffffffff/0xfffffffe are invalid.
+ * Same as in nvme_identify_nslist(), FFFFFFFFh/FFFFFFFFEh are invalid.
*/
if (min_nsid >= NVME_NSID_BROADCAST - 1) {
return NVME_INVALID_NSID | NVME_DNR;
@@ -4389,7 +4396,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req,
return NVME_INVALID_FIELD | NVME_DNR;
}
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
if (!active) {
@@ -4446,7 +4453,7 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req)
/*
* Because the NGUID and EUI64 fields are 0 in the Identify Namespace data
- * structure, a Namespace UUID (nidt = 0x3) must be reported in the
+ * structure, a Namespace UUID (nidt = 3h) must be reported in the
* Namespace Identification Descriptor. Add the namespace UUID here.
*/
ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID;
@@ -4595,7 +4602,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
/*
* The Reservation Notification Mask and Reservation Persistence
* features require a status code of Invalid Field in Command when
- * NSID is 0xFFFFFFFF. Since the device does not support those
+ * NSID is FFFFFFFFh. Since the device does not support those
* features we can always return Invalid Namespace or Format as we
* should do for all other features.
*/
@@ -4655,7 +4662,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
goto out;
case NVME_VOLATILE_WRITE_CACHE:
result = 0;
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -4707,9 +4714,6 @@ defaults:
result |= NVME_INTVC_NOCOALESCING;
}
break;
- case NVME_COMMAND_SET_PROFILE:
- result = 0;
- break;
default:
result = nvme_feature_default[fid];
break;
@@ -4805,7 +4809,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
break;
case NVME_ERROR_RECOVERY:
if (nsid == NVME_NSID_BROADCAST) {
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
@@ -4826,7 +4830,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
}
break;
case NVME_VOLATILE_WRITE_CACHE:
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -4847,15 +4851,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
}
/*
- * NVMe v1.3, Section 5.21.1.7: 0xffff is not an allowed value for NCQR
+ * NVMe v1.3, Section 5.21.1.7: FFFFh is not an allowed value for NCQR
* and NSQR.
*/
if ((dw11 & 0xffff) == 0xffff || ((dw11 >> 16) & 0xffff) == 0xffff) {
return NVME_INVALID_FIELD | NVME_DNR;
}
- trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
- ((dw11 >> 16) & 0xFFFF) + 1,
+ trace_pci_nvme_setfeat_numq((dw11 & 0xffff) + 1,
+ ((dw11 >> 16) & 0xffff) + 1,
n->params.max_ioqpairs,
n->params.max_ioqpairs);
req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) |
@@ -4912,7 +4916,25 @@ static void nvme_update_dmrsl(NvmeCtrl *n)
}
}
-static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns);
+static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns)
+{
+ ns->iocs = nvme_cse_iocs_none;
+ switch (ns->csi) {
+ case NVME_CSI_NVM:
+ if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) {
+ ns->iocs = nvme_cse_iocs_nvm;
+ }
+ break;
+ case NVME_CSI_ZONED:
+ if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) {
+ ns->iocs = nvme_cse_iocs_zoned;
+ } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) {
+ ns->iocs = nvme_cse_iocs_nvm;
+ }
+ break;
+ }
+}
+
static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
{
NvmeNamespace *ns;
@@ -4963,13 +4985,13 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
}
nvme_attach_ns(ctrl, ns);
- __nvme_select_ns_iocs(ctrl, ns);
+ nvme_select_iocs_ns(ctrl, ns);
} else {
if (!nvme_ns(ctrl, nsid)) {
return NVME_NS_NOT_ATTACHED | NVME_DNR;
}
- ctrl->namespaces[nsid - 1] = NULL;
+ ctrl->namespaces[nsid] = NULL;
ns->attached--;
nvme_update_dmrsl(ctrl);
@@ -5101,7 +5123,7 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req)
req->status = status;
}
} else {
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -5212,7 +5234,7 @@ static void nvme_ctrl_reset(NvmeCtrl *n)
NvmeNamespace *ns;
int i;
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -5254,7 +5276,7 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n)
memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size);
}
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
@@ -5264,37 +5286,18 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n)
}
}
-static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns)
-{
- ns->iocs = nvme_cse_iocs_none;
- switch (ns->csi) {
- case NVME_CSI_NVM:
- if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) {
- ns->iocs = nvme_cse_iocs_nvm;
- }
- break;
- case NVME_CSI_ZONED:
- if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) {
- ns->iocs = nvme_cse_iocs_zoned;
- } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) {
- ns->iocs = nvme_cse_iocs_nvm;
- }
- break;
- }
-}
-
-static void nvme_select_ns_iocs(NvmeCtrl *n)
+static void nvme_select_iocs(NvmeCtrl *n)
{
NvmeNamespace *ns;
int i;
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
}
- __nvme_select_ns_iocs(n, ns);
+ nvme_select_iocs_ns(n, ns);
}
}
@@ -5396,7 +5399,7 @@ static int nvme_start_ctrl(NvmeCtrl *n)
QTAILQ_INIT(&n->aer_queue);
- nvme_select_ns_iocs(n);
+ nvme_select_iocs(n);
return 0;
}
@@ -5493,7 +5496,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
n->bar.cc = data;
}
break;
- case 0x1C: /* CSTS */
+ case 0x1c: /* CSTS */
if (data & (1 << 4)) {
NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ssreset_w1c_unsupported,
"attempted to W1C CSTS.NSSRO"
@@ -5505,7 +5508,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
}
break;
case 0x20: /* NSSR */
- if (data == 0x4E564D65) {
+ if (data == 0x4e564d65) {
trace_pci_nvme_ub_mmiowr_ssreset_unsupported();
} else {
/* The spec says that writes of other values have no effect */
@@ -5575,11 +5578,11 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
n->bar.cmbmsc = (n->bar.cmbmsc & 0xffffffff) | (data << 32);
return;
- case 0xE00: /* PMRCAP */
+ case 0xe00: /* PMRCAP */
NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrcap_readonly,
"invalid write to PMRCAP register, ignored");
return;
- case 0xE04: /* PMRCTL */
+ case 0xe04: /* PMRCTL */
n->bar.pmrctl = data;
if (NVME_PMRCTL_EN(data)) {
memory_region_set_enabled(&n->pmr.dev->mr, true);
@@ -5590,19 +5593,19 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
n->pmr.cmse = false;
}
return;
- case 0xE08: /* PMRSTS */
+ case 0xe08: /* PMRSTS */
NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly,
"invalid write to PMRSTS register, ignored");
return;
- case 0xE0C: /* PMREBS */
+ case 0xe0C: /* PMREBS */
NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrebs_readonly,
"invalid write to PMREBS register, ignored");
return;
- case 0xE10: /* PMRSWTP */
+ case 0xe10: /* PMRSWTP */
NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrswtp_readonly,
"invalid write to PMRSWTP register, ignored");
return;
- case 0xE14: /* PMRMSCL */
+ case 0xe14: /* PMRMSCL */
if (!NVME_CAP_PMRS(n->bar.cap)) {
return;
}
@@ -5622,7 +5625,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
}
return;
- case 0xE18: /* PMRMSCU */
+ case 0xe18: /* PMRMSCU */
if (!NVME_CAP_PMRS(n->bar.cap)) {
return;
}
@@ -5664,7 +5667,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
* from PMRSTS should ensure prior writes
* made it to persistent media
*/
- if (addr == 0xE08 &&
+ if (addr == 0xe08 &&
(NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size);
}
@@ -5915,7 +5918,6 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp)
static void nvme_init_state(NvmeCtrl *n)
{
- n->num_namespaces = NVME_MAX_NAMESPACES;
/* add one to max_ioqpairs to account for the admin queue pair */
n->reg_size = pow2ceil(sizeof(NvmeBar) +
2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE);
@@ -6096,7 +6098,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->sqes = (0x6 << 4) | 0x6;
id->cqes = (0x4 << 4) | 0x4;
- id->nn = cpu_to_le32(n->num_namespaces);
+ id->nn = cpu_to_le32(NVME_MAX_NAMESPACES);
id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
NVME_ONCS_FEATURES | NVME_ONCS_DSM |
NVME_ONCS_COMPARE | NVME_ONCS_COPY);
@@ -6161,7 +6163,7 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns)
uint32_t nsid = ns->params.nsid;
assert(nsid && nsid <= NVME_MAX_NAMESPACES);
- n->namespaces[nsid - 1] = ns;
+ n->namespaces[nsid] = ns;
ns->attached++;
n->dmrsl = MIN_NON_ZERO(n->dmrsl,
@@ -6215,7 +6217,7 @@ static void nvme_exit(PCIDevice *pci_dev)
nvme_ctrl_reset(n);
- for (i = 1; i <= n->num_namespaces; i++) {
+ for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
ns = nvme_ns(n, i);
if (!ns) {
continue;
diff --git a/hw/block/nvme-dif.c b/hw/nvme/dif.c
index 81b0a4cb13..88efcbe9bd 100644
--- a/hw/block/nvme-dif.c
+++ b/hw/nvme/dif.c
@@ -9,13 +9,11 @@
*/
#include "qemu/osdep.h"
-#include "hw/block/block.h"
-#include "sysemu/dma.h"
-#include "sysemu/block-backend.h"
#include "qapi/error.h"
-#include "trace.h"
+#include "sysemu/block-backend.h"
+
#include "nvme.h"
-#include "nvme-dif.h"
+#include "trace.h"
uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba,
uint32_t reftag)
@@ -46,20 +44,18 @@ void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len,
uint32_t reftag)
{
uint8_t *end = buf + len;
- size_t lsize = nvme_lsize(ns);
- size_t msize = nvme_msize(ns);
int16_t pil = 0;
if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) {
- pil = nvme_msize(ns) - sizeof(NvmeDifTuple);
+ pil = ns->lbaf.ms - sizeof(NvmeDifTuple);
}
- trace_pci_nvme_dif_pract_generate_dif(len, lsize, lsize + pil, apptag,
- reftag);
+ trace_pci_nvme_dif_pract_generate_dif(len, ns->lbasz, ns->lbasz + pil,
+ apptag, reftag);
- for (; buf < end; buf += lsize, mbuf += msize) {
+ for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) {
NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil);
- uint16_t crc = crc_t10dif(0x0, buf, lsize);
+ uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz);
if (pil) {
crc = crc_t10dif(crc, mbuf, pil);
@@ -100,7 +96,7 @@ static uint16_t nvme_dif_prchk(NvmeNamespace *ns, NvmeDifTuple *dif,
}
if (ctrl & NVME_RW_PRINFO_PRCHK_GUARD) {
- uint16_t crc = crc_t10dif(0x0, buf, nvme_lsize(ns));
+ uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz);
if (pil) {
crc = crc_t10dif(crc, mbuf, pil);
@@ -139,8 +135,6 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len,
uint16_t appmask, uint32_t reftag)
{
uint8_t *end = buf + len;
- size_t lsize = nvme_lsize(ns);
- size_t msize = nvme_msize(ns);
int16_t pil = 0;
uint16_t status;
@@ -150,12 +144,12 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len,
}
if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) {
- pil = nvme_msize(ns) - sizeof(NvmeDifTuple);
+ pil = ns->lbaf.ms - sizeof(NvmeDifTuple);
}
- trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), lsize + pil);
+ trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), ns->lbasz + pil);
- for (; buf < end; buf += lsize, mbuf += msize) {
+ for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) {
NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil);
status = nvme_dif_prchk(ns, dif, buf, mbuf, pil, ctrl, apptag,
@@ -178,20 +172,18 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen,
BlockBackend *blk = ns->blkconf.blk;
BlockDriverState *bs = blk_bs(blk);
- size_t msize = nvme_msize(ns);
- size_t lsize = nvme_lsize(ns);
int64_t moffset = 0, offset = nvme_l2b(ns, slba);
uint8_t *mbufp, *end;
bool zeroed;
int16_t pil = 0;
- int64_t bytes = (mlen / msize) * lsize;
+ int64_t bytes = (mlen / ns->lbaf.ms) << ns->lbaf.ds;
int64_t pnum = 0;
Error *err = NULL;
if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) {
- pil = nvme_msize(ns) - sizeof(NvmeDifTuple);
+ pil = ns->lbaf.ms - sizeof(NvmeDifTuple);
}
do {
@@ -213,15 +205,15 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen,
if (zeroed) {
mbufp = mbuf + moffset;
- mlen = (pnum / lsize) * msize;
+ mlen = (pnum >> ns->lbaf.ds) * ns->lbaf.ms;
end = mbufp + mlen;
- for (; mbufp < end; mbufp += msize) {
+ for (; mbufp < end; mbufp += ns->lbaf.ms) {
memset(mbufp + pil, 0xff, sizeof(NvmeDifTuple));
}
}
- moffset += (pnum / lsize) * msize;
+ moffset += (pnum >> ns->lbaf.ds) * ns->lbaf.ms;
offset += pnum;
} while (pnum != bytes);
@@ -291,7 +283,7 @@ static void nvme_dif_rw_check_cb(void *opaque, int ret)
goto out;
}
- if (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8) {
+ if (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8) {
goto out;
}
@@ -314,7 +306,7 @@ static void nvme_dif_rw_mdata_in_cb(void *opaque, int ret)
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
size_t mlen = nvme_m2b(ns, nlb);
- uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ uint64_t offset = nvme_moff(ns, slba);
BlockBackend *blk = ns->blkconf.blk;
trace_pci_nvme_dif_rw_mdata_in_cb(nvme_cid(req), blk_name(blk));
@@ -343,7 +335,7 @@ static void nvme_dif_rw_mdata_out_cb(void *opaque, int ret)
NvmeNamespace *ns = req->ns;
NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd;
uint64_t slba = le64_to_cpu(rw->slba);
- uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba);
+ uint64_t offset = nvme_moff(ns, slba);
BlockBackend *blk = ns->blkconf.blk;
trace_pci_nvme_dif_rw_mdata_out_cb(nvme_cid(req), blk_name(blk));
@@ -395,8 +387,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req)
if (pract) {
uint8_t *mbuf, *end;
- size_t msize = nvme_msize(ns);
- int16_t pil = msize - sizeof(NvmeDifTuple);
+ int16_t pil = ns->lbaf.ms - sizeof(NvmeDifTuple);
status = nvme_check_prinfo(ns, ctrl, slba, reftag);
if (status) {
@@ -417,7 +408,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req)
pil = 0;
}
- for (; mbuf < end; mbuf += msize) {
+ for (; mbuf < end; mbuf += ns->lbaf.ms) {
NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil);
dif->apptag = cpu_to_be16(apptag);
@@ -436,7 +427,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req)
return NVME_NO_COMPLETE;
}
- if (nvme_ns_ext(ns) && !(pract && nvme_msize(ns) == 8)) {
+ if (nvme_ns_ext(ns) && !(pract && ns->lbaf.ms == 8)) {
mapped_len += mlen;
}
@@ -470,7 +461,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req)
qemu_iovec_init(&ctx->mdata.iov, 1);
qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen);
- if (!(pract && nvme_msize(ns) == 8)) {
+ if (!(pract && ns->lbaf.ms == 8)) {
status = nvme_bounce_mdata(n, ctx->mdata.bounce, ctx->mdata.iov.size,
NVME_TX_DIRECTION_TO_DEVICE, req);
if (status) {
diff --git a/hw/nvme/meson.build b/hw/nvme/meson.build
new file mode 100644
index 0000000000..3cf40046ee
--- /dev/null
+++ b/hw/nvme/meson.build
@@ -0,0 +1 @@
+softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c', 'dif.c', 'ns.c', 'subsys.c'))
diff --git a/hw/block/nvme-ns.c b/hw/nvme/ns.c
index 7bb618f182..992e5a13f5 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/nvme/ns.c
@@ -14,23 +14,16 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "qemu/cutils.h"
-#include "qemu/log.h"
#include "qemu/error-report.h"
-#include "hw/block/block.h"
-#include "hw/pci/pci.h"
+#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
-#include "qapi/error.h"
-
-#include "hw/qdev-properties.h"
-#include "hw/qdev-core.h"
-#include "trace.h"
#include "nvme.h"
-#include "nvme-ns.h"
+#include "trace.h"
#define MIN_DISCARD_GRANULARITY (4 * KiB)
+#define NVME_DEFAULT_ZONE_SIZE (128 * MiB)
void nvme_ns_init_format(NvmeNamespace *ns)
{
@@ -38,7 +31,10 @@ void nvme_ns_init_format(NvmeNamespace *ns)
BlockDriverInfo bdi;
int npdg, nlbas, ret;
- nlbas = nvme_ns_nlbas(ns);
+ ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
+ ns->lbasz = 1 << ns->lbaf.ds;
+
+ nlbas = ns->size / (ns->lbasz + ns->lbaf.ms);
id_ns->nsze = cpu_to_le64(nlbas);
@@ -46,13 +42,13 @@ void nvme_ns_init_format(NvmeNamespace *ns)
id_ns->ncap = id_ns->nsze;
id_ns->nuse = id_ns->ncap;
- ns->mdata_offset = nvme_l2b(ns, nlbas);
+ ns->moff = (int64_t)nlbas << ns->lbaf.ds;
- npdg = ns->blkconf.discard_granularity / nvme_lsize(ns);
+ npdg = ns->blkconf.discard_granularity / ns->lbasz;
ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi);
if (ret >= 0 && bdi.cluster_size > ns->blkconf.discard_granularity) {
- npdg = bdi.cluster_size / nvme_lsize(ns);
+ npdg = bdi.cluster_size / ns->lbasz;
}
id_ns->npda = id_ns->npdg = npdg - 1;
@@ -170,7 +166,6 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp)
{
uint64_t zone_size, zone_cap;
- uint32_t lbasz = nvme_lsize(ns);
/* Make sure that the values of ZNS properties are sane */
if (ns->params.zone_size_bs) {
@@ -188,14 +183,14 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp)
"zone size %"PRIu64"B", zone_cap, zone_size);
return -1;
}
- if (zone_size < lbasz) {
+ if (zone_size < ns->lbasz) {
error_setg(errp, "zone size %"PRIu64"B too small, "
- "must be at least %"PRIu32"B", zone_size, lbasz);
+ "must be at least %zuB", zone_size, ns->lbasz);
return -1;
}
- if (zone_cap < lbasz) {
+ if (zone_cap < ns->lbasz) {
error_setg(errp, "zone capacity %"PRIu64"B too small, "
- "must be at least %"PRIu32"B", zone_cap, lbasz);
+ "must be at least %zuB", zone_cap, ns->lbasz);
return -1;
}
@@ -203,9 +198,9 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp)
* Save the main zone geometry values to avoid
* calculating them later again.
*/
- ns->zone_size = zone_size / lbasz;
- ns->zone_capacity = zone_cap / lbasz;
- ns->num_zones = nvme_ns_nlbas(ns) / ns->zone_size;
+ ns->zone_size = zone_size / ns->lbasz;
+ ns->zone_capacity = zone_cap / ns->lbasz;
+ ns->num_zones = le64_to_cpu(ns->id_ns.nsze) / ns->zone_size;
/* Do a few more sanity checks of ZNS properties */
if (!ns->num_zones) {
@@ -215,43 +210,6 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp)
return -1;
}
- if (ns->params.max_open_zones > ns->num_zones) {
- error_setg(errp,
- "max_open_zones value %u exceeds the number of zones %u",
- ns->params.max_open_zones, ns->num_zones);
- return -1;
- }
- if (ns->params.max_active_zones > ns->num_zones) {
- error_setg(errp,
- "max_active_zones value %u exceeds the number of zones %u",
- ns->params.max_active_zones, ns->num_zones);
- return -1;
- }
-
- if (ns->params.max_active_zones) {
- if (ns->params.max_open_zones > ns->params.max_active_zones) {
- error_setg(errp, "max_open_zones (%u) exceeds max_active_zones (%u)",
- ns->params.max_open_zones, ns->params.max_active_zones);
- return -1;
- }
-
- if (!ns->params.max_open_zones) {
- ns->params.max_open_zones = ns->params.max_active_zones;
- }
- }
-
- if (ns->params.zd_extension_size) {
- if (ns->params.zd_extension_size & 0x3f) {
- error_setg(errp,
- "zone descriptor extension size must be a multiple of 64B");
- return -1;
- }
- if ((ns->params.zd_extension_size >> 6) > 0xff) {
- error_setg(errp, "zone descriptor extension size is too large");
- return -1;
- }
- }
-
return 0;
}
@@ -303,7 +261,7 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns)
id_ns_z = g_malloc0(sizeof(NvmeIdNsZoned));
- /* MAR/MOR are zeroes-based, 0xffffffff means no limit */
+ /* MAR/MOR are zeroes-based, FFFFFFFFFh means no limit */
id_ns_z->mar = cpu_to_le32(ns->params.max_active_zones - 1);
id_ns_z->mor = cpu_to_le32(ns->params.max_open_zones - 1);
id_ns_z->zoc = 0;
@@ -421,6 +379,34 @@ static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns,
}
}
+ if (ns->params.zoned) {
+ if (ns->params.max_active_zones) {
+ if (ns->params.max_open_zones > ns->params.max_active_zones) {
+ error_setg(errp, "max_open_zones (%u) exceeds "
+ "max_active_zones (%u)", ns->params.max_open_zones,
+ ns->params.max_active_zones);
+ return -1;
+ }
+
+ if (!ns->params.max_open_zones) {
+ ns->params.max_open_zones = ns->params.max_active_zones;
+ }
+ }
+
+ if (ns->params.zd_extension_size) {
+ if (ns->params.zd_extension_size & 0x3f) {
+ error_setg(errp, "zone descriptor extension size must be a "
+ "multiple of 64B");
+ return -1;
+ }
+ if ((ns->params.zd_extension_size >> 6) > 0xff) {
+ error_setg(errp,
+ "zone descriptor extension size is too large");
+ return -1;
+ }
+ }
+ }
+
return 0;
}
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
new file mode 100644
index 0000000000..81a35cda14
--- /dev/null
+++ b/hw/nvme/nvme.h
@@ -0,0 +1,547 @@
+/*
+ * QEMU NVM Express
+ *
+ * Copyright (c) 2012 Intel Corporation
+ * Copyright (c) 2021 Minwoo Im
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Authors:
+ * Keith Busch <kbusch@kernel.org>
+ * Klaus Jensen <k.jensen@samsung.com>
+ * Gollu Appalanaidu <anaidu.gollu@samsung.com>
+ * Dmitry Fomichev <dmitry.fomichev@wdc.com>
+ * Minwoo Im <minwoo.im.dev@gmail.com>
+ *
+ * This code is licensed under the GNU GPL v2 or later.
+ */
+
+#ifndef HW_NVME_INTERNAL_H
+#define HW_NVME_INTERNAL_H
+
+#include "qemu/uuid.h"
+#include "hw/pci/pci.h"
+#include "hw/block/block.h"
+
+#include "block/nvme.h"
+
+#define NVME_MAX_CONTROLLERS 32
+#define NVME_MAX_NAMESPACES 256
+
+typedef struct NvmeCtrl NvmeCtrl;
+typedef struct NvmeNamespace NvmeNamespace;
+
+#define TYPE_NVME_SUBSYS "nvme-subsys"
+#define NVME_SUBSYS(obj) \
+ OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)
+
+typedef struct NvmeSubsystem {
+ DeviceState parent_obj;
+ uint8_t subnqn[256];
+
+ NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS];
+ NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
+
+ struct {
+ char *nqn;
+ } params;
+} NvmeSubsystem;
+
+int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp);
+
+static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
+ uint32_t cntlid)
+{
+ if (!subsys || cntlid >= NVME_MAX_CONTROLLERS) {
+ return NULL;
+ }
+
+ return subsys->ctrls[cntlid];
+}
+
+static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys,
+ uint32_t nsid)
+{
+ if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) {
+ return NULL;
+ }
+
+ return subsys->namespaces[nsid];
+}
+
+#define TYPE_NVME_NS "nvme-ns"
+#define NVME_NS(obj) \
+ OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
+
+typedef struct NvmeZone {
+ NvmeZoneDescr d;
+ uint64_t w_ptr;
+ QTAILQ_ENTRY(NvmeZone) entry;
+} NvmeZone;
+
+typedef struct NvmeNamespaceParams {
+ bool detached;
+ bool shared;
+ uint32_t nsid;
+ QemuUUID uuid;
+
+ uint16_t ms;
+ uint8_t mset;
+ uint8_t pi;
+ uint8_t pil;
+
+ uint16_t mssrl;
+ uint32_t mcl;
+ uint8_t msrc;
+
+ bool zoned;
+ bool cross_zone_read;
+ uint64_t zone_size_bs;
+ uint64_t zone_cap_bs;
+ uint32_t max_active_zones;
+ uint32_t max_open_zones;
+ uint32_t zd_extension_size;
+} NvmeNamespaceParams;
+
+typedef struct NvmeNamespace {
+ DeviceState parent_obj;
+ BlockConf blkconf;
+ int32_t bootindex;
+ int64_t size;
+ int64_t moff;
+ NvmeIdNs id_ns;
+ NvmeLBAF lbaf;
+ size_t lbasz;
+ const uint32_t *iocs;
+ uint8_t csi;
+ uint16_t status;
+ int attached;
+
+ QTAILQ_ENTRY(NvmeNamespace) entry;
+
+ NvmeIdNsZoned *id_ns_zoned;
+ NvmeZone *zone_array;
+ QTAILQ_HEAD(, NvmeZone) exp_open_zones;
+ QTAILQ_HEAD(, NvmeZone) imp_open_zones;
+ QTAILQ_HEAD(, NvmeZone) closed_zones;
+ QTAILQ_HEAD(, NvmeZone) full_zones;
+ uint32_t num_zones;
+ uint64_t zone_size;
+ uint64_t zone_capacity;
+ uint32_t zone_size_log2;
+ uint8_t *zd_extensions;
+ int32_t nr_open_zones;
+ int32_t nr_active_zones;
+
+ NvmeNamespaceParams params;
+
+ struct {
+ uint32_t err_rec;
+ } features;
+} NvmeNamespace;
+
+static inline uint32_t nvme_nsid(NvmeNamespace *ns)
+{
+ if (ns) {
+ return ns->params.nsid;
+ }
+
+ return 0;
+}
+
+static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
+{
+ return lba << ns->lbaf.ds;
+}
+
+static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
+{
+ return ns->lbaf.ms * lba;
+}
+
+static inline int64_t nvme_moff(NvmeNamespace *ns, uint64_t lba)
+{
+ return ns->moff + nvme_m2b(ns, lba);
+}
+
+static inline bool nvme_ns_ext(NvmeNamespace *ns)
+{
+ return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
+}
+
+static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
+{
+ return zone->d.zs >> 4;
+}
+
+static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
+{
+ zone->d.zs = state << 4;
+}
+
+static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
+{
+ return zone->d.zslba + ns->zone_size;
+}
+
+static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
+{
+ return zone->d.zslba + zone->d.zcap;
+}
+
+static inline bool nvme_wp_is_valid(NvmeZone *zone)
+{
+ uint8_t st = nvme_get_zone_state(zone);
+
+ return st != NVME_ZONE_STATE_FULL &&
+ st != NVME_ZONE_STATE_READ_ONLY &&
+ st != NVME_ZONE_STATE_OFFLINE;
+}
+
+static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
+ uint32_t zone_idx)
+{
+ return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
+}
+
+static inline void nvme_aor_inc_open(NvmeNamespace *ns)
+{
+ assert(ns->nr_open_zones >= 0);
+ if (ns->params.max_open_zones) {
+ ns->nr_open_zones++;
+ assert(ns->nr_open_zones <= ns->params.max_open_zones);
+ }
+}
+
+static inline void nvme_aor_dec_open(NvmeNamespace *ns)
+{
+ if (ns->params.max_open_zones) {
+ assert(ns->nr_open_zones > 0);
+ ns->nr_open_zones--;
+ }
+ assert(ns->nr_open_zones >= 0);
+}
+
+static inline void nvme_aor_inc_active(NvmeNamespace *ns)
+{
+ assert(ns->nr_active_zones >= 0);
+ if (ns->params.max_active_zones) {
+ ns->nr_active_zones++;
+ assert(ns->nr_active_zones <= ns->params.max_active_zones);
+ }
+}
+
+static inline void nvme_aor_dec_active(NvmeNamespace *ns)
+{
+ if (ns->params.max_active_zones) {
+ assert(ns->nr_active_zones > 0);
+ ns->nr_active_zones--;
+ assert(ns->nr_active_zones >= ns->nr_open_zones);
+ }
+ assert(ns->nr_active_zones >= 0);
+}
+
+void nvme_ns_init_format(NvmeNamespace *ns);
+int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
+void nvme_ns_drain(NvmeNamespace *ns);
+void nvme_ns_shutdown(NvmeNamespace *ns);
+void nvme_ns_cleanup(NvmeNamespace *ns);
+
+typedef struct NvmeAsyncEvent {
+ QTAILQ_ENTRY(NvmeAsyncEvent) entry;
+ NvmeAerResult result;
+} NvmeAsyncEvent;
+
+enum {
+ NVME_SG_ALLOC = 1 << 0,
+ NVME_SG_DMA = 1 << 1,
+};
+
+typedef struct NvmeSg {
+ int flags;
+
+ union {
+ QEMUSGList qsg;
+ QEMUIOVector iov;
+ };
+} NvmeSg;
+
+typedef enum NvmeTxDirection {
+ NVME_TX_DIRECTION_TO_DEVICE = 0,
+ NVME_TX_DIRECTION_FROM_DEVICE = 1,
+} NvmeTxDirection;
+
+typedef struct NvmeRequest {
+ struct NvmeSQueue *sq;
+ struct NvmeNamespace *ns;
+ BlockAIOCB *aiocb;
+ uint16_t status;
+ void *opaque;
+ NvmeCqe cqe;
+ NvmeCmd cmd;
+ BlockAcctCookie acct;
+ NvmeSg sg;
+ QTAILQ_ENTRY(NvmeRequest)entry;
+} NvmeRequest;
+
+typedef struct NvmeBounceContext {
+ NvmeRequest *req;
+
+ struct {
+ QEMUIOVector iov;
+ uint8_t *bounce;
+ } data, mdata;
+} NvmeBounceContext;
+
+static inline const char *nvme_adm_opc_str(uint8_t opc)
+{
+ switch (opc) {
+ case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ";
+ case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ";
+ case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE";
+ case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ";
+ case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ";
+ case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY";
+ case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT";
+ case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES";
+ case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES";
+ case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ";
+ case NVME_ADM_CMD_NS_ATTACHMENT: return "NVME_ADM_CMD_NS_ATTACHMENT";
+ case NVME_ADM_CMD_FORMAT_NVM: return "NVME_ADM_CMD_FORMAT_NVM";
+ default: return "NVME_ADM_CMD_UNKNOWN";
+ }
+}
+
+static inline const char *nvme_io_opc_str(uint8_t opc)
+{
+ switch (opc) {
+ case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH";
+ case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE";
+ case NVME_CMD_READ: return "NVME_NVM_CMD_READ";
+ case NVME_CMD_COMPARE: return "NVME_NVM_CMD_COMPARE";
+ case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES";
+ case NVME_CMD_DSM: return "NVME_NVM_CMD_DSM";
+ case NVME_CMD_VERIFY: return "NVME_NVM_CMD_VERIFY";
+ case NVME_CMD_COPY: return "NVME_NVM_CMD_COPY";
+ case NVME_CMD_ZONE_MGMT_SEND: return "NVME_ZONED_CMD_MGMT_SEND";
+ case NVME_CMD_ZONE_MGMT_RECV: return "NVME_ZONED_CMD_MGMT_RECV";
+ case NVME_CMD_ZONE_APPEND: return "NVME_ZONED_CMD_ZONE_APPEND";
+ default: return "NVME_NVM_CMD_UNKNOWN";
+ }
+}
+
+typedef struct NvmeSQueue {
+ struct NvmeCtrl *ctrl;
+ uint16_t sqid;
+ uint16_t cqid;
+ uint32_t head;
+ uint32_t tail;
+ uint32_t size;
+ uint64_t dma_addr;
+ QEMUTimer *timer;
+ NvmeRequest *io_req;
+ QTAILQ_HEAD(, NvmeRequest) req_list;
+ QTAILQ_HEAD(, NvmeRequest) out_req_list;
+ QTAILQ_ENTRY(NvmeSQueue) entry;
+} NvmeSQueue;
+
+typedef struct NvmeCQueue {
+ struct NvmeCtrl *ctrl;
+ uint8_t phase;
+ uint16_t cqid;
+ uint16_t irq_enabled;
+ uint32_t head;
+ uint32_t tail;
+ uint32_t vector;
+ uint32_t size;
+ uint64_t dma_addr;
+ QEMUTimer *timer;
+ QTAILQ_HEAD(, NvmeSQueue) sq_list;
+ QTAILQ_HEAD(, NvmeRequest) req_list;
+} NvmeCQueue;
+
+#define TYPE_NVME_BUS "nvme-bus"
+#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS)
+
+typedef struct NvmeBus {
+ BusState parent_bus;
+} NvmeBus;
+
+#define TYPE_NVME "nvme"
+#define NVME(obj) \
+ OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
+
+typedef struct NvmeParams {
+ char *serial;
+ uint32_t num_queues; /* deprecated since 5.1 */
+ uint32_t max_ioqpairs;
+ uint16_t msix_qsize;
+ uint32_t cmb_size_mb;
+ uint8_t aerl;
+ uint32_t aer_max_queued;
+ uint8_t mdts;
+ uint8_t vsl;
+ bool use_intel_id;
+ uint8_t zasl;
+ bool legacy_cmb;
+} NvmeParams;
+
+typedef struct NvmeCtrl {
+ PCIDevice parent_obj;
+ MemoryRegion bar0;
+ MemoryRegion iomem;
+ NvmeBar bar;
+ NvmeParams params;
+ NvmeBus bus;
+
+ uint16_t cntlid;
+ bool qs_created;
+ uint32_t page_size;
+ uint16_t page_bits;
+ uint16_t max_prp_ents;
+ uint16_t cqe_size;
+ uint16_t sqe_size;
+ uint32_t reg_size;
+ uint32_t max_q_ents;
+ uint8_t outstanding_aers;
+ uint32_t irq_status;
+ uint64_t host_timestamp; /* Timestamp sent by the host */
+ uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
+ uint64_t starttime_ms;
+ uint16_t temperature;
+ uint8_t smart_critical_warning;
+
+ struct {
+ MemoryRegion mem;
+ uint8_t *buf;
+ bool cmse;
+ hwaddr cba;
+ } cmb;
+
+ struct {
+ HostMemoryBackend *dev;
+ bool cmse;
+ hwaddr cba;
+ } pmr;
+
+ uint8_t aer_mask;
+ NvmeRequest **aer_reqs;
+ QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
+ int aer_queued;
+
+ uint32_t dmrsl;
+
+ /* Namespace ID is started with 1 so bitmap should be 1-based */
+#define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1)
+ DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE);
+
+ NvmeSubsystem *subsys;
+
+ NvmeNamespace namespace;
+ NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
+ NvmeSQueue **sq;
+ NvmeCQueue **cq;
+ NvmeSQueue admin_sq;
+ NvmeCQueue admin_cq;
+ NvmeIdCtrl id_ctrl;
+
+ struct {
+ struct {
+ uint16_t temp_thresh_hi;
+ uint16_t temp_thresh_low;
+ };
+ uint32_t async_config;
+ } features;
+} NvmeCtrl;
+
+static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
+{
+ if (!nsid || nsid > NVME_MAX_NAMESPACES) {
+ return NULL;
+ }
+
+ return n->namespaces[nsid];
+}
+
+static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
+{
+ NvmeSQueue *sq = req->sq;
+ NvmeCtrl *n = sq->ctrl;
+
+ return n->cq[sq->cqid];
+}
+
+static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req)
+{
+ NvmeSQueue *sq = req->sq;
+ return sq->ctrl;
+}
+
+static inline uint16_t nvme_cid(NvmeRequest *req)
+{
+ if (!req) {
+ return 0xffff;
+ }
+
+ return le16_to_cpu(req->cqe.cid);
+}
+
+void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns);
+uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
+ NvmeTxDirection dir, NvmeRequest *req);
+uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
+ NvmeTxDirection dir, NvmeRequest *req);
+void nvme_rw_complete_cb(void *opaque, int ret);
+uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len,
+ NvmeCmd *cmd);
+
+/* from Linux kernel (crypto/crct10dif_common.c) */
+static const uint16_t t10_dif_crc_table[256] = {
+ 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
+ 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
+ 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
+ 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
+ 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
+ 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
+ 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
+ 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
+ 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
+ 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
+ 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
+ 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
+ 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
+ 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
+ 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
+ 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
+ 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
+ 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
+ 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
+ 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
+ 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
+ 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
+ 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
+ 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
+ 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
+ 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
+ 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
+ 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
+ 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
+ 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
+ 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
+ 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
+};
+
+uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba,
+ uint32_t reftag);
+uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen,
+ uint64_t slba);
+void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len,
+ uint8_t *mbuf, size_t mlen, uint16_t apptag,
+ uint32_t reftag);
+uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len,
+ uint8_t *mbuf, size_t mlen, uint16_t ctrl,
+ uint64_t slba, uint16_t apptag,
+ uint16_t appmask, uint32_t reftag);
+uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req);
+
+
+#endif /* HW_NVME_INTERNAL_H */
diff --git a/hw/block/nvme-subsys.c b/hw/nvme/subsys.c
index 9604c19117..192223d17c 100644
--- a/hw/block/nvme-subsys.c
+++ b/hw/nvme/subsys.c
@@ -6,20 +6,10 @@
* This code is licensed under the GNU GPL v2. Refer COPYING.
*/
-#include "qemu/units.h"
#include "qemu/osdep.h"
-#include "qemu/uuid.h"
-#include "qemu/iov.h"
-#include "qemu/cutils.h"
#include "qapi/error.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-core.h"
-#include "hw/block/block.h"
-#include "block/aio.h"
-#include "block/accounting.h"
-#include "hw/pci/pci.h"
+
#include "nvme.h"
-#include "nvme-subsys.h"
int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp)
{
diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events
new file mode 100644
index 0000000000..ea33d0ccc3
--- /dev/null
+++ b/hw/nvme/trace-events
@@ -0,0 +1,204 @@
+# successful events
+pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
+pci_nvme_irq_pin(void) "pulsing IRQ pin"
+pci_nvme_irq_masked(void) "IRQ is masked"
+pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
+pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
+pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
+pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d"
+pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64""
+pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
+pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
+pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32""
+pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8""
+pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8""
+pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32""
+pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64""
+pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64""
+pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8""
+pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32""
+pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32""
+pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16""
+pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32""
+pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16""
+pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16""
+pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32""
+pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8""
+pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32""
+pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16""
+pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32""
+pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32""
+pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d"
+pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32""
+pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32""
+pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32""
+pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32""
+pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64""
+pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
+pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
+pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
+pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
+pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
+pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8""
+pci_nvme_identify_ctrl(void) "identify controller"
+pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8""
+pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16""
+pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8""
+pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8""
+pci_nvme_identify_cmd_set(void) "identify i/o command set"
+pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
+pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
+pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""
+pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
+pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
+pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
+pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
+pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
+pci_nvme_process_aers(int queued) "queued %d"
+pci_nvme_aer(uint16_t cid) "cid %"PRIu16""
+pci_nvme_aer_aerl_exceeded(void) "aerl exceeded"
+pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8""
+pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
+pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8""
+pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32""
+pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
+pci_nvme_enqueue_event_noqueue(int queued) "queued %d"
+pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8""
+pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs"
+pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
+pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d"
+pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d"
+pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16""
+pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16""
+pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
+pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
+pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
+pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64""
+pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64""
+pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64""
+pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
+pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64""
+pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded"
+pci_nvme_mmio_stopped(void) "cleared controller enable bit"
+pci_nvme_mmio_shutdown_set(void) "shutdown bit set"
+pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
+pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
+pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
+pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
+pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
+pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32""
+pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32""
+pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32""
+pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state"
+pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state"
+
+# error conditions
+pci_nvme_err_mdts(size_t len) "len %zu"
+pci_nvme_err_zasl(size_t len) "len %zu"
+pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8""
+pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64""
+pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64""
+pci_nvme_err_cfs(void) "controller fatal status"
+pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16""
+pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8""
+pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
+pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
+pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32""
+pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
+pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64""
+pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
+pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
+pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
+pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
+pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64""
+pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64""
+pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64""
+pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64""
+pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32""
+pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64""
+pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64""
+pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64""
+pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64""
+pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64""
+pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64""
+pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64""
+pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16""
+pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16""
+pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded"
+pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded"
+pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32""
+pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32""
+pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16""
+pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16""
+pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16""
+pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16""
+pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64""
+pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16""
+pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16""
+pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16""
+pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16""
+pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16""
+pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64""
+pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16""
+pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16""
+pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
+pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
+pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
+pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16""
+pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
+pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
+pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
+pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null"
+pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64""
+pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64""
+pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u"
+pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u"
+pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u"
+pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
+pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
+pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
+pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u"
+pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
+pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
+pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32""
+pci_nvme_err_startfail(void) "setting controller enable bit failed"
+pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8""
+
+# undefined behavior
+pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64""
+pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u"
+pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled"
+pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status"
+pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)"
+pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
+pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
+pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
+pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
+pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
+pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
+pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
+pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
+pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
+pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
+pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0"
+pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring"
+pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring"
+pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring"
+pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring"
+pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring"
+pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field"
diff --git a/hw/nvme/trace.h b/hw/nvme/trace.h
new file mode 100644
index 0000000000..b398ea107f
--- /dev/null
+++ b/hw/nvme/trace.h
@@ -0,0 +1 @@
+#include "trace/trace-hw_nvme.h"
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 34b3538beb..1698d3a192 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -3,7 +3,7 @@ pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c'))
pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: files('designware.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c'))
-pci_ss.add(when: 'CONFIG_ACPI', if_true: files('gpex-acpi.c'))
+pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], if_true: files('gpex-acpi.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_Q35', if_true: files('q35.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_XILINX', if_true: files('xilinx-pcie.c'))
pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c'))
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 86d6f379d1..597d974dd4 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -29,6 +29,9 @@ ppc_ss.add(when: 'CONFIG_PSERIES', if_true: files(
'spapr_numa.c',
'pef.c',
))
+ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_TCG'], if_true: files(
+ 'spapr_softmmu.c',
+))
ppc_ss.add(when: 'CONFIG_SPAPR_RNG', if_true: files('spapr_rng.c'))
ppc_ss.add(when: ['CONFIG_PSERIES', 'CONFIG_LINUX'], if_true: files(
'spapr_pci_vfio.c',
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index ffe01977cd..d16dd2d080 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -196,7 +196,7 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
- if (env->spr_cb[SPR_PURR].oea_read) {
+ if (ppc_has_spr(cpu, SPR_PURR)) {
_FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 8f40319aee..c23bcc4490 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -703,10 +703,10 @@ static void spapr_dt_cpu(CPUState *cs, void *fdt, int offset,
_FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
- if (env->spr_cb[SPR_PURR].oea_read) {
+ if (ppc_has_spr(cpu, SPR_PURR)) {
_FDT((fdt_setprop_cell(fdt, offset, "ibm,purr", 1)));
}
- if (env->spr_cb[SPR_SPURR].oea_read) {
+ if (ppc_has_spr(cpu, SPR_PURR)) {
_FDT((fdt_setprop_cell(fdt, offset, "ibm,spurr", 1)));
}
@@ -979,6 +979,7 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
*/
val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
val[3] = 0x00; /* Hash */
+ spapr_check_mmu_mode(false);
} else if (kvm_enabled()) {
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
val[3] = 0x80; /* OV5_MMU_BOTH */
@@ -1556,6 +1557,22 @@ void spapr_setup_hpt(SpaprMachineState *spapr)
}
}
+void spapr_check_mmu_mode(bool guest_radix)
+{
+ if (guest_radix) {
+ if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
+ error_report("Guest requested unavailable MMU mode (radix).");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
+ && !kvmppc_has_cap_mmu_hash_v3()) {
+ error_report("Guest requested unavailable MMU mode (hash).");
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
static void spapr_machine_reset(MachineState *machine)
{
SpaprMachineState *spapr = SPAPR_MACHINE(machine);
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 9ea7ddd1e9..d0c419b392 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -371,6 +371,65 @@ static bool spapr_pagesize_cb(void *opaque, uint32_t seg_pshift,
return true;
}
+static void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu,
+ bool (*cb)(void *, uint32_t, uint32_t),
+ void *opaque)
+{
+ PPCHash64Options *opts = cpu->hash64_opts;
+ int i;
+ int n = 0;
+ bool ci_largepage = false;
+
+ assert(opts);
+
+ n = 0;
+ for (i = 0; i < ARRAY_SIZE(opts->sps); i++) {
+ PPCHash64SegmentPageSizes *sps = &opts->sps[i];
+ int j;
+ int m = 0;
+
+ assert(n <= i);
+
+ if (!sps->page_shift) {
+ break;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(sps->enc); j++) {
+ PPCHash64PageSize *ps = &sps->enc[j];
+
+ assert(m <= j);
+ if (!ps->page_shift) {
+ break;
+ }
+
+ if (cb(opaque, sps->page_shift, ps->page_shift)) {
+ if (ps->page_shift >= 16) {
+ ci_largepage = true;
+ }
+ sps->enc[m++] = *ps;
+ }
+ }
+
+ /* Clear rest of the row */
+ for (j = m; j < ARRAY_SIZE(sps->enc); j++) {
+ memset(&sps->enc[j], 0, sizeof(sps->enc[j]));
+ }
+
+ if (m) {
+ n++;
+ }
+ }
+
+ /* Clear the rest of the table */
+ for (i = n; i < ARRAY_SIZE(opts->sps); i++) {
+ memset(&opts->sps[i], 0, sizeof(opts->sps[i]));
+ }
+
+ if (!ci_largepage) {
+ opts->flags &= ~PPC_HASH64_CI_LARGEPAGE;
+ }
+}
+
static void cap_hpt_maxpagesize_cpu_apply(SpaprMachineState *spapr,
PowerPCCPU *cpu,
uint8_t val, Error **errp)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 16c719c3de..f25014afda 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -20,24 +20,7 @@
#include "mmu-book3s-v3.h"
#include "hw/mem/memory-device.h"
-static bool has_spr(PowerPCCPU *cpu, int spr)
-{
- /* We can test whether the SPR is defined by checking for a valid name */
- return cpu->env.spr_cb[spr].name != NULL;
-}
-
-static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
-{
- /*
- * hash value/pteg group index is normalized by HPT mask
- */
- if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
- return false;
- }
- return true;
-}
-
-static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
+bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
{
MachineState *machine = MACHINE(spapr);
DeviceMemoryState *dms = machine->device_memory;
@@ -53,355 +36,6 @@ static bool is_ram_address(SpaprMachineState *spapr, hwaddr addr)
return false;
}
-static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong flags = args[0];
- target_ulong ptex = args[1];
- target_ulong pteh = args[2];
- target_ulong ptel = args[3];
- unsigned apshift;
- target_ulong raddr;
- target_ulong slot;
- const ppc_hash_pte64_t *hptes;
-
- apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
- if (!apshift) {
- /* Bad page size encoding */
- return H_PARAMETER;
- }
-
- raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
-
- if (is_ram_address(spapr, raddr)) {
- /* Regular RAM - should have WIMG=0010 */
- if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
- return H_PARAMETER;
- }
- } else {
- target_ulong wimg_flags;
- /* Looks like an IO address */
- /* FIXME: What WIMG combinations could be sensible for IO?
- * For now we allow WIMG=010x, but are there others? */
- /* FIXME: Should we check against registered IO addresses? */
- wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
-
- if (wimg_flags != HPTE64_R_I &&
- wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
- return H_PARAMETER;
- }
- }
-
- pteh &= ~0x60ULL;
-
- if (!valid_ptex(cpu, ptex)) {
- return H_PARAMETER;
- }
-
- slot = ptex & 7ULL;
- ptex = ptex & ~7ULL;
-
- if (likely((flags & H_EXACT) == 0)) {
- hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
- for (slot = 0; slot < 8; slot++) {
- if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
- break;
- }
- }
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
- if (slot == 8) {
- return H_PTEG_FULL;
- }
- } else {
- hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
- if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
- ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
- return H_PTEG_FULL;
- }
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
- }
-
- spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
-
- args[0] = ptex + slot;
- return H_SUCCESS;
-}
-
-typedef enum {
- REMOVE_SUCCESS = 0,
- REMOVE_NOT_FOUND = 1,
- REMOVE_PARM = 2,
- REMOVE_HW = 3,
-} RemoveResult;
-
-static RemoveResult remove_hpte(PowerPCCPU *cpu
- , target_ulong ptex,
- target_ulong avpn,
- target_ulong flags,
- target_ulong *vp, target_ulong *rp)
-{
- const ppc_hash_pte64_t *hptes;
- target_ulong v, r;
-
- if (!valid_ptex(cpu, ptex)) {
- return REMOVE_PARM;
- }
-
- hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
- v = ppc_hash64_hpte0(cpu, hptes, 0);
- r = ppc_hash64_hpte1(cpu, hptes, 0);
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
-
- if ((v & HPTE64_V_VALID) == 0 ||
- ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
- ((flags & H_ANDCOND) && (v & avpn) != 0)) {
- return REMOVE_NOT_FOUND;
- }
- *vp = v;
- *rp = r;
- spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
- ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
- return REMOVE_SUCCESS;
-}
-
-static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong flags = args[0];
- target_ulong ptex = args[1];
- target_ulong avpn = args[2];
- RemoveResult ret;
-
- ret = remove_hpte(cpu, ptex, avpn, flags,
- &args[0], &args[1]);
-
- switch (ret) {
- case REMOVE_SUCCESS:
- check_tlb_flush(env, true);
- return H_SUCCESS;
-
- case REMOVE_NOT_FOUND:
- return H_NOT_FOUND;
-
- case REMOVE_PARM:
- return H_PARAMETER;
-
- case REMOVE_HW:
- return H_HARDWARE;
- }
-
- g_assert_not_reached();
-}
-
-#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL
-#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL
-#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL
-#define H_BULK_REMOVE_END 0xc000000000000000ULL
-#define H_BULK_REMOVE_CODE 0x3000000000000000ULL
-#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL
-#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL
-#define H_BULK_REMOVE_PARM 0x2000000000000000ULL
-#define H_BULK_REMOVE_HW 0x3000000000000000ULL
-#define H_BULK_REMOVE_RC 0x0c00000000000000ULL
-#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL
-#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL
-#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL
-#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL
-#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL
-
-#define H_BULK_REMOVE_MAX_BATCH 4
-
-static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- int i;
- target_ulong rc = H_SUCCESS;
-
- for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
- target_ulong *tsh = &args[i*2];
- target_ulong tsl = args[i*2 + 1];
- target_ulong v, r, ret;
-
- if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
- break;
- } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
- return H_PARAMETER;
- }
-
- *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
- *tsh |= H_BULK_REMOVE_RESPONSE;
-
- if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
- *tsh |= H_BULK_REMOVE_PARM;
- return H_PARAMETER;
- }
-
- ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
- (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
- &v, &r);
-
- *tsh |= ret << 60;
-
- switch (ret) {
- case REMOVE_SUCCESS:
- *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
- break;
-
- case REMOVE_PARM:
- rc = H_PARAMETER;
- goto exit;
-
- case REMOVE_HW:
- rc = H_HARDWARE;
- goto exit;
- }
- }
- exit:
- check_tlb_flush(env, true);
-
- return rc;
-}
-
-static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- CPUPPCState *env = &cpu->env;
- target_ulong flags = args[0];
- target_ulong ptex = args[1];
- target_ulong avpn = args[2];
- const ppc_hash_pte64_t *hptes;
- target_ulong v, r;
-
- if (!valid_ptex(cpu, ptex)) {
- return H_PARAMETER;
- }
-
- hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
- v = ppc_hash64_hpte0(cpu, hptes, 0);
- r = ppc_hash64_hpte1(cpu, hptes, 0);
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
-
- if ((v & HPTE64_V_VALID) == 0 ||
- ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
- return H_NOT_FOUND;
- }
-
- r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
- HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
- r |= (flags << 55) & HPTE64_R_PP0;
- r |= (flags << 48) & HPTE64_R_KEY_HI;
- r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
- spapr_store_hpte(cpu, ptex,
- (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
- ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
- /* Flush the tlb */
- check_tlb_flush(env, true);
- /* Don't need a memory barrier, due to qemu's global lock */
- spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
- return H_SUCCESS;
-}
-
-static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong flags = args[0];
- target_ulong ptex = args[1];
- int i, ridx, n_entries = 1;
- const ppc_hash_pte64_t *hptes;
-
- if (!valid_ptex(cpu, ptex)) {
- return H_PARAMETER;
- }
-
- if (flags & H_READ_4) {
- /* Clear the two low order bits */
- ptex &= ~(3ULL);
- n_entries = 4;
- }
-
- hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
- for (i = 0, ridx = 0; i < n_entries; i++) {
- args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
- args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
- }
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
-
- return H_SUCCESS;
-}
-
-struct SpaprPendingHpt {
- /* These fields are read-only after initialization */
- int shift;
- QemuThread thread;
-
- /* These fields are protected by the BQL */
- bool complete;
-
- /* These fields are private to the preparation thread if
- * !complete, otherwise protected by the BQL */
- int ret;
- void *hpt;
-};
-
-static void free_pending_hpt(SpaprPendingHpt *pending)
-{
- if (pending->hpt) {
- qemu_vfree(pending->hpt);
- }
-
- g_free(pending);
-}
-
-static void *hpt_prepare_thread(void *opaque)
-{
- SpaprPendingHpt *pending = opaque;
- size_t size = 1ULL << pending->shift;
-
- pending->hpt = qemu_try_memalign(size, size);
- if (pending->hpt) {
- memset(pending->hpt, 0, size);
- pending->ret = H_SUCCESS;
- } else {
- pending->ret = H_NO_MEM;
- }
-
- qemu_mutex_lock_iothread();
-
- if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) {
- /* Ready to go */
- pending->complete = true;
- } else {
- /* We've been cancelled, clean ourselves up */
- free_pending_hpt(pending);
- }
-
- qemu_mutex_unlock_iothread();
- return NULL;
-}
-
-/* Must be called with BQL held */
-static void cancel_hpt_prepare(SpaprMachineState *spapr)
-{
- SpaprPendingHpt *pending = spapr->pending_hpt;
-
- /* Let the thread know it's cancelled */
- spapr->pending_hpt = NULL;
-
- if (!pending) {
- /* Nothing to do */
- return;
- }
-
- if (!pending->complete) {
- /* thread will clean itself up */
- return;
- }
-
- free_pending_hpt(pending);
-}
-
/* Convert a return code from the KVM ioctl()s implementing resize HPT
* into a PAPR hypercall return code */
static target_ulong resize_hpt_convert_rc(int ret)
@@ -447,7 +81,6 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
{
target_ulong flags = args[0];
int shift = args[1];
- SpaprPendingHpt *pending = spapr->pending_hpt;
uint64_t current_ram_size;
int rc;
@@ -484,182 +117,11 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
return resize_hpt_convert_rc(rc);
}
- if (pending) {
- /* something already in progress */
- if (pending->shift == shift) {
- /* and it's suitable */
- if (pending->complete) {
- return pending->ret;
- } else {
- return H_LONG_BUSY_ORDER_100_MSEC;
- }
- }
-
- /* not suitable, cancel and replace */
- cancel_hpt_prepare(spapr);
- }
-
- if (!shift) {
- /* nothing to do */
- return H_SUCCESS;
- }
-
- /* start new prepare */
-
- pending = g_new0(SpaprPendingHpt, 1);
- pending->shift = shift;
- pending->ret = H_HARDWARE;
-
- qemu_thread_create(&pending->thread, "sPAPR HPT prepare",
- hpt_prepare_thread, pending, QEMU_THREAD_DETACHED);
-
- spapr->pending_hpt = pending;
-
- /* In theory we could estimate the time more accurately based on
- * the new size, but there's not much point */
- return H_LONG_BUSY_ORDER_100_MSEC;
-}
-
-static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot)
-{
- uint8_t *addr = htab;
-
- addr += pteg * HASH_PTEG_SIZE_64;
- addr += slot * HASH_PTE_SIZE_64;
- return ldq_p(addr);
-}
-
-static void new_hpte_store(void *htab, uint64_t pteg, int slot,
- uint64_t pte0, uint64_t pte1)
-{
- uint8_t *addr = htab;
-
- addr += pteg * HASH_PTEG_SIZE_64;
- addr += slot * HASH_PTE_SIZE_64;
-
- stq_p(addr, pte0);
- stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1);
-}
-
-static int rehash_hpte(PowerPCCPU *cpu,
- const ppc_hash_pte64_t *hptes,
- void *old_hpt, uint64_t oldsize,
- void *new_hpt, uint64_t newsize,
- uint64_t pteg, int slot)
-{
- uint64_t old_hash_mask = (oldsize >> 7) - 1;
- uint64_t new_hash_mask = (newsize >> 7) - 1;
- target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot);
- target_ulong pte1;
- uint64_t avpn;
- unsigned base_pg_shift;
- uint64_t hash, new_pteg, replace_pte0;
-
- if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) {
- return H_SUCCESS;
- }
-
- pte1 = ppc_hash64_hpte1(cpu, hptes, slot);
-
- base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1);
- assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */
- avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23);
-
- if (pte0 & HPTE64_V_SECONDARY) {
- pteg = ~pteg;
- }
-
- if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) {
- uint64_t offset, vsid;
-
- /* We only have 28 - 23 bits of offset in avpn */
- offset = (avpn & 0x1f) << 23;
- vsid = avpn >> 5;
- /* We can find more bits from the pteg value */
- if (base_pg_shift < 23) {
- offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift;
- }
-
- hash = vsid ^ (offset >> base_pg_shift);
- } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) {
- uint64_t offset, vsid;
-
- /* We only have 40 - 23 bits of seg_off in avpn */
- offset = (avpn & 0x1ffff) << 23;
- vsid = avpn >> 17;
- if (base_pg_shift < 23) {
- offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask)
- << base_pg_shift;
- }
-
- hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift);
- } else {
- error_report("rehash_pte: Bad segment size in HPTE");
+ if (kvm_enabled()) {
return H_HARDWARE;
}
- new_pteg = hash & new_hash_mask;
- if (pte0 & HPTE64_V_SECONDARY) {
- assert(~pteg == (hash & old_hash_mask));
- new_pteg = ~new_pteg;
- } else {
- assert(pteg == (hash & old_hash_mask));
- }
- assert((oldsize != newsize) || (pteg == new_pteg));
- replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot);
- /*
- * Strictly speaking, we don't need all these tests, since we only
- * ever rehash bolted HPTEs. We might in future handle non-bolted
- * HPTEs, though so make the logic correct for those cases as
- * well.
- */
- if (replace_pte0 & HPTE64_V_VALID) {
- assert(newsize < oldsize);
- if (replace_pte0 & HPTE64_V_BOLTED) {
- if (pte0 & HPTE64_V_BOLTED) {
- /* Bolted collision, nothing we can do */
- return H_PTEG_FULL;
- } else {
- /* Discard this hpte */
- return H_SUCCESS;
- }
- }
- }
-
- new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1);
- return H_SUCCESS;
-}
-
-static int rehash_hpt(PowerPCCPU *cpu,
- void *old_hpt, uint64_t oldsize,
- void *new_hpt, uint64_t newsize)
-{
- uint64_t n_ptegs = oldsize >> 7;
- uint64_t pteg;
- int slot;
- int rc;
-
- for (pteg = 0; pteg < n_ptegs; pteg++) {
- hwaddr ptex = pteg * HPTES_PER_GROUP;
- const ppc_hash_pte64_t *hptes
- = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
-
- if (!hptes) {
- return H_HARDWARE;
- }
-
- for (slot = 0; slot < HPTES_PER_GROUP; slot++) {
- rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize,
- pteg, slot);
- if (rc != H_SUCCESS) {
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
- return rc;
- }
- }
- ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
- }
-
- return H_SUCCESS;
+ return softmmu_resize_hpt_prepare(cpu, spapr, shift);
}
static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data)
@@ -675,7 +137,7 @@ static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data)
}
}
-static void push_sregs_to_kvm_pr(SpaprMachineState *spapr)
+void push_sregs_to_kvm_pr(SpaprMachineState *spapr)
{
CPUState *cs;
@@ -700,9 +162,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
{
target_ulong flags = args[0];
target_ulong shift = args[1];
- SpaprPendingHpt *pending = spapr->pending_hpt;
int rc;
- size_t newsize;
if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
return H_AUTHORITY;
@@ -725,42 +185,14 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
return rc;
}
- if (flags != 0) {
- return H_PARAMETER;
- }
-
- if (!pending || (pending->shift != shift)) {
- /* no matching prepare */
- return H_CLOSED;
- }
-
- if (!pending->complete) {
- /* prepare has not completed */
- return H_BUSY;
+ if (kvm_enabled()) {
+ return H_HARDWARE;
}
- /* Shouldn't have got past PREPARE without an HPT */
- g_assert(spapr->htab_shift);
-
- newsize = 1ULL << pending->shift;
- rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr),
- pending->hpt, newsize);
- if (rc == H_SUCCESS) {
- qemu_vfree(spapr->htab);
- spapr->htab = pending->hpt;
- spapr->htab_shift = pending->shift;
-
- push_sregs_to_kvm_pr(spapr);
-
- pending->hpt = NULL; /* so it's not free()d */
- }
+ return softmmu_resize_hpt_commit(cpu, spapr, flags, shift);
+}
- /* Clean up */
- spapr->pending_hpt = NULL;
- free_pending_hpt(pending);
- return rc;
-}
static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
@@ -774,12 +206,12 @@ static target_ulong h_set_sprg0(PowerPCCPU *cpu, SpaprMachineState *spapr,
static target_ulong h_set_dabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
- if (!has_spr(cpu, SPR_DABR)) {
+ if (!ppc_has_spr(cpu, SPR_DABR)) {
return H_HARDWARE; /* DABR register not available */
}
cpu_synchronize_state(CPU(cpu));
- if (has_spr(cpu, SPR_DABRX)) {
+ if (ppc_has_spr(cpu, SPR_DABRX)) {
cpu->env.spr[SPR_DABRX] = 0x3; /* Use Problem and Privileged state */
} else if (!(args[0] & 0x4)) { /* Breakpoint Translation set? */
return H_RESERVED_DABR;
@@ -794,7 +226,7 @@ static target_ulong h_set_xdabr(PowerPCCPU *cpu, SpaprMachineState *spapr,
{
target_ulong dabrx = args[1];
- if (!has_spr(cpu, SPR_DABR) || !has_spr(cpu, SPR_DABRX)) {
+ if (!ppc_has_spr(cpu, SPR_DABR) || !ppc_has_spr(cpu, SPR_DABRX)) {
return H_HARDWARE;
}
@@ -1760,18 +1192,8 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu,
spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest);
spapr_ovec_cleanup(ov5_guest);
- if (guest_radix) {
- if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
- error_report("Guest requested unavailable MMU mode (radix).");
- exit(EXIT_FAILURE);
- }
- } else {
- if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
- && !kvmppc_has_cap_mmu_hash_v3()) {
- error_report("Guest requested unavailable MMU mode (hash).");
- exit(EXIT_FAILURE);
- }
- }
+ spapr_check_mmu_mode(guest_radix);
+
spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00);
spapr_ovec_cleanup(ov1_guest);
@@ -2023,16 +1445,34 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
return H_FUNCTION;
}
-static void hypercall_register_types(void)
+#ifndef CONFIG_TCG
+static target_ulong h_softmmu(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ g_assert_not_reached();
+}
+
+static void hypercall_register_softmmu(void)
{
/* hcall-pft */
- spapr_register_hypercall(H_ENTER, h_enter);
- spapr_register_hypercall(H_REMOVE, h_remove);
- spapr_register_hypercall(H_PROTECT, h_protect);
- spapr_register_hypercall(H_READ, h_read);
+ spapr_register_hypercall(H_ENTER, h_softmmu);
+ spapr_register_hypercall(H_REMOVE, h_softmmu);
+ spapr_register_hypercall(H_PROTECT, h_softmmu);
+ spapr_register_hypercall(H_READ, h_softmmu);
/* hcall-bulk */
- spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+ spapr_register_hypercall(H_BULK_REMOVE, h_softmmu);
+}
+#else
+static void hypercall_register_softmmu(void)
+{
+ /* DO NOTHING */
+}
+#endif
+
+static void hypercall_register_types(void)
+{
+ hypercall_register_softmmu();
/* hcall-hpt-resize */
spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare);
diff --git a/hw/ppc/spapr_softmmu.c b/hw/ppc/spapr_softmmu.c
new file mode 100644
index 0000000000..6c6b86dd3c
--- /dev/null
+++ b/hw/ppc/spapr_softmmu.c
@@ -0,0 +1,627 @@
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/runstate.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "helper_regs.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_cpu_core.h"
+#include "mmu-hash64.h"
+#include "cpu-models.h"
+#include "trace.h"
+#include "kvm_ppc.h"
+#include "hw/ppc/fdt.h"
+#include "hw/ppc/spapr_ovec.h"
+#include "mmu-book3s-v3.h"
+#include "hw/mem/memory-device.h"
+
+static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
+{
+ /*
+ * hash value/pteg group index is normalized by HPT mask
+ */
+ if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) {
+ return false;
+ }
+ return true;
+}
+
+static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong ptex = args[1];
+ target_ulong pteh = args[2];
+ target_ulong ptel = args[3];
+ unsigned apshift;
+ target_ulong raddr;
+ target_ulong slot;
+ const ppc_hash_pte64_t *hptes;
+
+ apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
+ if (!apshift) {
+ /* Bad page size encoding */
+ return H_PARAMETER;
+ }
+
+ raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
+
+ if (is_ram_address(spapr, raddr)) {
+ /* Regular RAM - should have WIMG=0010 */
+ if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
+ return H_PARAMETER;
+ }
+ } else {
+ target_ulong wimg_flags;
+ /* Looks like an IO address */
+ /* FIXME: What WIMG combinations could be sensible for IO?
+ * For now we allow WIMG=010x, but are there others? */
+ /* FIXME: Should we check against registered IO addresses? */
+ wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
+
+ if (wimg_flags != HPTE64_R_I &&
+ wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
+ return H_PARAMETER;
+ }
+ }
+
+ pteh &= ~0x60ULL;
+
+ if (!valid_ptex(cpu, ptex)) {
+ return H_PARAMETER;
+ }
+
+ slot = ptex & 7ULL;
+ ptex = ptex & ~7ULL;
+
+ if (likely((flags & H_EXACT) == 0)) {
+ hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+ for (slot = 0; slot < 8; slot++) {
+ if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
+ break;
+ }
+ }
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ if (slot == 8) {
+ return H_PTEG_FULL;
+ }
+ } else {
+ hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
+ if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
+ return H_PTEG_FULL;
+ }
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
+ }
+
+ spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
+
+ args[0] = ptex + slot;
+ return H_SUCCESS;
+}
+
+typedef enum {
+ REMOVE_SUCCESS = 0,
+ REMOVE_NOT_FOUND = 1,
+ REMOVE_PARM = 2,
+ REMOVE_HW = 3,
+} RemoveResult;
+
+static RemoveResult remove_hpte(PowerPCCPU *cpu
+ , target_ulong ptex,
+ target_ulong avpn,
+ target_ulong flags,
+ target_ulong *vp, target_ulong *rp)
+{
+ const ppc_hash_pte64_t *hptes;
+ target_ulong v, r;
+
+ if (!valid_ptex(cpu, ptex)) {
+ return REMOVE_PARM;
+ }
+
+ hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+ v = ppc_hash64_hpte0(cpu, hptes, 0);
+ r = ppc_hash64_hpte1(cpu, hptes, 0);
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
+
+ if ((v & HPTE64_V_VALID) == 0 ||
+ ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
+ ((flags & H_ANDCOND) && (v & avpn) != 0)) {
+ return REMOVE_NOT_FOUND;
+ }
+ *vp = v;
+ *rp = r;
+ spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
+ ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
+ return REMOVE_SUCCESS;
+}
+
+static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong flags = args[0];
+ target_ulong ptex = args[1];
+ target_ulong avpn = args[2];
+ RemoveResult ret;
+
+ ret = remove_hpte(cpu, ptex, avpn, flags,
+ &args[0], &args[1]);
+
+ switch (ret) {
+ case REMOVE_SUCCESS:
+ check_tlb_flush(env, true);
+ return H_SUCCESS;
+
+ case REMOVE_NOT_FOUND:
+ return H_NOT_FOUND;
+
+ case REMOVE_PARM:
+ return H_PARAMETER;
+
+ case REMOVE_HW:
+ return H_HARDWARE;
+ }
+
+ g_assert_not_reached();
+}
+
+#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL
+#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL
+#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL
+#define H_BULK_REMOVE_END 0xc000000000000000ULL
+#define H_BULK_REMOVE_CODE 0x3000000000000000ULL
+#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL
+#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL
+#define H_BULK_REMOVE_PARM 0x2000000000000000ULL
+#define H_BULK_REMOVE_HW 0x3000000000000000ULL
+#define H_BULK_REMOVE_RC 0x0c00000000000000ULL
+#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL
+#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL
+#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL
+#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL
+#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL
+
+#define H_BULK_REMOVE_MAX_BATCH 4
+
+static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUPPCState *env = &cpu->env;
+ int i;
+ target_ulong rc = H_SUCCESS;
+
+ for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
+ target_ulong *tsh = &args[i*2];
+ target_ulong tsl = args[i*2 + 1];
+ target_ulong v, r, ret;
+
+ if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
+ break;
+ } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
+ return H_PARAMETER;
+ }
+
+ *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
+ *tsh |= H_BULK_REMOVE_RESPONSE;
+
+ if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
+ *tsh |= H_BULK_REMOVE_PARM;
+ return H_PARAMETER;
+ }
+
+ ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
+ (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
+ &v, &r);
+
+ *tsh |= ret << 60;
+
+ switch (ret) {
+ case REMOVE_SUCCESS:
+ *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
+ break;
+
+ case REMOVE_PARM:
+ rc = H_PARAMETER;
+ goto exit;
+
+ case REMOVE_HW:
+ rc = H_HARDWARE;
+ goto exit;
+ }
+ }
+ exit:
+ check_tlb_flush(env, true);
+
+ return rc;
+}
+
+static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUPPCState *env = &cpu->env;
+ target_ulong flags = args[0];
+ target_ulong ptex = args[1];
+ target_ulong avpn = args[2];
+ const ppc_hash_pte64_t *hptes;
+ target_ulong v, r;
+
+ if (!valid_ptex(cpu, ptex)) {
+ return H_PARAMETER;
+ }
+
+ hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
+ v = ppc_hash64_hpte0(cpu, hptes, 0);
+ r = ppc_hash64_hpte1(cpu, hptes, 0);
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
+
+ if ((v & HPTE64_V_VALID) == 0 ||
+ ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
+ return H_NOT_FOUND;
+ }
+
+ r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
+ HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
+ r |= (flags << 55) & HPTE64_R_PP0;
+ r |= (flags << 48) & HPTE64_R_KEY_HI;
+ r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
+ spapr_store_hpte(cpu, ptex,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
+ ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
+ /* Flush the tlb */
+ check_tlb_flush(env, true);
+ /* Don't need a memory barrier, due to qemu's global lock */
+ spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
+ return H_SUCCESS;
+}
+
+static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong ptex = args[1];
+ int i, ridx, n_entries = 1;
+ const ppc_hash_pte64_t *hptes;
+
+ if (!valid_ptex(cpu, ptex)) {
+ return H_PARAMETER;
+ }
+
+ if (flags & H_READ_4) {
+ /* Clear the two low order bits */
+ ptex &= ~(3ULL);
+ n_entries = 4;
+ }
+
+ hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
+ for (i = 0, ridx = 0; i < n_entries; i++) {
+ args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
+ args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
+ }
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
+
+ return H_SUCCESS;
+}
+
+struct SpaprPendingHpt {
+ /* These fields are read-only after initialization */
+ int shift;
+ QemuThread thread;
+
+ /* These fields are protected by the BQL */
+ bool complete;
+
+ /* These fields are private to the preparation thread if
+ * !complete, otherwise protected by the BQL */
+ int ret;
+ void *hpt;
+};
+
+static void free_pending_hpt(SpaprPendingHpt *pending)
+{
+ if (pending->hpt) {
+ qemu_vfree(pending->hpt);
+ }
+
+ g_free(pending);
+}
+
+static void *hpt_prepare_thread(void *opaque)
+{
+ SpaprPendingHpt *pending = opaque;
+ size_t size = 1ULL << pending->shift;
+
+ pending->hpt = qemu_try_memalign(size, size);
+ if (pending->hpt) {
+ memset(pending->hpt, 0, size);
+ pending->ret = H_SUCCESS;
+ } else {
+ pending->ret = H_NO_MEM;
+ }
+
+ qemu_mutex_lock_iothread();
+
+ if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) {
+ /* Ready to go */
+ pending->complete = true;
+ } else {
+ /* We've been cancelled, clean ourselves up */
+ free_pending_hpt(pending);
+ }
+
+ qemu_mutex_unlock_iothread();
+ return NULL;
+}
+
+/* Must be called with BQL held */
+static void cancel_hpt_prepare(SpaprMachineState *spapr)
+{
+ SpaprPendingHpt *pending = spapr->pending_hpt;
+
+ /* Let the thread know it's cancelled */
+ spapr->pending_hpt = NULL;
+
+ if (!pending) {
+ /* Nothing to do */
+ return;
+ }
+
+ if (!pending->complete) {
+ /* thread will clean itself up */
+ return;
+ }
+
+ free_pending_hpt(pending);
+}
+
+target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong shift)
+{
+ SpaprPendingHpt *pending = spapr->pending_hpt;
+
+ if (pending) {
+ /* something already in progress */
+ if (pending->shift == shift) {
+ /* and it's suitable */
+ if (pending->complete) {
+ return pending->ret;
+ } else {
+ return H_LONG_BUSY_ORDER_100_MSEC;
+ }
+ }
+
+ /* not suitable, cancel and replace */
+ cancel_hpt_prepare(spapr);
+ }
+
+ if (!shift) {
+ /* nothing to do */
+ return H_SUCCESS;
+ }
+
+ /* start new prepare */
+
+ pending = g_new0(SpaprPendingHpt, 1);
+ pending->shift = shift;
+ pending->ret = H_HARDWARE;
+
+ qemu_thread_create(&pending->thread, "sPAPR HPT prepare",
+ hpt_prepare_thread, pending, QEMU_THREAD_DETACHED);
+
+ spapr->pending_hpt = pending;
+
+ /* In theory we could estimate the time more accurately based on
+ * the new size, but there's not much point */
+ return H_LONG_BUSY_ORDER_100_MSEC;
+}
+
+static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot)
+{
+ uint8_t *addr = htab;
+
+ addr += pteg * HASH_PTEG_SIZE_64;
+ addr += slot * HASH_PTE_SIZE_64;
+ return ldq_p(addr);
+}
+
+static void new_hpte_store(void *htab, uint64_t pteg, int slot,
+ uint64_t pte0, uint64_t pte1)
+{
+ uint8_t *addr = htab;
+
+ addr += pteg * HASH_PTEG_SIZE_64;
+ addr += slot * HASH_PTE_SIZE_64;
+
+ stq_p(addr, pte0);
+ stq_p(addr + HASH_PTE_SIZE_64 / 2, pte1);
+}
+
+static int rehash_hpte(PowerPCCPU *cpu,
+ const ppc_hash_pte64_t *hptes,
+ void *old_hpt, uint64_t oldsize,
+ void *new_hpt, uint64_t newsize,
+ uint64_t pteg, int slot)
+{
+ uint64_t old_hash_mask = (oldsize >> 7) - 1;
+ uint64_t new_hash_mask = (newsize >> 7) - 1;
+ target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot);
+ target_ulong pte1;
+ uint64_t avpn;
+ unsigned base_pg_shift;
+ uint64_t hash, new_pteg, replace_pte0;
+
+ if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) {
+ return H_SUCCESS;
+ }
+
+ pte1 = ppc_hash64_hpte1(cpu, hptes, slot);
+
+ base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1);
+ assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */
+ avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23);
+
+ if (pte0 & HPTE64_V_SECONDARY) {
+ pteg = ~pteg;
+ }
+
+ if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) {
+ uint64_t offset, vsid;
+
+ /* We only have 28 - 23 bits of offset in avpn */
+ offset = (avpn & 0x1f) << 23;
+ vsid = avpn >> 5;
+ /* We can find more bits from the pteg value */
+ if (base_pg_shift < 23) {
+ offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift;
+ }
+
+ hash = vsid ^ (offset >> base_pg_shift);
+ } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) {
+ uint64_t offset, vsid;
+
+ /* We only have 40 - 23 bits of seg_off in avpn */
+ offset = (avpn & 0x1ffff) << 23;
+ vsid = avpn >> 17;
+ if (base_pg_shift < 23) {
+ offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask)
+ << base_pg_shift;
+ }
+
+ hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift);
+ } else {
+ error_report("rehash_pte: Bad segment size in HPTE");
+ return H_HARDWARE;
+ }
+
+ new_pteg = hash & new_hash_mask;
+ if (pte0 & HPTE64_V_SECONDARY) {
+ assert(~pteg == (hash & old_hash_mask));
+ new_pteg = ~new_pteg;
+ } else {
+ assert(pteg == (hash & old_hash_mask));
+ }
+ assert((oldsize != newsize) || (pteg == new_pteg));
+ replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot);
+ /*
+ * Strictly speaking, we don't need all these tests, since we only
+ * ever rehash bolted HPTEs. We might in future handle non-bolted
+ * HPTEs, though so make the logic correct for those cases as
+ * well.
+ */
+ if (replace_pte0 & HPTE64_V_VALID) {
+ assert(newsize < oldsize);
+ if (replace_pte0 & HPTE64_V_BOLTED) {
+ if (pte0 & HPTE64_V_BOLTED) {
+ /* Bolted collision, nothing we can do */
+ return H_PTEG_FULL;
+ } else {
+ /* Discard this hpte */
+ return H_SUCCESS;
+ }
+ }
+ }
+
+ new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1);
+ return H_SUCCESS;
+}
+
+static int rehash_hpt(PowerPCCPU *cpu,
+ void *old_hpt, uint64_t oldsize,
+ void *new_hpt, uint64_t newsize)
+{
+ uint64_t n_ptegs = oldsize >> 7;
+ uint64_t pteg;
+ int slot;
+ int rc;
+
+ for (pteg = 0; pteg < n_ptegs; pteg++) {
+ hwaddr ptex = pteg * HPTES_PER_GROUP;
+ const ppc_hash_pte64_t *hptes
+ = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
+
+ if (!hptes) {
+ return H_HARDWARE;
+ }
+
+ for (slot = 0; slot < HPTES_PER_GROUP; slot++) {
+ rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize,
+ pteg, slot);
+ if (rc != H_SUCCESS) {
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ return rc;
+ }
+ }
+ ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
+ }
+
+ return H_SUCCESS;
+}
+
+target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong flags,
+ target_ulong shift)
+{
+ SpaprPendingHpt *pending = spapr->pending_hpt;
+ int rc;
+ size_t newsize;
+
+ if (flags != 0) {
+ return H_PARAMETER;
+ }
+
+ if (!pending || (pending->shift != shift)) {
+ /* no matching prepare */
+ return H_CLOSED;
+ }
+
+ if (!pending->complete) {
+ /* prepare has not completed */
+ return H_BUSY;
+ }
+
+ /* Shouldn't have got past PREPARE without an HPT */
+ g_assert(spapr->htab_shift);
+
+ newsize = 1ULL << pending->shift;
+ rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr),
+ pending->hpt, newsize);
+ if (rc == H_SUCCESS) {
+ qemu_vfree(spapr->htab);
+ spapr->htab = pending->hpt;
+ spapr->htab_shift = pending->shift;
+
+ push_sregs_to_kvm_pr(spapr);
+
+ pending->hpt = NULL; /* so it's not free()d */
+ }
+
+ /* Clean up */
+ spapr->pending_hpt = NULL;
+ free_pending_hpt(pending);
+
+ return rc;
+}
+
+static void hypercall_register_types(void)
+{
+ /* hcall-pft */
+ spapr_register_hypercall(H_ENTER, h_enter);
+ spapr_register_hypercall(H_REMOVE, h_remove);
+ spapr_register_hypercall(H_PROTECT, h_protect);
+ spapr_register_hypercall(H_READ, h_read);
+
+ /* hcall-bulk */
+ spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+
+}
+
+type_init(hypercall_register_types)
diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c
index 9ce31526e8..e67a5de72c 100644
--- a/hw/remote/mpqemu-link.c
+++ b/hw/remote/mpqemu-link.c
@@ -218,7 +218,7 @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
bool mpqemu_msg_valid(MPQemuMsg *msg)
{
- if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) {
+ if (msg->cmd >= MPQEMU_CMD_MAX || msg->cmd < 0) {
return false;
}
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 1de18cdcf1..86957ec7b0 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -19,9 +19,20 @@ config OPENTITAN
select IBEX
select UNIMP
+config SHAKTI
+ bool
+
+config SHAKTI_C
+ bool
+ select UNIMP
+ select SHAKTI
+ select SIFIVE_CLINT
+ select SIFIVE_PLIC
+
config RISCV_VIRT
bool
imply PCI_DEVICES
+ imply VIRTIO_VGA
imply TEST_DEVICES
select GOLDFISH_RTC
select MSI_NONBROKEN
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 275c0f7eb7..a97454661c 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -4,6 +4,7 @@ riscv_ss.add(files('numa.c'))
riscv_ss.add(files('riscv_hart.c'))
riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
+riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index dc9dea117e..7545dcda9c 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -119,7 +119,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
&error_abort);
object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
&error_abort);
- object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort);
+ object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort);
/* Boot ROM */
@@ -148,16 +148,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_DEV_UART].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
0, qdev_get_gpio_in(DEVICE(&s->plic),
- IBEX_UART_TX_WATERMARK_IRQ));
+ IBEX_UART0_TX_WATERMARK_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
1, qdev_get_gpio_in(DEVICE(&s->plic),
- IBEX_UART_RX_WATERMARK_IRQ));
+ IBEX_UART0_RX_WATERMARK_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
2, qdev_get_gpio_in(DEVICE(&s->plic),
- IBEX_UART_TX_EMPTY_IRQ));
+ IBEX_UART0_TX_EMPTY_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
3, qdev_get_gpio_in(DEVICE(&s->plic),
- IBEX_UART_RX_OVERFLOW_IRQ));
+ IBEX_UART0_RX_OVERFLOW_IRQ));
create_unimplemented_device("riscv.lowrisc.ibex.gpio",
memmap[IBEX_DEV_GPIO].base, memmap[IBEX_DEV_GPIO].size);
diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c
new file mode 100644
index 0000000000..18f70fadaa
--- /dev/null
+++ b/hw/riscv/shakti_c.c
@@ -0,0 +1,181 @@
+/*
+ * Shakti C-class SoC emulation
+ *
+ * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ * 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 "hw/boards.h"
+#include "hw/riscv/shakti_c.h"
+#include "qapi/error.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/intc/sifive_clint.h"
+#include "sysemu/sysemu.h"
+#include "hw/qdev-properties.h"
+#include "exec/address-spaces.h"
+#include "hw/riscv/boot.h"
+
+
+static const struct MemmapEntry {
+ hwaddr base;
+ hwaddr size;
+} shakti_c_memmap[] = {
+ [SHAKTI_C_ROM] = { 0x00001000, 0x2000 },
+ [SHAKTI_C_RAM] = { 0x80000000, 0x0 },
+ [SHAKTI_C_UART] = { 0x00011300, 0x00040 },
+ [SHAKTI_C_GPIO] = { 0x020d0000, 0x00100 },
+ [SHAKTI_C_PLIC] = { 0x0c000000, 0x20000 },
+ [SHAKTI_C_CLINT] = { 0x02000000, 0xc0000 },
+ [SHAKTI_C_I2C] = { 0x20c00000, 0x00100 },
+};
+
+static void shakti_c_machine_state_init(MachineState *mstate)
+{
+ ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+
+ /* Allow only Shakti C CPU for this platform */
+ if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_SHAKTI_C) != 0) {
+ error_report("This board can only be used with Shakti C CPU");
+ exit(1);
+ }
+
+ /* Initialize SoC */
+ object_initialize_child(OBJECT(mstate), "soc", &sms->soc,
+ TYPE_RISCV_SHAKTI_SOC);
+ qdev_realize(DEVICE(&sms->soc), NULL, &error_abort);
+
+ /* register RAM */
+ memory_region_init_ram(main_mem, NULL, "riscv.shakti.c.ram",
+ mstate->ram_size, &error_fatal);
+ memory_region_add_subregion(system_memory,
+ shakti_c_memmap[SHAKTI_C_RAM].base,
+ main_mem);
+
+ /* ROM reset vector */
+ riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus,
+ shakti_c_memmap[SHAKTI_C_RAM].base,
+ shakti_c_memmap[SHAKTI_C_ROM].base,
+ shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0,
+ NULL);
+ if (mstate->firmware) {
+ riscv_load_firmware(mstate->firmware,
+ shakti_c_memmap[SHAKTI_C_RAM].base,
+ NULL);
+ }
+}
+
+static void shakti_c_machine_instance_init(Object *obj)
+{
+}
+
+static void shakti_c_machine_class_init(ObjectClass *klass, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(klass);
+ mc->desc = "RISC-V Board compatible with Shakti SDK";
+ mc->init = shakti_c_machine_state_init;
+ mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C;
+}
+
+static const TypeInfo shakti_c_machine_type_info = {
+ .name = TYPE_RISCV_SHAKTI_MACHINE,
+ .parent = TYPE_MACHINE,
+ .class_init = shakti_c_machine_class_init,
+ .instance_init = shakti_c_machine_instance_init,
+ .instance_size = sizeof(ShaktiCMachineState),
+};
+
+static void shakti_c_machine_type_info_register(void)
+{
+ type_register_static(&shakti_c_machine_type_info);
+}
+type_init(shakti_c_machine_type_info_register)
+
+static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp)
+{
+ ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(dev);
+ MemoryRegion *system_memory = get_system_memory();
+
+ sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort);
+
+ sss->plic = sifive_plic_create(shakti_c_memmap[SHAKTI_C_PLIC].base,
+ (char *)SHAKTI_C_PLIC_HART_CONFIG, 0,
+ SHAKTI_C_PLIC_NUM_SOURCES,
+ SHAKTI_C_PLIC_NUM_PRIORITIES,
+ SHAKTI_C_PLIC_PRIORITY_BASE,
+ SHAKTI_C_PLIC_PENDING_BASE,
+ SHAKTI_C_PLIC_ENABLE_BASE,
+ SHAKTI_C_PLIC_ENABLE_STRIDE,
+ SHAKTI_C_PLIC_CONTEXT_BASE,
+ SHAKTI_C_PLIC_CONTEXT_STRIDE,
+ shakti_c_memmap[SHAKTI_C_PLIC].size);
+
+ sifive_clint_create(shakti_c_memmap[SHAKTI_C_CLINT].base,
+ shakti_c_memmap[SHAKTI_C_CLINT].size, 0, 1,
+ SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
+ SIFIVE_CLINT_TIMEBASE_FREQ, false);
+
+ qdev_prop_set_chr(DEVICE(&(sss->uart)), "chardev", serial_hd(0));
+ if (!sysbus_realize(SYS_BUS_DEVICE(&sss->uart), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&sss->uart), 0,
+ shakti_c_memmap[SHAKTI_C_UART].base);
+
+ /* ROM */
+ memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom",
+ shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal);
+ memory_region_add_subregion(system_memory,
+ shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom);
+}
+
+static void shakti_c_soc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = shakti_c_soc_state_realize;
+}
+
+static void shakti_c_soc_instance_init(Object *obj)
+{
+ ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj);
+
+ object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY);
+ object_initialize_child(obj, "uart", &sss->uart, TYPE_SHAKTI_UART);
+
+ /*
+ * CPU type is fixed and we are not supporting passing from commandline yet.
+ * So let it be in instance_init. When supported should use ms->cpu_type
+ * instead of TYPE_RISCV_CPU_SHAKTI_C
+ */
+ object_property_set_str(OBJECT(&sss->cpus), "cpu-type",
+ TYPE_RISCV_CPU_SHAKTI_C, &error_abort);
+ object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1,
+ &error_abort);
+}
+
+static const TypeInfo shakti_c_type_info = {
+ .name = TYPE_RISCV_SHAKTI_SOC,
+ .parent = TYPE_DEVICE,
+ .class_init = shakti_c_soc_class_init,
+ .instance_init = shakti_c_soc_instance_init,
+ .instance_size = sizeof(ShaktiCSoCState),
+};
+
+static void shakti_c_type_info_register(void)
+{
+ type_register_static(&shakti_c_type_info);
+}
+type_init(shakti_c_type_info_register)
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 3e8b44b2c0..ddc658c8d6 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -48,7 +48,7 @@
#include "sysemu/arch_init.h"
#include "sysemu/sysemu.h"
-static MemMapEntry sifive_e_memmap[] = {
+static const MemMapEntry sifive_e_memmap[] = {
[SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 },
[SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 },
[SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 },
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index 3d2d3854e7..4fbafddb22 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -871,22 +871,6 @@ static void rtc_notify_suspend(Notifier *notifier, void *data)
rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE);
}
-static void rtc_reset(void *opaque)
-{
- RTCState *s = opaque;
-
- s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
- s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
- check_update_timer(s);
-
- qemu_irq_lower(s->irq);
-
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- s->irq_coalesced = 0;
- s->irq_reinject_on_ack_count = 0;
- }
-}
-
static const MemoryRegionOps cmos_ops = {
.read = cmos_ioport_read,
.write = cmos_ioport_write,
@@ -961,7 +945,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3);
- qemu_register_reset(rtc_reset, s);
object_property_add_tm(OBJECT(s), "date", rtc_get_date);
@@ -997,15 +980,32 @@ static Property mc146818rtc_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static void rtc_resetdev(DeviceState *d)
+static void rtc_reset_enter(Object *obj, ResetType type)
{
- RTCState *s = MC146818_RTC(d);
+ RTCState *s = MC146818_RTC(obj);
/* Reason: VM do suspend self will set 0xfe
* Reset any values other than 0xfe(Guest suspend case) */
if (s->cmos_data[0x0f] != 0xfe) {
s->cmos_data[0x0f] = 0x00;
}
+
+ s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
+ s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
+ check_update_timer(s);
+
+
+ if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
+ s->irq_coalesced = 0;
+ s->irq_reinject_on_ack_count = 0;
+ }
+}
+
+static void rtc_reset_hold(Object *obj)
+{
+ RTCState *s = MC146818_RTC(obj);
+
+ qemu_irq_lower(s->irq);
}
static void rtc_build_aml(ISADevice *isadev, Aml *scope)
@@ -1032,11 +1032,13 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope)
static void rtc_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
ISADeviceClass *isa = ISA_DEVICE_CLASS(klass);
dc->realize = rtc_realizefn;
- dc->reset = rtc_resetdev;
dc->vmsd = &vmstate_rtc;
+ rc->phases.enter = rtc_reset_enter;
+ rc->phases.hold = rtc_reset_hold;
isa->build_aml = rtc_build_aml;
device_class_set_props(dc, mc146818rtc_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 4ad8793406..28e003250a 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -94,8 +94,7 @@ static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
return progress;
}
-static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
- VirtIOHandleAIOOutput fn)
+static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
int rc;
@@ -109,7 +108,6 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n,
return rc;
}
- virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn);
return 0;
}
@@ -154,40 +152,55 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
goto fail_guest_notifiers;
}
- aio_context_acquire(s->ctx);
- rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0,
- virtio_scsi_data_plane_handle_ctrl);
- if (rc) {
- goto fail_vrings;
+ memory_region_transaction_begin();
+
+ rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0);
+ if (rc != 0) {
+ goto fail_host_notifiers;
}
vq_init_count++;
- rc = virtio_scsi_vring_init(s, vs->event_vq, 1,
- virtio_scsi_data_plane_handle_event);
- if (rc) {
- goto fail_vrings;
+ rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1);
+ if (rc != 0) {
+ goto fail_host_notifiers;
}
vq_init_count++;
+
for (i = 0; i < vs->conf.num_queues; i++) {
- rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2,
- virtio_scsi_data_plane_handle_cmd);
+ rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2);
if (rc) {
- goto fail_vrings;
+ goto fail_host_notifiers;
}
vq_init_count++;
}
+ memory_region_transaction_commit();
+
+ aio_context_acquire(s->ctx);
+ virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx,
+ virtio_scsi_data_plane_handle_ctrl);
+ virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx,
+ virtio_scsi_data_plane_handle_event);
+
+ for (i = 0; i < vs->conf.num_queues; i++) {
+ virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx,
+ virtio_scsi_data_plane_handle_cmd);
+ }
+
s->dataplane_starting = false;
s->dataplane_started = true;
aio_context_release(s->ctx);
return 0;
-fail_vrings:
- aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
- aio_context_release(s->ctx);
+fail_host_notifiers:
for (i = 0; i < vq_init_count; i++) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
+ }
+
+ memory_region_transaction_commit();
+
+ for (i = 0; i < vq_init_count; i++) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
}
k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
@@ -225,8 +238,15 @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
blk_drain_all(); /* ensure there are no in-flight requests */
+ memory_region_transaction_begin();
+
for (i = 0; i < vs->conf.num_queues + 2; i++) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
+ }
+
+ memory_region_transaction_commit();
+
+ for (i = 0; i < vs->conf.num_queues + 2; i++) {
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
}
diff --git a/hw/sd/meson.build b/hw/sd/meson.build
index 9c29691e13..f1ce357a3b 100644
--- a/hw/sd/meson.build
+++ b/hw/sd/meson.build
@@ -4,7 +4,6 @@ softmmu_ss.add(when: 'CONFIG_SDHCI', if_true: files('sdhci.c'))
softmmu_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
softmmu_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-memcard.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c
deleted file mode 100644
index a1235aa46c..0000000000
--- a/hw/sd/milkymist-memcard.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * QEMU model of the Milkymist SD Card Controller.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/memcard.pdf
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qapi/error.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-#include "hw/qdev-properties.h"
-#include "hw/sd/sd.h"
-#include "qom/object.h"
-
-enum {
- ENABLE_CMD_TX = (1<<0),
- ENABLE_CMD_RX = (1<<1),
- ENABLE_DAT_TX = (1<<2),
- ENABLE_DAT_RX = (1<<3),
-};
-
-enum {
- PENDING_CMD_TX = (1<<0),
- PENDING_CMD_RX = (1<<1),
- PENDING_DAT_TX = (1<<2),
- PENDING_DAT_RX = (1<<3),
-};
-
-enum {
- START_CMD_TX = (1<<0),
- START_DAT_RX = (1<<1),
-};
-
-enum {
- R_CLK2XDIV = 0,
- R_ENABLE,
- R_PENDING,
- R_START,
- R_CMD,
- R_DAT,
- R_MAX
-};
-
-#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMemcardState, MILKYMIST_MEMCARD)
-
-#define TYPE_MILKYMIST_SDBUS "milkymist-sdbus"
-
-struct MilkymistMemcardState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
- SDBus sdbus;
-
- int command_write_ptr;
- int response_read_ptr;
- int response_len;
- int ignore_next_cmd;
- int enabled;
- uint8_t command[6];
- uint8_t response[17];
- uint32_t regs[R_MAX];
-};
-
-static void update_pending_bits(MilkymistMemcardState *s)
-{
- /* transmits are instantaneous, thus tx pending bits are never set */
- s->regs[R_PENDING] = 0;
- /* if rx is enabled the corresponding pending bits are always set */
- if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
- s->regs[R_PENDING] |= PENDING_CMD_RX;
- }
- if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
- s->regs[R_PENDING] |= PENDING_DAT_RX;
- }
-}
-
-static void memcard_sd_command(MilkymistMemcardState *s)
-{
- SDRequest req;
-
- req.cmd = s->command[0] & 0x3f;
- req.arg = ldl_be_p(s->command + 1);
- req.crc = s->command[5];
-
- s->response[0] = req.cmd;
- s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1);
- s->response_read_ptr = 0;
-
- if (s->response_len == 16) {
- /* R2 response */
- s->response[0] = 0x3f;
- s->response_len += 1;
- } else if (s->response_len == 4) {
- /* no crc calculation, insert dummy byte */
- s->response[5] = 0;
- s->response_len += 2;
- }
-
- if (req.cmd == 0) {
- /* next write is a dummy byte to clock the initialization of the sd
- * card */
- s->ignore_next_cmd = 1;
- }
-}
-
-static uint64_t memcard_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistMemcardState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_CMD:
- if (!s->enabled) {
- r = 0xff;
- } else {
- r = s->response[s->response_read_ptr++];
- if (s->response_read_ptr > s->response_len) {
- qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: "
- "read more cmd bytes than available: clipping\n");
- s->response_read_ptr = 0;
- }
- }
- break;
- case R_DAT:
- if (!s->enabled) {
- r = 0xffffffff;
- } else {
- sdbus_read_data(&s->sdbus, &r, sizeof(r));
- be32_to_cpus(&r);
- }
- break;
- case R_CLK2XDIV:
- case R_ENABLE:
- case R_PENDING:
- case R_START:
- r = s->regs[addr];
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
- "read access to unknown register 0x%" HWADDR_PRIx "\n",
- addr << 2);
- break;
- }
-
- trace_milkymist_memcard_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistMemcardState *s = opaque;
- uint32_t val32;
-
- trace_milkymist_memcard_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_PENDING:
- /* clear rx pending bits */
- s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
- update_pending_bits(s);
- break;
- case R_CMD:
- if (!s->enabled) {
- break;
- }
- if (s->ignore_next_cmd) {
- s->ignore_next_cmd = 0;
- break;
- }
- s->command[s->command_write_ptr] = value & 0xff;
- s->command_write_ptr = (s->command_write_ptr + 1) % 6;
- if (s->command_write_ptr == 0) {
- memcard_sd_command(s);
- }
- break;
- case R_DAT:
- if (!s->enabled) {
- break;
- }
- val32 = cpu_to_be32(value);
- sdbus_write_data(&s->sdbus, &val32, sizeof(val32));
- break;
- case R_ENABLE:
- s->regs[addr] = value;
- update_pending_bits(s);
- break;
- case R_CLK2XDIV:
- case R_START:
- s->regs[addr] = value;
- break;
-
- default:
- qemu_log_mask(LOG_UNIMP, "milkymist_memcard: "
- "write access to unknown register 0x%" HWADDR_PRIx " "
- "(value 0x%" PRIx64 ")\n", addr << 2, value);
- break;
- }
-}
-
-static const MemoryRegionOps memcard_mmio_ops = {
- .read = memcard_read,
- .write = memcard_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_memcard_reset(DeviceState *d)
-{
- MilkymistMemcardState *s = MILKYMIST_MEMCARD(d);
- int i;
-
- s->command_write_ptr = 0;
- s->response_read_ptr = 0;
- s->response_len = 0;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-}
-
-static void milkymist_memcard_set_readonly(DeviceState *dev, bool level)
-{
- qemu_log_mask(LOG_UNIMP,
- "milkymist_memcard: read-only mode not supported\n");
-}
-
-static void milkymist_memcard_set_inserted(DeviceState *dev, bool level)
-{
- MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev);
-
- s->enabled = !!level;
-}
-
-static void milkymist_memcard_init(Object *obj)
-{
- MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s,
- "milkymist-memcard", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
- DEVICE(obj), "sd-bus");
-}
-
-static const VMStateDescription vmstate_milkymist_memcard = {
- .name = "milkymist-memcard",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
- VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
- VMSTATE_INT32(response_len, MilkymistMemcardState),
- VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
- VMSTATE_INT32(enabled, MilkymistMemcardState),
- VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
- VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
- VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = milkymist_memcard_reset;
- dc->vmsd = &vmstate_milkymist_memcard;
- /* Reason: output IRQs should be wired up */
- dc->user_creatable = false;
-}
-
-static const TypeInfo milkymist_memcard_info = {
- .name = TYPE_MILKYMIST_MEMCARD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistMemcardState),
- .instance_init = milkymist_memcard_init,
- .class_init = milkymist_memcard_class_init,
-};
-
-static void milkymist_sdbus_class_init(ObjectClass *klass, void *data)
-{
- SDBusClass *sbc = SD_BUS_CLASS(klass);
-
- sbc->set_inserted = milkymist_memcard_set_inserted;
- sbc->set_readonly = milkymist_memcard_set_readonly;
-}
-
-static const TypeInfo milkymist_sdbus_info = {
- .name = TYPE_MILKYMIST_SDBUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = milkymist_sdbus_class_init,
-};
-
-static void milkymist_memcard_register_types(void)
-{
- type_register_static(&milkymist_memcard_info);
- type_register_static(&milkymist_sdbus_info);
-}
-
-type_init(milkymist_memcard_register_types)
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 4140e48540..e185d07a1d 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -55,10 +55,6 @@ sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t
sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t length) "%s %20s/ CMD%02d len %" PRIu32
sdcard_set_voltage(uint16_t millivolts) "%u mV"
-# milkymist-memcard.c
-milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-
# pxa2xx_mmci.c
pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x"
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index f22c4f5b73..7397e56737 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -27,6 +27,7 @@
#include "hw/firmware/smbios.h"
#include "hw/loader.h"
#include "hw/boards.h"
+#include "hw/pci/pci_bus.h"
#include "smbios_build.h"
/* legacy structures and constants for <= 2.0 machines */
@@ -118,6 +119,28 @@ static struct {
uint16_t speed;
} type17;
+static QEnumLookup type41_kind_lookup = {
+ .array = (const char *const[]) {
+ "other",
+ "unknown",
+ "video",
+ "scsi",
+ "ethernet",
+ "tokenring",
+ "sound",
+ "pata",
+ "sata",
+ "sas",
+ },
+ .size = 10
+};
+struct type41_instance {
+ const char *designation, *pcidev;
+ uint8_t instance, kind;
+ QTAILQ_ENTRY(type41_instance) next;
+};
+static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41);
+
static QemuOptsList qemu_smbios_opts = {
.name = "smbios",
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
@@ -358,6 +381,32 @@ static const QemuOptDesc qemu_smbios_type17_opts[] = {
{ /* end of list */ }
};
+static const QemuOptDesc qemu_smbios_type41_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "designation",
+ .type = QEMU_OPT_STRING,
+ .help = "reference designation string",
+ },{
+ .name = "kind",
+ .type = QEMU_OPT_STRING,
+ .help = "device type",
+ .def_value_str = "other",
+ },{
+ .name = "instance",
+ .type = QEMU_OPT_NUMBER,
+ .help = "device type instance",
+ },{
+ .name = "pcidev",
+ .type = QEMU_OPT_STRING,
+ .help = "PCI device",
+ },
+ { /* end of list */ }
+};
+
static void smbios_register_config(void)
{
qemu_add_opts(&qemu_smbios_opts);
@@ -773,6 +822,53 @@ static void smbios_build_type_32_table(void)
SMBIOS_BUILD_TABLE_POST;
}
+static void smbios_build_type_41_table(Error **errp)
+{
+ unsigned instance = 0;
+ struct type41_instance *t41;
+
+ QTAILQ_FOREACH(t41, &type41, next) {
+ SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true);
+
+ SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation);
+ t->device_type = t41->kind;
+ t->device_type_instance = t41->instance;
+ t->segment_group_number = cpu_to_le16(0);
+ t->bus_number = 0;
+ t->device_number = 0;
+
+ if (t41->pcidev) {
+ PCIDevice *pdev = NULL;
+ int rc = pci_qdev_find_device(t41->pcidev, &pdev);
+ if (rc != 0) {
+ error_setg(errp,
+ "No PCI device %s for SMBIOS type 41 entry %s",
+ t41->pcidev, t41->designation);
+ return;
+ }
+ /*
+ * We only handle the case were the device is attached to
+ * the PCI root bus. The general case is more complex as
+ * bridges are enumerated later and the table would need
+ * to be updated at this moment.
+ */
+ if (!pci_bus_is_root(pci_get_bus(pdev))) {
+ error_setg(errp,
+ "Cannot create type 41 entry for PCI device %s: "
+ "not attached to the root bus",
+ t41->pcidev);
+ return;
+ }
+ t->segment_group_number = cpu_to_le16(0);
+ t->bus_number = pci_dev_bus_num(pdev);
+ t->device_number = pdev->devfn;
+ }
+
+ SMBIOS_BUILD_TABLE_POST;
+ instance++;
+ }
+}
+
static void smbios_build_type_127_table(void)
{
SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
@@ -883,7 +979,8 @@ void smbios_get_tables(MachineState *ms,
const struct smbios_phys_mem_area *mem_array,
const unsigned int mem_array_size,
uint8_t **tables, size_t *tables_len,
- uint8_t **anchor, size_t *anchor_len)
+ uint8_t **anchor, size_t *anchor_len,
+ Error **errp)
{
unsigned i, dimm_cnt;
@@ -928,6 +1025,7 @@ void smbios_get_tables(MachineState *ms,
smbios_build_type_32_table();
smbios_build_type_38_table();
+ smbios_build_type_41_table(errp);
smbios_build_type_127_table();
smbios_validate_table(ms);
@@ -1224,6 +1322,30 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
save_opt(&type17.part, opts, "part");
type17.speed = qemu_opt_get_number(opts, "speed", 0);
return;
+ case 41: {
+ struct type41_instance *t;
+ Error *local_err = NULL;
+
+ if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) {
+ return;
+ }
+ t = g_new0(struct type41_instance, 1);
+ save_opt(&t->designation, opts, "designation");
+ t->kind = qapi_enum_parse(&type41_kind_lookup,
+ qemu_opt_get(opts, "kind"),
+ 0, &local_err) + 1;
+ t->kind |= 0x80; /* enabled */
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ g_free(t);
+ return;
+ }
+ t->instance = qemu_opt_get_number(opts, "instance", 1);
+ save_opt(&t->pcidev, opts, "pcidev");
+
+ QTAILQ_INSERT_TAIL(&type41, t, next);
+ return;
+ }
default:
error_setg(errp,
"Don't know how to build fields for SMBIOS type %ld",
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
index 5379006086..4ba662190d 100644
--- a/hw/timer/etraxfs_timer.c
+++ b/hw/timer/etraxfs_timer.c
@@ -309,9 +309,9 @@ static const MemoryRegionOps timer_ops = {
}
};
-static void etraxfs_timer_reset(void *opaque)
+static void etraxfs_timer_reset_enter(Object *obj, ResetType type)
{
- ETRAXTimerState *t = opaque;
+ ETRAXTimerState *t = ETRAX_TIMER(obj);
ptimer_transaction_begin(t->ptimer_t0);
ptimer_stop(t->ptimer_t0);
@@ -325,6 +325,12 @@ static void etraxfs_timer_reset(void *opaque)
t->rw_wd_ctrl = 0;
t->r_intr = 0;
t->rw_intr_mask = 0;
+}
+
+static void etraxfs_timer_reset_hold(Object *obj)
+{
+ ETRAXTimerState *t = ETRAX_TIMER(obj);
+
qemu_irq_lower(t->irq);
}
@@ -343,14 +349,16 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
"etraxfs-timer", 0x5c);
sysbus_init_mmio(sbd, &t->mmio);
- qemu_register_reset(etraxfs_timer_reset, t);
}
static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->realize = etraxfs_timer_realize;
+ rc->phases.enter = etraxfs_timer_reset_enter;
+ rc->phases.hold = etraxfs_timer_reset_hold;
}
static const TypeInfo etraxfs_timer_info = {
diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c
deleted file mode 100644
index eeaf0ada5f..0000000000
--- a/hw/timer/lm32_timer.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * QEMU model of the LatticeMico32 timer block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://www.latticesemi.com/documents/mico32timer.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define DEFAULT_FREQUENCY (50*1000000)
-
-enum {
- R_SR = 0,
- R_CR,
- R_PERIOD,
- R_SNAPSHOT,
- R_MAX
-};
-
-enum {
- SR_TO = (1 << 0),
- SR_RUN = (1 << 1),
-};
-
-enum {
- CR_ITO = (1 << 0),
- CR_CONT = (1 << 1),
- CR_START = (1 << 2),
- CR_STOP = (1 << 3),
-};
-
-#define TYPE_LM32_TIMER "lm32-timer"
-OBJECT_DECLARE_SIMPLE_TYPE(LM32TimerState, LM32_TIMER)
-
-struct LM32TimerState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- ptimer_state *ptimer;
-
- qemu_irq irq;
- uint32_t freq_hz;
-
- uint32_t regs[R_MAX];
-};
-
-static void timer_update_irq(LM32TimerState *s)
-{
- int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
-
- trace_lm32_timer_irq_state(state);
- qemu_set_irq(s->irq, state);
-}
-
-static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
-{
- LM32TimerState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_SR:
- case R_CR:
- case R_PERIOD:
- r = s->regs[addr];
- break;
- case R_SNAPSHOT:
- r = (uint32_t)ptimer_get_count(s->ptimer);
- break;
- default:
- error_report("lm32_timer: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_lm32_timer_memory_read(addr << 2, r);
- return r;
-}
-
-static void timer_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LM32TimerState *s = opaque;
-
- trace_lm32_timer_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_SR:
- s->regs[R_SR] &= ~SR_TO;
- break;
- case R_CR:
- ptimer_transaction_begin(s->ptimer);
- s->regs[R_CR] = value;
- if (s->regs[R_CR] & CR_START) {
- ptimer_run(s->ptimer, 1);
- }
- if (s->regs[R_CR] & CR_STOP) {
- ptimer_stop(s->ptimer);
- }
- ptimer_transaction_commit(s->ptimer);
- break;
- case R_PERIOD:
- s->regs[R_PERIOD] = value;
- ptimer_transaction_begin(s->ptimer);
- ptimer_set_count(s->ptimer, value);
- ptimer_transaction_commit(s->ptimer);
- break;
- case R_SNAPSHOT:
- error_report("lm32_timer: write access to read only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_timer: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
- timer_update_irq(s);
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void timer_hit(void *opaque)
-{
- LM32TimerState *s = opaque;
-
- trace_lm32_timer_hit();
-
- s->regs[R_SR] |= SR_TO;
-
- if (s->regs[R_CR] & CR_CONT) {
- ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
- ptimer_run(s->ptimer, 1);
- }
- timer_update_irq(s);
-}
-
-static void timer_reset(DeviceState *d)
-{
- LM32TimerState *s = LM32_TIMER(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
- ptimer_transaction_begin(s->ptimer);
- ptimer_stop(s->ptimer);
- ptimer_transaction_commit(s->ptimer);
-}
-
-static void lm32_timer_init(Object *obj)
-{
- LM32TimerState *s = LM32_TIMER(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, obj, &timer_ops, s,
- "timer", R_MAX * 4);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void lm32_timer_realize(DeviceState *dev, Error **errp)
-{
- LM32TimerState *s = LM32_TIMER(dev);
-
- s->ptimer = ptimer_init(timer_hit, s, PTIMER_POLICY_DEFAULT);
-
- ptimer_transaction_begin(s->ptimer);
- ptimer_set_freq(s->ptimer, s->freq_hz);
- ptimer_transaction_commit(s->ptimer);
-}
-
-static const VMStateDescription vmstate_lm32_timer = {
- .name = "lm32-timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_PTIMER(ptimer, LM32TimerState),
- VMSTATE_UINT32(freq_hz, LM32TimerState),
- VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property lm32_timer_properties[] = {
- DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_timer_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = lm32_timer_realize;
- dc->reset = timer_reset;
- dc->vmsd = &vmstate_lm32_timer;
- device_class_set_props(dc, lm32_timer_properties);
-}
-
-static const TypeInfo lm32_timer_info = {
- .name = TYPE_LM32_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32TimerState),
- .instance_init = lm32_timer_init,
- .class_init = lm32_timer_class_init,
-};
-
-static void lm32_timer_register_types(void)
-{
- type_register_static(&lm32_timer_info);
-}
-
-type_init(lm32_timer_register_types)
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index 598d058506..157f540ecd 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -19,15 +19,12 @@ softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c'))
softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c'))
-softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_timer.c'))
-softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-sysctl.c'))
softmmu_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c'))
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c'))
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
-softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_ost.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c
deleted file mode 100644
index 9ecea63861..0000000000
--- a/hw/timer/milkymist-sysctl.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * QEMU model of the Milkymist System Controller.
- *
- * Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/sysctl.pdf
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "sysemu/runstate.h"
-#include "hw/ptimer.h"
-#include "hw/qdev-properties.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-enum {
- CTRL_ENABLE = (1<<0),
- CTRL_AUTORESTART = (1<<1),
-};
-
-enum {
- ICAP_READY = (1<<0),
-};
-
-enum {
- R_GPIO_IN = 0,
- R_GPIO_OUT,
- R_GPIO_INTEN,
- R_TIMER0_CONTROL = 4,
- R_TIMER0_COMPARE,
- R_TIMER0_COUNTER,
- R_TIMER1_CONTROL = 8,
- R_TIMER1_COMPARE,
- R_TIMER1_COUNTER,
- R_ICAP = 16,
- R_DBG_SCRATCHPAD = 20,
- R_DBG_WRITE_LOCK,
- R_CLK_FREQUENCY = 29,
- R_CAPABILITIES,
- R_SYSTEM_ID,
- R_MAX
-};
-
-#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl"
-OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSysctlState, MILKYMIST_SYSCTL)
-
-struct MilkymistSysctlState {
- SysBusDevice parent_obj;
-
- MemoryRegion regs_region;
-
- ptimer_state *ptimer0;
- ptimer_state *ptimer1;
-
- uint32_t freq_hz;
- uint32_t capabilities;
- uint32_t systemid;
- uint32_t strappings;
-
- uint32_t regs[R_MAX];
-
- qemu_irq gpio_irq;
- qemu_irq timer0_irq;
- qemu_irq timer1_irq;
-};
-
-static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
-{
- trace_milkymist_sysctl_icap_write(value);
- switch (value & 0xffff) {
- case 0x000e:
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
- break;
- }
-}
-
-static uint64_t sysctl_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistSysctlState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_TIMER0_COUNTER:
- r = (uint32_t)ptimer_get_count(s->ptimer0);
- /* milkymist timer counts up */
- r = s->regs[R_TIMER0_COMPARE] - r;
- break;
- case R_TIMER1_COUNTER:
- r = (uint32_t)ptimer_get_count(s->ptimer1);
- /* milkymist timer counts up */
- r = s->regs[R_TIMER1_COMPARE] - r;
- break;
- case R_GPIO_IN:
- case R_GPIO_OUT:
- case R_GPIO_INTEN:
- case R_TIMER0_CONTROL:
- case R_TIMER0_COMPARE:
- case R_TIMER1_CONTROL:
- case R_TIMER1_COMPARE:
- case R_ICAP:
- case R_DBG_SCRATCHPAD:
- case R_DBG_WRITE_LOCK:
- case R_CLK_FREQUENCY:
- case R_CAPABILITIES:
- case R_SYSTEM_ID:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_sysctl: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_sysctl_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistSysctlState *s = opaque;
-
- trace_milkymist_sysctl_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_GPIO_OUT:
- case R_GPIO_INTEN:
- case R_TIMER0_COUNTER:
- case R_TIMER1_COUNTER:
- case R_DBG_SCRATCHPAD:
- s->regs[addr] = value;
- break;
- case R_TIMER0_COMPARE:
- ptimer_transaction_begin(s->ptimer0);
- ptimer_set_limit(s->ptimer0, value, 0);
- s->regs[addr] = value;
- ptimer_transaction_commit(s->ptimer0);
- break;
- case R_TIMER1_COMPARE:
- ptimer_transaction_begin(s->ptimer1);
- ptimer_set_limit(s->ptimer1, value, 0);
- s->regs[addr] = value;
- ptimer_transaction_commit(s->ptimer1);
- break;
- case R_TIMER0_CONTROL:
- ptimer_transaction_begin(s->ptimer0);
- s->regs[addr] = value;
- if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
- trace_milkymist_sysctl_start_timer0();
- ptimer_set_count(s->ptimer0,
- s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
- ptimer_run(s->ptimer0, 0);
- } else {
- trace_milkymist_sysctl_stop_timer0();
- ptimer_stop(s->ptimer0);
- }
- ptimer_transaction_commit(s->ptimer0);
- break;
- case R_TIMER1_CONTROL:
- ptimer_transaction_begin(s->ptimer1);
- s->regs[addr] = value;
- if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
- trace_milkymist_sysctl_start_timer1();
- ptimer_set_count(s->ptimer1,
- s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
- ptimer_run(s->ptimer1, 0);
- } else {
- trace_milkymist_sysctl_stop_timer1();
- ptimer_stop(s->ptimer1);
- }
- ptimer_transaction_commit(s->ptimer1);
- break;
- case R_ICAP:
- sysctl_icap_write(s, value);
- break;
- case R_DBG_WRITE_LOCK:
- s->regs[addr] = 1;
- break;
- case R_SYSTEM_ID:
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- break;
-
- case R_GPIO_IN:
- case R_CLK_FREQUENCY:
- case R_CAPABILITIES:
- error_report("milkymist_sysctl: write to read-only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
-
- default:
- error_report("milkymist_sysctl: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-}
-
-static const MemoryRegionOps sysctl_mmio_ops = {
- .read = sysctl_read,
- .write = sysctl_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timer0_hit(void *opaque)
-{
- MilkymistSysctlState *s = opaque;
-
- if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
- s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
- trace_milkymist_sysctl_stop_timer0();
- ptimer_stop(s->ptimer0);
- }
-
- trace_milkymist_sysctl_pulse_irq_timer0();
- qemu_irq_pulse(s->timer0_irq);
-}
-
-static void timer1_hit(void *opaque)
-{
- MilkymistSysctlState *s = opaque;
-
- if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
- s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
- trace_milkymist_sysctl_stop_timer1();
- ptimer_stop(s->ptimer1);
- }
-
- trace_milkymist_sysctl_pulse_irq_timer1();
- qemu_irq_pulse(s->timer1_irq);
-}
-
-static void milkymist_sysctl_reset(DeviceState *d)
-{
- MilkymistSysctlState *s = MILKYMIST_SYSCTL(d);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- ptimer_transaction_begin(s->ptimer0);
- ptimer_stop(s->ptimer0);
- ptimer_transaction_commit(s->ptimer0);
- ptimer_transaction_begin(s->ptimer1);
- ptimer_stop(s->ptimer1);
- ptimer_transaction_commit(s->ptimer1);
-
- /* defaults */
- s->regs[R_ICAP] = ICAP_READY;
- s->regs[R_SYSTEM_ID] = s->systemid;
- s->regs[R_CLK_FREQUENCY] = s->freq_hz;
- s->regs[R_CAPABILITIES] = s->capabilities;
- s->regs[R_GPIO_IN] = s->strappings;
-}
-
-static void milkymist_sysctl_init(Object *obj)
-{
- MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->gpio_irq);
- sysbus_init_irq(dev, &s->timer0_irq);
- sysbus_init_irq(dev, &s->timer1_irq);
-
- memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s,
- "milkymist-sysctl", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-}
-
-static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
-{
- MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
-
- s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT);
- s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT);
-
- ptimer_transaction_begin(s->ptimer0);
- ptimer_set_freq(s->ptimer0, s->freq_hz);
- ptimer_transaction_commit(s->ptimer0);
- ptimer_transaction_begin(s->ptimer1);
- ptimer_set_freq(s->ptimer1, s->freq_hz);
- ptimer_transaction_commit(s->ptimer1);
-}
-
-static const VMStateDescription vmstate_milkymist_sysctl = {
- .name = "milkymist-sysctl",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
- VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
- VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property milkymist_sysctl_properties[] = {
- DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
- freq_hz, 80000000),
- DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
- capabilities, 0x00000000),
- DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
- systemid, 0x10014d31),
- DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
- strappings, 0x00000001),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = milkymist_sysctl_realize;
- dc->reset = milkymist_sysctl_reset;
- dc->vmsd = &vmstate_milkymist_sysctl;
- device_class_set_props(dc, milkymist_sysctl_properties);
-}
-
-static const TypeInfo milkymist_sysctl_info = {
- .name = TYPE_MILKYMIST_SYSCTL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistSysctlState),
- .instance_init = milkymist_sysctl_init,
- .class_init = milkymist_sysctl_class_init,
-};
-
-static void milkymist_sysctl_register_types(void)
-{
- type_register_static(&milkymist_sysctl_info);
-}
-
-type_init(milkymist_sysctl_register_types)
diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c
deleted file mode 100644
index d5bf26b56b..0000000000
--- a/hw/timer/puv3_ost.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * OSTimer device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "hw/sysbus.h"
-#include "hw/irq.h"
-#include "hw/ptimer.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-#include "qom/object.h"
-
-#undef DEBUG_PUV3
-#include "hw/unicore32/puv3.h"
-
-#define TYPE_PUV3_OST "puv3_ost"
-OBJECT_DECLARE_SIMPLE_TYPE(PUV3OSTState, PUV3_OST)
-
-/* puv3 ostimer implementation. */
-struct PUV3OSTState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- ptimer_state *ptimer;
-
- uint32_t reg_OSMR0;
- uint32_t reg_OSCR;
- uint32_t reg_OSSR;
- uint32_t reg_OIER;
-};
-
-static uint64_t puv3_ost_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PUV3OSTState *s = opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case 0x10: /* Counter Register */
- ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
- break;
- case 0x14: /* Status Register */
- ret = s->reg_OSSR;
- break;
- case 0x1c: /* Interrupt Enable Register */
- ret = s->reg_OIER;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
- DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
- return ret;
-}
-
-static void puv3_ost_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PUV3OSTState *s = opaque;
-
- DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
- switch (offset) {
- case 0x00: /* Match Register 0 */
- ptimer_transaction_begin(s->ptimer);
- s->reg_OSMR0 = value;
- if (s->reg_OSMR0 > s->reg_OSCR) {
- ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
- } else {
- ptimer_set_count(s->ptimer, s->reg_OSMR0 +
- (0xffffffff - s->reg_OSCR));
- }
- ptimer_run(s->ptimer, 2);
- ptimer_transaction_commit(s->ptimer);
- break;
- case 0x14: /* Status Register */
- assert(value == 0);
- if (s->reg_OSSR) {
- s->reg_OSSR = value;
- qemu_irq_lower(s->irq);
- }
- break;
- case 0x1c: /* Interrupt Enable Register */
- s->reg_OIER = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps puv3_ost_ops = {
- .read = puv3_ost_read,
- .write = puv3_ost_write,
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_ost_tick(void *opaque)
-{
- PUV3OSTState *s = opaque;
-
- DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
- s->reg_OSCR, s->reg_OSMR0);
-
- s->reg_OSCR = s->reg_OSMR0;
- if (s->reg_OIER) {
- s->reg_OSSR = 1;
- qemu_irq_raise(s->irq);
- }
-}
-
-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(sbd, &s->irq);
-
- s->ptimer = ptimer_init(puv3_ost_tick, s, PTIMER_POLICY_DEFAULT);
- ptimer_transaction_begin(s->ptimer);
- ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
- ptimer_transaction_commit(s->ptimer);
-
- memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
- PUV3_REGS_OFFSET);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void puv3_ost_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = puv3_ost_realize;
-}
-
-static const TypeInfo puv3_ost_info = {
- .name = TYPE_PUV3_OST,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PUV3OSTState),
- .class_init = puv3_ost_class_init,
-};
-
-static void puv3_ost_register_type(void)
-{
- type_register_static(&puv3_ost_info);
-}
-
-type_init(puv3_ost_register_type)
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index f8b9db25c2..029fb56280 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -24,23 +24,6 @@ grlib_gptimer_hit(int id) "timer:%d HIT"
grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x"
-# lm32_timer.c
-lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-lm32_timer_hit(void) "timer hit"
-lm32_timer_irq_state(int level) "irq state %d"
-
-# milkymist-sysctl.c
-milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
-milkymist_sysctl_icap_write(uint32_t value) "value 0x%08x"
-milkymist_sysctl_start_timer0(void) "Start timer0"
-milkymist_sysctl_stop_timer0(void) "Stop timer0"
-milkymist_sysctl_start_timer1(void) "Start timer1"
-milkymist_sysctl_stop_timer1(void) "Stop timer1"
-milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0"
-milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1"
-
# aspeed_timer.c
aspeed_timer_ctrl_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
aspeed_timer_ctrl_external_clock(uint8_t i, bool enable) "Timer %" PRIu8 ": %d"
diff --git a/hw/tricore/meson.build b/hw/tricore/meson.build
index 77ff6fd137..47e36bb077 100644
--- a/hw/tricore/meson.build
+++ b/hw/tricore/meson.build
@@ -1,5 +1,6 @@
tricore_ss = ss.source_set()
tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testboard.c'))
+tricore_ss.add(when: 'CONFIG_TRICORE', if_true: files('tricore_testdevice.c'))
tricore_ss.add(when: 'CONFIG_TRIBOARD', if_true: files('triboard.c'))
tricore_ss.add(when: 'CONFIG_TC27X_SOC', if_true: files('tc27x_soc.c'))
diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c
index 51658d9e37..b6810e3be0 100644
--- a/hw/tricore/tricore_testboard.c
+++ b/hw/tricore/tricore_testboard.c
@@ -27,6 +27,7 @@
#include "hw/loader.h"
#include "elf.h"
#include "hw/tricore/tricore.h"
+#include "hw/tricore/tricore_testdevice.h"
#include "qemu/error-report.h"
@@ -56,6 +57,7 @@ static void tricore_testboard_init(MachineState *machine, int board_id)
{
TriCoreCPU *cpu;
CPUTriCoreState *env;
+ TriCoreTestDeviceState *test_dev;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ext_cram = g_new(MemoryRegion, 1);
@@ -87,6 +89,12 @@ static void tricore_testboard_init(MachineState *machine, int board_id)
memory_region_add_subregion(sysmem, 0xf0050000, pcp_data);
memory_region_add_subregion(sysmem, 0xf0060000, pcp_text);
+ test_dev = g_new(TriCoreTestDeviceState, 1);
+ object_initialize(test_dev, sizeof(TriCoreTestDeviceState),
+ TYPE_TRICORE_TESTDEVICE);
+ memory_region_add_subregion(sysmem, 0xf0000000, &test_dev->iomem);
+
+
tricoretb_binfo.ram_size = machine->ram_size;
tricoretb_binfo.kernel_filename = machine->kernel_filename;
diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c
new file mode 100644
index 0000000000..a1563aa568
--- /dev/null
+++ b/hw/tricore/tricore_testdevice.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018-2021 Bastian Koppelmann Paderborn University
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/qdev-properties.h"
+#include "hw/tricore/tricore_testdevice.h"
+
+static void tricore_testdevice_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ exit(value);
+}
+
+static uint64_t tricore_testdevice_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ return 0xdeadbeef;
+}
+
+static void tricore_testdevice_reset(DeviceState *dev)
+{
+}
+
+static const MemoryRegionOps tricore_testdevice_ops = {
+ .read = tricore_testdevice_read,
+ .write = tricore_testdevice_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tricore_testdevice_init(Object *obj)
+{
+ TriCoreTestDeviceState *s = TRICORE_TESTDEVICE(obj);
+ /* map memory */
+ memory_region_init_io(&s->iomem, OBJECT(s), &tricore_testdevice_ops, s,
+ "tricore_testdevice", 0x4);
+}
+
+static Property tricore_testdevice_properties[] = {
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void tricore_testdevice_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_props(dc, tricore_testdevice_properties);
+ dc->reset = tricore_testdevice_reset;
+}
+
+static const TypeInfo tricore_testdevice_info = {
+ .name = TYPE_TRICORE_TESTDEVICE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TriCoreTestDeviceState),
+ .instance_init = tricore_testdevice_init,
+ .class_init = tricore_testdevice_class_init,
+};
+
+static void tricore_testdevice_register_types(void)
+{
+ type_register_static(&tricore_testdevice_info);
+}
+
+type_init(tricore_testdevice_register_types)
diff --git a/hw/unicore32/Kconfig b/hw/unicore32/Kconfig
deleted file mode 100644
index 4443a29dd2..0000000000
--- a/hw/unicore32/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-config PUV3
- bool
- select ISA_BUS
- select PCKBD
- select PTIMER
diff --git a/hw/unicore32/meson.build b/hw/unicore32/meson.build
deleted file mode 100644
index fc26d6bcab..0000000000
--- a/hw/unicore32/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-unicore32_ss = ss.source_set()
-# PKUnity-v3 SoC and board information
-unicore32_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3.c'))
-
-hw_arch += {'unicore32': unicore32_ss}
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
deleted file mode 100644
index eacacb4249..0000000000
--- a/hw/unicore32/puv3.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Generic PKUnity SoC machine and board descriptor
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "ui/console.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/qtest.h"
-#include "hw/unicore32/puv3.h"
-#include "hw/input/i8042.h"
-#include "hw/irq.h"
-
-#define KERNEL_LOAD_ADDR 0x03000000
-#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */
-
-/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
-#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */
-
-/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
-#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */
-#define PUV3_INTC_BASE (0xee600000) /* APB-6 */
-#define PUV3_OST_BASE (0xee800000) /* APB-8 */
-#define PUV3_PM_BASE (0xeea00000) /* APB-10 */
-#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */
-
-static void puv3_intc_cpu_handler(void *opaque, int irq, int level)
-{
- UniCore32CPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
-
- assert(irq == 0);
- if (level) {
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
-}
-
-static void puv3_soc_init(CPUUniCore32State *env)
-{
- qemu_irq cpu_intc, irqs[PUV3_IRQS_NR];
- DeviceState *dev;
- MemoryRegion *i8042 = g_new(MemoryRegion, 1);
- int i;
-
- /* Initialize interrupt controller */
- cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler,
- env_archcpu(env), 0);
- dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc);
- for (i = 0; i < PUV3_IRQS_NR; i++) {
- irqs[i] = qdev_get_gpio_in(dev, i);
- }
-
- /* Initialize minimal necessary devices for kernel booting */
- sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL);
- sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL);
- sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]);
- sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE,
- irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1],
- irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3],
- irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5],
- irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7],
- irqs[PUV3_IRQS_GPIOHIGH], NULL);
-
- /* Keyboard (i8042), mouse disabled for nographic */
- i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4);
- memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042);
-}
-
-static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size)
-{
- MemoryRegion *ram_memory = g_new(MemoryRegion, 1);
-
- /* SDRAM at address zero. */
- memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size,
- &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0, ram_memory);
-}
-
-static const GraphicHwOps no_ops;
-
-static void puv3_load_kernel(const char *kernel_filename)
-{
- int size;
-
- if (kernel_filename == NULL && qtest_enabled()) {
- return;
- }
- if (kernel_filename == NULL) {
- error_report("kernel parameter cannot be empty");
- exit(1);
- }
-
- /* only zImage format supported */
- size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
- KERNEL_MAX_SIZE);
- if (size < 0) {
- error_report("Load kernel error: '%s'", kernel_filename);
- exit(1);
- }
-
- /* cheat curses that we have a graphic console, only under ocd console */
- graphic_console_init(NULL, 0, &no_ops, NULL);
-}
-
-static void puv3_init(MachineState *machine)
-{
- ram_addr_t ram_size = machine->ram_size;
- const char *kernel_filename = machine->kernel_filename;
- const char *initrd_filename = machine->initrd_filename;
- CPUUniCore32State *env;
- UniCore32CPU *cpu;
-
- if (initrd_filename) {
- error_report("Please use kernel built-in initramdisk");
- exit(1);
- }
-
- cpu = UNICORE32_CPU(cpu_create(machine->cpu_type));
- env = &cpu->env;
-
- puv3_soc_init(env);
- puv3_board_init(env, ram_size);
- puv3_load_kernel(kernel_filename);
-}
-
-static void puv3_machine_init(MachineClass *mc)
-{
- mc->desc = "PKUnity Version-3 based on UniCore32";
- mc->init = puv3_init;
- mc->is_default = true;
- mc->default_cpu_type = UNICORE32_CPU_TYPE_NAME("UniCore-II");
-}
-
-DEFINE_MACHINE("puv3", puv3_machine_init)
diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h
index 57c12ef662..01aca55ca7 100644
--- a/hw/usb/quirks-ftdi-ids.h
+++ b/hw/usb/quirks-ftdi-ids.h
@@ -1222,12 +1222,6 @@
#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D
/*
- * Milkymist One JTAG/Serial
- */
-#define QIHARDWARE_VID 0x20B7
-#define MILKYMISTONE_JTAGSERIAL_PID 0x0713
-
-/*
* CTI GmbH RS485 Converter http://www.cti-lean.com/
*/
/* USB-485-Mini*/
diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h
index 50ef2f9c2e..c3e595f40b 100644
--- a/hw/usb/quirks.h
+++ b/hw/usb/quirks.h
@@ -904,7 +904,6 @@ static const struct usb_device_id usbredir_ftdi_serial_ids[] = {
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
- { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) },
{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) },
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index ded0c10453..ee57abe045 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1909,6 +1909,11 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque)
return err;
}
}
+ if (dev->num_queues && dev->max_queues < dev->num_queues) {
+ error_report("The maximum number of queues supported by the "
+ "backend is %" PRIu64, dev->max_queues);
+ return -EINVAL;
+ }
if (virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM) &&
!(virtio_has_feature(dev->protocol_features,
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index 01d2101d09..8f2fb9f10b 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -371,8 +371,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
return 0;
}
-int vhost_vdpa_get_device_id(struct vhost_dev *dev,
- uint32_t *device_id)
+static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
+ uint32_t *device_id)
{
int ret;
ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id);
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index d120bf8f43..4b5d9e5e50 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -663,9 +663,6 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data)
}
switch (pnd->reason) {
- case PRECOPY_NOTIFY_SETUP:
- precopy_enable_free_page_optimization();
- break;
case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC:
virtio_balloon_free_page_stop(dev);
break;
@@ -685,6 +682,7 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data)
*/
virtio_balloon_free_page_done(dev);
break;
+ case PRECOPY_NOTIFY_SETUP:
case PRECOPY_NOTIFY_COMPLETE:
break;
default:
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index d6332d45c3..859978d248 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -69,6 +69,11 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
return;
}
+ if (has_iommu && !virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
+ error_setg(errp, "iommu_platform=true is not supported by the device");
+ return;
+ }
+
if (klass->device_plugged != NULL) {
klass->device_plugged(qbus->parent, &local_err);
}
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index 655824ff81..75aa7d6f1b 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -902,9 +902,6 @@ static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data)
PrecopyNotifyData *pnd = data;
switch (pnd->reason) {
- case PRECOPY_NOTIFY_SETUP:
- precopy_enable_free_page_optimization();
- break;
case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC:
virtio_mem_precopy_exclude_unplugged(vmem);
break;
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 342c918ea7..5952471b38 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -36,7 +36,9 @@
static bool virtio_mmio_ioeventfd_enabled(DeviceState *d)
{
- return kvm_eventfds_enabled();
+ VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
+
+ return (proxy->flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0;
}
static int virtio_mmio_ioeventfd_assign(DeviceState *d,
@@ -720,6 +722,8 @@ static Property virtio_mmio_properties[] = {
DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy,
format_transport_address, true),
DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags,
+ VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -731,6 +735,11 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
d, NULL);
sysbus_init_irq(sbd, &proxy->irq);
+
+ if (!kvm_eventfds_enabled()) {
+ proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD;
+ }
+
if (proxy->legacy) {
memory_region_init_io(&proxy->iomem, OBJECT(d),
&virtio_legacy_mem_ops, proxy,
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 9e13cb9e3a..e02544b2df 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2981,7 +2981,7 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val)
return ret;
}
-size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes,
+size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes,
uint64_t host_features)
{
size_t config_size = 0;
diff --git a/include/block/block_int.h b/include/block/block_int.h
index c823f5b1b3..b2c8b09d0f 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -357,7 +357,7 @@ struct BlockDriver {
* of in-flight requests, so don't waste the time if possible.
*
* One example usage is to avoid waiting for an nbd target node reconnect
- * timeout during job-cancel.
+ * timeout during job-cancel with force=true.
*/
void (*bdrv_cancel_in_flight)(BlockDriverState *bs);
@@ -954,12 +954,8 @@ struct BlockDriverState {
*/
int64_t total_sectors;
- /* Callback before write request is processed */
- NotifierWithReturnList before_write_notifiers;
-
/* threshold limit for writes, in bytes. "High water mark". */
uint64_t write_threshold_offset;
- NotifierWithReturn write_threshold_notifier;
/* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex.
* Reading from the list can be done with either the BQL or the
@@ -1085,15 +1081,6 @@ bool bdrv_backing_overridden(BlockDriverState *bs);
/**
- * bdrv_add_before_write_notifier:
- *
- * Register a callback that is invoked before write requests are processed but
- * after any throttling or waiting for overlapping requests.
- */
-void bdrv_add_before_write_notifier(BlockDriverState *bs,
- NotifierWithReturn *notifier);
-
-/**
* bdrv_add_aio_context_notifier:
*
* If a long-running job intends to be always run in the same AioContext as a
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 4ac926fbc6..0ff9ce17a9 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -7,7 +7,7 @@ typedef struct QEMU_PACKED NvmeBar {
uint32_t intms;
uint32_t intmc;
uint32_t cc;
- uint32_t rsvd1;
+ uint8_t rsvd24[4];
uint32_t csts;
uint32_t nssrc;
uint32_t aqa;
@@ -848,8 +848,8 @@ enum NvmeStatusCodes {
NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
NVME_NS_ALREADY_ATTACHED = 0x0118,
NVME_NS_PRIVATE = 0x0119,
- NVME_NS_NOT_ATTACHED = 0x011A,
- NVME_NS_CTRL_LIST_INVALID = 0x011C,
+ NVME_NS_NOT_ATTACHED = 0x011a,
+ NVME_NS_CTRL_LIST_INVALID = 0x011c,
NVME_CONFLICTING_ATTRS = 0x0180,
NVME_INVALID_PROT_INFO = 0x0181,
NVME_WRITE_TO_RO = 0x0182,
@@ -1409,9 +1409,9 @@ typedef enum NvmeZoneState {
NVME_ZONE_STATE_IMPLICITLY_OPEN = 0x02,
NVME_ZONE_STATE_EXPLICITLY_OPEN = 0x03,
NVME_ZONE_STATE_CLOSED = 0x04,
- NVME_ZONE_STATE_READ_ONLY = 0x0D,
- NVME_ZONE_STATE_FULL = 0x0E,
- NVME_ZONE_STATE_OFFLINE = 0x0F,
+ NVME_ZONE_STATE_READ_ONLY = 0x0d,
+ NVME_ZONE_STATE_FULL = 0x0e,
+ NVME_ZONE_STATE_OFFLINE = 0x0f,
} NvmeZoneState;
static inline void _nvme_check_size(void)
diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h
index c646f267a4..f50f923e7e 100644
--- a/include/block/write-threshold.h
+++ b/include/block/write-threshold.h
@@ -13,7 +13,7 @@
#ifndef BLOCK_WRITE_THRESHOLD_H
#define BLOCK_WRITE_THRESHOLD_H
-#include "block/block_int.h"
+#include "qemu/typedefs.h"
/*
* bdrv_write_threshold_set:
@@ -36,27 +36,12 @@ void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes);
uint64_t bdrv_write_threshold_get(const BlockDriverState *bs);
/*
- * bdrv_write_threshold_is_set
+ * bdrv_write_threshold_check_write
*
- * Tell if a write threshold is set for a given BDS.
+ * Check whether the specified request exceeds the write threshold.
+ * If so, send a corresponding event and disable write threshold checking.
*/
-bool bdrv_write_threshold_is_set(const BlockDriverState *bs);
-
-/*
- * bdrv_write_threshold_exceeded
- *
- * Return the extent of a write request that exceeded the threshold,
- * or zero if the request is below the threshold.
- * Return zero also if the threshold was not set.
- *
- * NOTE: here we assume the following holds for each request this code
- * deals with:
- *
- * assert((req->offset + req->bytes) <= UINT64_MAX)
- *
- * Please not there is *not* an actual C assert().
- */
-uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs,
- const BdrvTrackedRequest *req);
+void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset,
+ int64_t bytes);
#endif
diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h
index 4701445e80..524f29196d 100644
--- a/include/disas/dis-asm.h
+++ b/include/disas/dis-asm.h
@@ -249,8 +249,6 @@ enum bfd_architecture
#define bfd_mach_nios2 0
#define bfd_mach_nios2r1 1
#define bfd_mach_nios2r2 2
- bfd_arch_lm32, /* Lattice Mico32 */
-#define bfd_mach_lm32 1
bfd_arch_rx, /* Renesas RX */
#define bfd_mach_rx 0x75
#define bfd_mach_rx_v2 0x76
@@ -443,7 +441,6 @@ int print_insn_m32r (bfd_vma, disassemble_info*);
int print_insn_m88k (bfd_vma, disassemble_info*);
int print_insn_mn10200 (bfd_vma, disassemble_info*);
int print_insn_mn10300 (bfd_vma, disassemble_info*);
-int print_insn_moxie (bfd_vma, disassemble_info*);
int print_insn_ns32k (bfd_vma, disassemble_info*);
int print_insn_big_powerpc (bfd_vma, disassemble_info*);
int print_insn_little_powerpc (bfd_vma, disassemble_info*);
@@ -458,7 +455,6 @@ int print_insn_crisv32 (bfd_vma, disassemble_info*);
int print_insn_crisv10 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
-int print_insn_lm32 (bfd_vma, disassemble_info*);
int print_insn_big_nios2 (bfd_vma, disassemble_info*);
int print_insn_little_nios2 (bfd_vma, disassemble_info*);
int print_insn_xtensa (bfd_vma, disassemble_info*);
diff --git a/include/elf.h b/include/elf.h
index 78237c9a87..033bcc9576 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -174,9 +174,8 @@ typedef struct mips_elf_abiflags_v0 {
#define EM_OPENRISC 92 /* OpenCores OpenRISC */
-#define EM_UNICORE32 110 /* UniCore32 */
-
#define EM_HEXAGON 164 /* Qualcomm Hexagon */
+
#define EM_RX 173 /* Renesas RX family */
#define EM_RISCV 243 /* RISC-V */
@@ -206,9 +205,6 @@ typedef struct mips_elf_abiflags_v0 {
#define EM_AARCH64 183
-#define EM_MOXIE 223 /* Moxie processor family */
-#define EM_MOXIE_OLD 0xFEED
-
#define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */
/* This is the info that is needed to parse the dynamic section of the file */
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 5a0a2d93e0..ccabed4003 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -57,6 +57,7 @@ const char *qemu_ram_get_idstr(RAMBlock *rb);
void *qemu_ram_get_host_addr(RAMBlock *rb);
ram_addr_t qemu_ram_get_offset(RAMBlock *rb);
ram_addr_t qemu_ram_get_used_length(RAMBlock *rb);
+ram_addr_t qemu_ram_get_max_length(RAMBlock *rb);
bool qemu_ram_is_shared(RAMBlock *rb);
bool qemu_ram_is_uf_zeroable(RAMBlock *rb);
void qemu_ram_set_uf_zeroable(RAMBlock *rb);
diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index 298e01eef4..467529d84c 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -1,6 +1,7 @@
#ifndef GEN_ICOUNT_H
#define GEN_ICOUNT_H
+#include "exec/exec-all.h"
#include "qemu/timer.h"
/* Helpers for instruction counting code generation. */
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 5728a681b2..c8b9088924 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -131,7 +131,7 @@ typedef struct IOMMUTLBEvent {
#define RAM_SHARED (1 << 1)
/* Only a portion of RAM (used_length) is actually used, and migrated.
- * This used_length size can change across reboots.
+ * Resizing RAM while migrating can result in the migration being canceled.
*/
#define RAM_RESIZEABLE (1 << 2)
@@ -955,7 +955,9 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr,
* RAM. Accesses into the region will
* modify memory directly. Only an initial
* portion of this RAM is actually used.
- * The used size can change across reboots.
+ * Changing the size while migrating
+ * can result in the migration being
+ * canceled.
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
@@ -1586,8 +1588,8 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr);
/* memory_region_ram_resize: Resize a RAM region.
*
- * Only legal before guest might have detected the memory size: e.g. on
- * incoming migration, or right after reset.
+ * Resizing RAM while migrating can result in the migration being canceled.
+ * Care has to be taken if the guest might have already detected the memory.
*
* @mr: a memory region created with @memory_region_init_resizeable_ram.
* @newsize: the new size the region
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 4cd3f8abb4..7ad4ad18e8 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -4,6 +4,8 @@
#ifndef HW_POISON_H
#define HW_POISON_H
+#include "config-poison.h"
+
#pragma GCC poison TARGET_I386
#pragma GCC poison TARGET_X86_64
#pragma GCC poison TARGET_AARCH64
@@ -12,7 +14,6 @@
#pragma GCC poison TARGET_CRIS
#pragma GCC poison TARGET_HEXAGON
#pragma GCC poison TARGET_HPPA
-#pragma GCC poison TARGET_LM32
#pragma GCC poison TARGET_M68K
#pragma GCC poison TARGET_MICROBLAZE
#pragma GCC poison TARGET_MIPS
@@ -20,7 +21,6 @@
#pragma GCC poison TARGET_ABI_MIPSO32
#pragma GCC poison TARGET_MIPS64
#pragma GCC poison TARGET_ABI_MIPSN64
-#pragma GCC poison TARGET_MOXIE
#pragma GCC poison TARGET_NIOS2
#pragma GCC poison TARGET_OPENRISC
#pragma GCC poison TARGET_PPC
@@ -32,7 +32,6 @@
#pragma GCC poison TARGET_SPARC
#pragma GCC poison TARGET_SPARC64
#pragma GCC poison TARGET_TRICORE
-#pragma GCC poison TARGET_UNICORE32
#pragma GCC poison TARGET_XTENSA
#pragma GCC poison TARGET_ALIGNED_ONLY
@@ -74,12 +73,10 @@
#pragma GCC poison CONFIG_HPPA_DIS
#pragma GCC poison CONFIG_I386_DIS
#pragma GCC poison CONFIG_HEXAGON_DIS
-#pragma GCC poison CONFIG_LM32_DIS
#pragma GCC poison CONFIG_M68K_DIS
#pragma GCC poison CONFIG_MICROBLAZE_DIS
#pragma GCC poison CONFIG_MIPS_DIS
#pragma GCC poison CONFIG_NANOMIPS_DIS
-#pragma GCC poison CONFIG_MOXIE_DIS
#pragma GCC poison CONFIG_NIOS2_DIS
#pragma GCC poison CONFIG_PPC_DIS
#pragma GCC poison CONFIG_RISCV_DIS
@@ -88,8 +85,12 @@
#pragma GCC poison CONFIG_SPARC_DIS
#pragma GCC poison CONFIG_XTENSA_DIS
+#pragma GCC poison CONFIG_HAX
+#pragma GCC poison CONFIG_HVF
#pragma GCC poison CONFIG_LINUX_USER
#pragma GCC poison CONFIG_KVM
#pragma GCC poison CONFIG_SOFTMMU
+#pragma GCC poison CONFIG_WHPX
+#pragma GCC poison CONFIG_XEN
#endif
diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h
index 07d50864d8..664701b759 100644
--- a/include/exec/ramblock.h
+++ b/include/exec/ramblock.h
@@ -59,6 +59,16 @@ struct RAMBlock {
*/
unsigned long *clear_bmap;
uint8_t clear_bmap_shift;
+
+ /*
+ * RAM block length that corresponds to the used_length on the migration
+ * source (after RAM block sizes were synchronized). Especially, after
+ * starting to run the guest, used_length and postcopy_length can differ.
+ * Used to register/unregister uffd handlers and as the size of the received
+ * bitmap. Receiving any page beyond this length will bail out, as it
+ * could not have been valid on the source.
+ */
+ ram_addr_t postcopy_length;
};
#endif
#endif
diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h
index 26704aa3b0..ece6497ee2 100644
--- a/include/exec/ramlist.h
+++ b/include/exec/ramlist.h
@@ -65,15 +65,20 @@ void qemu_mutex_lock_ramlist(void);
void qemu_mutex_unlock_ramlist(void);
struct RAMBlockNotifier {
- void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size);
- void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size);
+ void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size,
+ size_t max_size);
+ void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size,
+ size_t max_size);
+ void (*ram_block_resized)(RAMBlockNotifier *n, void *host, size_t old_size,
+ size_t new_size);
QLIST_ENTRY(RAMBlockNotifier) next;
};
void ram_block_notifier_add(RAMBlockNotifier *n);
void ram_block_notifier_remove(RAMBlockNotifier *n);
-void ram_block_notify_add(void *host, size_t size);
-void ram_block_notify_remove(void *host, size_t size);
+void ram_block_notify_add(void *host, size_t size, size_t max_size);
+void ram_block_notify_remove(void *host, size_t size, size_t max_size);
+void ram_block_notify_resize(void *host, size_t old_size, size_t new_size);
void ram_block_dump(Monitor *mon);
diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h
index a35ec2893a..ec4e27a595 100644
--- a/include/fpu/softfloat-macros.h
+++ b/include/fpu/softfloat-macros.h
@@ -83,6 +83,43 @@ this code that are retained.
#define FPU_SOFTFLOAT_MACROS_H
#include "fpu/softfloat-types.h"
+#include "qemu/host-utils.h"
+
+/**
+ * shl_double: double-word merging left shift
+ * @l: left or most-significant word
+ * @r: right or least-significant word
+ * @c: shift count
+ *
+ * Shift @l left by @c bits, shifting in bits from @r.
+ */
+static inline uint64_t shl_double(uint64_t l, uint64_t r, int c)
+{
+#if defined(__x86_64__)
+ asm("shld %b2, %1, %0" : "+r"(l) : "r"(r), "ci"(c));
+ return l;
+#else
+ return c ? (l << c) | (r >> (64 - c)) : l;
+#endif
+}
+
+/**
+ * shr_double: double-word merging right shift
+ * @l: left or most-significant word
+ * @r: right or least-significant word
+ * @c: shift count
+ *
+ * Shift @r right by @c bits, shifting in bits from @l.
+ */
+static inline uint64_t shr_double(uint64_t l, uint64_t r, int c)
+{
+#if defined(__x86_64__)
+ asm("shrd %b2, %1, %0" : "+r"(r) : "r"(l), "ci"(c));
+ return r;
+#else
+ return c ? (r >> c) | (l << (64 - c)) : r;
+#endif
+}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
@@ -403,16 +440,12 @@ static inline void
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
-static inline void
- add128(
- uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
+static inline void add128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1,
+ uint64_t *z0Ptr, uint64_t *z1Ptr)
{
- uint64_t z1;
-
- z1 = a1 + b1;
- *z1Ptr = z1;
- *z0Ptr = a0 + b0 + ( z1 < a1 );
-
+ bool c = 0;
+ *z1Ptr = uadd64_carry(a1, b1, &c);
+ *z0Ptr = uadd64_carry(a0, b0, &c);
}
/*----------------------------------------------------------------------------
@@ -423,34 +456,14 @@ static inline void
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
-static inline void
- add192(
- uint64_t a0,
- uint64_t a1,
- uint64_t a2,
- uint64_t b0,
- uint64_t b1,
- uint64_t b2,
- uint64_t *z0Ptr,
- uint64_t *z1Ptr,
- uint64_t *z2Ptr
- )
+static inline void add192(uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t b0, uint64_t b1, uint64_t b2,
+ uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr)
{
- uint64_t z0, z1, z2;
- int8_t carry0, carry1;
-
- z2 = a2 + b2;
- carry1 = ( z2 < a2 );
- z1 = a1 + b1;
- carry0 = ( z1 < a1 );
- z0 = a0 + b0;
- z1 += carry1;
- z0 += ( z1 < carry1 );
- z0 += carry0;
- *z2Ptr = z2;
- *z1Ptr = z1;
- *z0Ptr = z0;
-
+ bool c = 0;
+ *z2Ptr = uadd64_carry(a2, b2, &c);
+ *z1Ptr = uadd64_carry(a1, b1, &c);
+ *z0Ptr = uadd64_carry(a0, b0, &c);
}
/*----------------------------------------------------------------------------
@@ -461,14 +474,12 @@ static inline void
| `z1Ptr'.
*----------------------------------------------------------------------------*/
-static inline void
- sub128(
- uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr )
+static inline void sub128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1,
+ uint64_t *z0Ptr, uint64_t *z1Ptr)
{
-
- *z1Ptr = a1 - b1;
- *z0Ptr = a0 - b0 - ( a1 < b1 );
-
+ bool c = 0;
+ *z1Ptr = usub64_borrow(a1, b1, &c);
+ *z0Ptr = usub64_borrow(a0, b0, &c);
}
/*----------------------------------------------------------------------------
@@ -479,34 +490,14 @@ static inline void
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
-static inline void
- sub192(
- uint64_t a0,
- uint64_t a1,
- uint64_t a2,
- uint64_t b0,
- uint64_t b1,
- uint64_t b2,
- uint64_t *z0Ptr,
- uint64_t *z1Ptr,
- uint64_t *z2Ptr
- )
+static inline void sub192(uint64_t a0, uint64_t a1, uint64_t a2,
+ uint64_t b0, uint64_t b1, uint64_t b2,
+ uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr)
{
- uint64_t z0, z1, z2;
- int8_t borrow0, borrow1;
-
- z2 = a2 - b2;
- borrow1 = ( a2 < b2 );
- z1 = a1 - b1;
- borrow0 = ( a1 < b1 );
- z0 = a0 - b0;
- z0 -= ( z1 < borrow1 );
- z1 -= borrow1;
- z0 -= borrow0;
- *z2Ptr = z2;
- *z1Ptr = z1;
- *z0Ptr = z0;
-
+ bool c = 0;
+ *z2Ptr = usub64_borrow(a2, b2, &c);
+ *z1Ptr = usub64_borrow(a1, b1, &c);
+ *z0Ptr = usub64_borrow(a0, b0, &c);
}
/*----------------------------------------------------------------------------
@@ -515,27 +506,10 @@ static inline void
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
-static inline void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr )
+static inline void
+mul64To128(uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr)
{
- uint32_t aHigh, aLow, bHigh, bLow;
- uint64_t z0, zMiddleA, zMiddleB, z1;
-
- aLow = a;
- aHigh = a>>32;
- bLow = b;
- bHigh = b>>32;
- z1 = ( (uint64_t) aLow ) * bLow;
- zMiddleA = ( (uint64_t) aLow ) * bHigh;
- zMiddleB = ( (uint64_t) aHigh ) * bLow;
- z0 = ( (uint64_t) aHigh ) * bHigh;
- zMiddleA += zMiddleB;
- z0 += ( ( (uint64_t) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
- zMiddleA <<= 32;
- z1 += zMiddleA;
- z0 += ( z1 < zMiddleA );
- *z1Ptr = z1;
- *z0Ptr = z0;
-
+ mulu64(z1Ptr, z0Ptr, a, b);
}
/*----------------------------------------------------------------------------
@@ -546,24 +520,14 @@ static inline void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t
*----------------------------------------------------------------------------*/
static inline void
- mul128By64To192(
- uint64_t a0,
- uint64_t a1,
- uint64_t b,
- uint64_t *z0Ptr,
- uint64_t *z1Ptr,
- uint64_t *z2Ptr
- )
+mul128By64To192(uint64_t a0, uint64_t a1, uint64_t b,
+ uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr)
{
- uint64_t z0, z1, z2, more1;
-
- mul64To128( a1, b, &z1, &z2 );
- mul64To128( a0, b, &z0, &more1 );
- add128( z0, more1, 0, z1, &z0, &z1 );
- *z2Ptr = z2;
- *z1Ptr = z1;
- *z0Ptr = z0;
+ uint64_t z0, z1, m1;
+ mul64To128(a1, b, &m1, z2Ptr);
+ mul64To128(a0, b, &z0, &z1);
+ add128(z0, z1, 0, m1, z0Ptr, z1Ptr);
}
/*----------------------------------------------------------------------------
@@ -573,34 +537,21 @@ static inline void
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
-static inline void
- mul128To256(
- uint64_t a0,
- uint64_t a1,
- uint64_t b0,
- uint64_t b1,
- uint64_t *z0Ptr,
- uint64_t *z1Ptr,
- uint64_t *z2Ptr,
- uint64_t *z3Ptr
- )
+static inline void mul128To256(uint64_t a0, uint64_t a1,
+ uint64_t b0, uint64_t b1,
+ uint64_t *z0Ptr, uint64_t *z1Ptr,
+ uint64_t *z2Ptr, uint64_t *z3Ptr)
{
- uint64_t z0, z1, z2, z3;
- uint64_t more1, more2;
-
- mul64To128( a1, b1, &z2, &z3 );
- mul64To128( a1, b0, &z1, &more2 );
- add128( z1, more2, 0, z2, &z1, &z2 );
- mul64To128( a0, b0, &z0, &more1 );
- add128( z0, more1, 0, z1, &z0, &z1 );
- mul64To128( a0, b1, &more1, &more2 );
- add128( more1, more2, 0, z2, &more1, &z2 );
- add128( z0, z1, 0, more1, &z0, &z1 );
- *z3Ptr = z3;
- *z2Ptr = z2;
- *z1Ptr = z1;
- *z0Ptr = z0;
+ uint64_t z0, z1, z2;
+ uint64_t m0, m1, m2, n1, n2;
+
+ mul64To128(a1, b0, &m1, &m2);
+ mul64To128(a0, b1, &n1, &n2);
+ mul64To128(a1, b1, &z2, z3Ptr);
+ mul64To128(a0, b0, &z0, &z1);
+ add192( 0, m1, m2, 0, n1, n2, &m0, &m1, &m2);
+ add192(m0, m1, m2, z0, z1, z2, z0Ptr, z1Ptr, z2Ptr);
}
/*----------------------------------------------------------------------------
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 78ad5ca738..53f2c2ea3c 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -100,7 +100,10 @@ typedef enum {
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
-void float_raise(uint8_t flags, float_status *status);
+static inline void float_raise(uint8_t flags, float_status *status)
+{
+ status->float_exception_flags |= flags;
+}
/*----------------------------------------------------------------------------
| If `a' is denormal and we are in flush-to-zero mode then set the
@@ -1194,6 +1197,8 @@ float128 float128_round_to_int(float128, float_status *status);
float128 float128_add(float128, float128, float_status *status);
float128 float128_sub(float128, float128, float_status *status);
float128 float128_mul(float128, float128, float_status *status);
+float128 float128_muladd(float128, float128, float128, int,
+ float_status *status);
float128 float128_div(float128, float128, float_status *status);
float128 float128_rem(float128, float128, float_status *status);
float128 float128_sqrt(float128, float_status *status);
diff --git a/include/hw/char/lm32_juart.h b/include/hw/char/lm32_juart.h
deleted file mode 100644
index 6fce278326..0000000000
--- a/include/hw/char/lm32_juart.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef QEMU_HW_CHAR_LM32_JUART_H
-#define QEMU_HW_CHAR_LM32_JUART_H
-
-#include "hw/qdev-core.h"
-
-#define TYPE_LM32_JUART "lm32-juart"
-
-uint32_t lm32_juart_get_jtx(DeviceState *d);
-uint32_t lm32_juart_get_jrx(DeviceState *d);
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
-
-#endif /* QEMU_HW_CHAR_LM32_JUART_H */
diff --git a/include/hw/char/shakti_uart.h b/include/hw/char/shakti_uart.h
new file mode 100644
index 0000000000..526c408233
--- /dev/null
+++ b/include/hw/char/shakti_uart.h
@@ -0,0 +1,74 @@
+/*
+ * SHAKTI UART
+ *
+ * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ * 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 HW_SHAKTI_UART_H
+#define HW_SHAKTI_UART_H
+
+#include "hw/sysbus.h"
+#include "chardev/char-fe.h"
+
+#define SHAKTI_UART_BAUD 0x00
+#define SHAKTI_UART_TX 0x04
+#define SHAKTI_UART_RX 0x08
+#define SHAKTI_UART_STATUS 0x0C
+#define SHAKTI_UART_DELAY 0x10
+#define SHAKTI_UART_CONTROL 0x14
+#define SHAKTI_UART_INT_EN 0x18
+#define SHAKTI_UART_IQ_CYCLES 0x1C
+#define SHAKTI_UART_RX_THRES 0x20
+
+#define SHAKTI_UART_STATUS_TX_EMPTY (1 << 0)
+#define SHAKTI_UART_STATUS_TX_FULL (1 << 1)
+#define SHAKTI_UART_STATUS_RX_NOT_EMPTY (1 << 2)
+#define SHAKTI_UART_STATUS_RX_FULL (1 << 3)
+/* 9600 8N1 is the default setting */
+/* Reg value = (50000000 Hz)/(16 * 9600)*/
+#define SHAKTI_UART_BAUD_DEFAULT 0x0145
+#define SHAKTI_UART_CONTROL_DEFAULT 0x0100
+
+#define TYPE_SHAKTI_UART "shakti-uart"
+#define SHAKTI_UART(obj) \
+ OBJECT_CHECK(ShaktiUartState, (obj), TYPE_SHAKTI_UART)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion mmio;
+
+ uint32_t uart_baud;
+ uint32_t uart_tx;
+ uint32_t uart_rx;
+ uint32_t uart_status;
+ uint32_t uart_delay;
+ uint32_t uart_control;
+ uint32_t uart_interrupt;
+ uint32_t uart_iq_cycles;
+ uint32_t uart_rx_threshold;
+
+ CharBackend chr;
+} ShaktiUartState;
+
+#endif /* HW_SHAKTI_UART_H */
diff --git a/include/hw/core/accel-cpu.h b/include/hw/core/accel-cpu.h
index 24a6697412..5dbfd79955 100644
--- a/include/hw/core/accel-cpu.h
+++ b/include/hw/core/accel-cpu.h
@@ -32,7 +32,7 @@ typedef struct AccelCPUClass {
void (*cpu_class_init)(CPUClass *cc);
void (*cpu_instance_init)(CPUState *cpu);
- void (*cpu_realizefn)(CPUState *cpu, Error **errp);
+ bool (*cpu_realizefn)(CPUState *cpu, Error **errp);
} AccelCPUClass;
#endif /* ACCEL_CPU_H */
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index c68bc3ba8a..d45f78290e 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -192,6 +192,12 @@ struct CPUClass {
/* when TCG is not available, this pointer is NULL */
struct TCGCPUOps *tcg_ops;
+
+ /*
+ * if not NULL, this is called in order for the CPUClass to initialize
+ * class data that depends on the accelerator, see accel/accel-common.c.
+ */
+ void (*init_accel_cpu)(struct AccelCPUClass *accel_cpu, CPUClass *cc);
};
/*
diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h
index 1f8fc9b375..520f8ec202 100644
--- a/include/hw/display/edid.h
+++ b/include/hw/display/edid.h
@@ -11,6 +11,7 @@ typedef struct qemu_edid_info {
uint32_t prefy;
uint32_t maxx;
uint32_t maxy;
+ uint32_t refresh_rate;
} qemu_edid_info;
void qemu_edid_generate(uint8_t *edid, size_t size,
@@ -21,10 +22,11 @@ void qemu_edid_region_io(MemoryRegion *region, Object *owner,
uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res);
-#define DEFINE_EDID_PROPERTIES(_state, _edid_info) \
- DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \
- DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \
- DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \
- DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0)
+#define DEFINE_EDID_PROPERTIES(_state, _edid_info) \
+ DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \
+ DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \
+ DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \
+ DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0), \
+ DEFINE_PROP_UINT32("refresh_rate", _state, _edid_info.refresh_rate, 0)
#endif /* EDID_H */
diff --git a/include/hw/display/milkymist_tmu2.h b/include/hw/display/milkymist_tmu2.h
deleted file mode 100644
index fdce9535a1..0000000000
--- a/include/hw/display/milkymist_tmu2.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * QEMU model of the Milkymist texture mapping unit.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- * Copyright (c) 2010 Sebastien Bourdeauducq
- * <sebastien.bourdeauducq@lekernel.net>
- *
- * 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.1 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/>.
- *
- *
- * Specification available at:
- * http://milkymist.walle.cc/socdoc/tmu2.pdf
- *
- */
-
-#ifndef HW_DISPLAY_MILKYMIST_TMU2_H
-#define HW_DISPLAY_MILKYMIST_TMU2_H
-
-#include "exec/hwaddr.h"
-#include "hw/qdev-core.h"
-
-#if defined(CONFIG_X11) && defined(CONFIG_OPENGL)
-DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq);
-#else
-static inline DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq)
-{
- return NULL;
-}
-#endif
-
-#endif /* HW_DISPLAY_MILKYMIST_TMU2_H */
diff --git a/include/hw/display/vga.h b/include/hw/display/vga.h
index ca0003dbfd..5f7825e0e3 100644
--- a/include/hw/display/vga.h
+++ b/include/hw/display/vga.h
@@ -11,6 +11,12 @@
#include "exec/hwaddr.h"
+/*
+ * modules can reference this symbol to avoid being loaded
+ * into system emulators without vga support
+ */
+extern bool have_vga;
+
enum vga_retrace_method {
VGA_RETRACE_DUMB,
VGA_RETRACE_PRECISE
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index 6ee458e7bc..1c37cec4ae 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -368,14 +368,6 @@ static int glue(load_elf, SZ)(const char *name, int fd,
}
}
break;
- case EM_MOXIE:
- if (ehdr.e_machine != EM_MOXIE) {
- if (ehdr.e_machine != EM_MOXIE_OLD) {
- ret = ELF_LOAD_WRONG_ARCH;
- goto fail;
- }
- }
- break;
case EM_MIPS:
case EM_NANOMIPS:
if ((ehdr.e_machine != EM_MIPS) &&
diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h
index 02a0ced0a0..5a0dd0c8cf 100644
--- a/include/hw/firmware/smbios.h
+++ b/include/hw/firmware/smbios.h
@@ -258,6 +258,17 @@ struct smbios_type_32 {
uint8_t boot_status;
} QEMU_PACKED;
+/* SMBIOS type 41 - Onboard Devices Extended Information */
+struct smbios_type_41 {
+ struct smbios_structure_header header;
+ uint8_t reference_designation_str;
+ uint8_t device_type;
+ uint8_t device_type_instance;
+ uint16_t segment_group_number;
+ uint8_t bus_number;
+ uint8_t device_number;
+} QEMU_PACKED;
+
/* SMBIOS type 127 -- End-of-table */
struct smbios_type_127 {
struct smbios_structure_header header;
@@ -273,5 +284,6 @@ void smbios_get_tables(MachineState *ms,
const struct smbios_phys_mem_area *mem_array,
const unsigned int mem_array_size,
uint8_t **tables, size_t *tables_len,
- uint8_t **anchor, size_t *anchor_len);
+ uint8_t **anchor, size_t *anchor_len,
+ Error **errp);
#endif /* QEMU_SMBIOS_H */
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 277dd9f2d6..ff4129ea70 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -16,6 +16,7 @@ enum i2c_event {
I2C_NACK /* Masker NACKed a receive byte. */
};
+typedef struct I2CNodeList I2CNodeList;
#define TYPE_I2C_SLAVE "i2c-slave"
OBJECT_DECLARE_TYPE(I2CSlave, I2CSlaveClass,
@@ -39,6 +40,16 @@ struct I2CSlaveClass {
* return code is not used and should be zero.
*/
int (*event)(I2CSlave *s, enum i2c_event event);
+
+ /*
+ * Check if this device matches the address provided. Returns bool of
+ * true if it matches (or broadcast), and updates the device list, false
+ * otherwise.
+ *
+ * If broadcast is true, match should add the device and return true.
+ */
+ bool (*match_and_add)(I2CSlave *candidate, uint8_t address, bool broadcast,
+ I2CNodeList *current_devs);
};
struct I2CSlave {
@@ -58,9 +69,11 @@ struct I2CNode {
QLIST_ENTRY(I2CNode) next;
};
+typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList;
+
struct I2CBus {
BusState qbus;
- QLIST_HEAD(, I2CNode) current_devs;
+ I2CNodeList current_devs;
uint8_t saved_address;
bool broadcast;
};
@@ -74,6 +87,8 @@ void i2c_nack(I2CBus *bus);
int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send);
int i2c_send(I2CBus *bus, uint8_t data);
uint8_t i2c_recv(I2CBus *bus);
+bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast,
+ I2CNodeList *current_devs);
/**
* Create an I2C slave device on the heap.
diff --git a/include/hw/i2c/i2c_mux_pca954x.h b/include/hw/i2c/i2c_mux_pca954x.h
new file mode 100644
index 0000000000..8aaf9bbc39
--- /dev/null
+++ b/include/hw/i2c/i2c_mux_pca954x.h
@@ -0,0 +1,19 @@
+#ifndef QEMU_I2C_MUX_PCA954X
+#define QEMU_I2C_MUX_PCA954X
+
+#include "hw/i2c/i2c.h"
+
+#define TYPE_PCA9546 "pca9546"
+#define TYPE_PCA9548 "pca9548"
+
+/**
+ * Retrieves the i2c bus associated with the specified channel on this i2c
+ * mux.
+ * @mux: an i2c mux device.
+ * @channel: the i2c channel requested
+ *
+ * Returns: a pointer to the associated i2c bus.
+ */
+I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel);
+
+#endif
diff --git a/include/hw/lm32/lm32_pic.h b/include/hw/lm32/lm32_pic.h
deleted file mode 100644
index 9e5e038437..0000000000
--- a/include/hw/lm32/lm32_pic.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef QEMU_HW_LM32_PIC_H
-#define QEMU_HW_LM32_PIC_H
-
-
-uint32_t lm32_pic_get_ip(DeviceState *d);
-uint32_t lm32_pic_get_im(DeviceState *d);
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
-void lm32_pic_set_im(DeviceState *d, uint32_t im);
-
-#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h
index 3d3db82641..1473e6db62 100644
--- a/include/hw/mem/pc-dimm.h
+++ b/include/hw/mem/pc-dimm.h
@@ -56,9 +56,6 @@ struct PCDIMMDevice {
* PCDIMMDeviceClass:
* @realize: called after common dimm is realized so that the dimm based
* devices get the chance to do specified operations.
- * @get_vmstate_memory_region: returns #MemoryRegion which indicates the
- * memory of @dimm should be kept during live migration. Will not fail
- * after the device was realized.
*/
struct PCDIMMDeviceClass {
/* private */
@@ -66,8 +63,6 @@ struct PCDIMMDeviceClass {
/* public */
void (*realize)(PCDIMMDevice *dimm, Error **errp);
- MemoryRegion *(*get_vmstate_memory_region)(PCDIMMDevice *dimm,
- Error **errp);
};
void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine,
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 7f40a158f4..bbf817af46 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -582,6 +582,12 @@ typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
target_ulong *args);
+target_ulong softmmu_resize_hpt_prepare(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong shift);
+target_ulong softmmu_resize_hpt_commit(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong flags, target_ulong shift);
+bool is_ram_address(SpaprMachineState *spapr, hwaddr addr);
+void push_sregs_to_kvm_pr(SpaprMachineState *spapr);
/* Virtual Processor Area structure constants */
#define VPA_MIN_SIZE 640
@@ -821,6 +827,7 @@ void spapr_dt_events(SpaprMachineState *sm, void *fdt);
void close_htab_fd(SpaprMachineState *spapr);
void spapr_setup_hpt(SpaprMachineState *spapr);
void spapr_free_hpt(SpaprMachineState *spapr);
+void spapr_check_mmu_mode(bool guest_radix);
SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
void spapr_tce_table_enable(SpaprTceTable *tcet,
uint32_t page_shift, uint64_t bus_offset,
diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h
index a5ea3a5e4e..aab9bc9245 100644
--- a/include/hw/riscv/opentitan.h
+++ b/include/hw/riscv/opentitan.h
@@ -82,14 +82,14 @@ enum {
};
enum {
- IBEX_UART_RX_PARITY_ERR_IRQ = 0x28,
- IBEX_UART_RX_TIMEOUT_IRQ = 0x27,
- IBEX_UART_RX_BREAK_ERR_IRQ = 0x26,
- IBEX_UART_RX_FRAME_ERR_IRQ = 0x25,
- IBEX_UART_RX_OVERFLOW_IRQ = 0x24,
- IBEX_UART_TX_EMPTY_IRQ = 0x23,
- IBEX_UART_RX_WATERMARK_IRQ = 0x22,
- IBEX_UART_TX_WATERMARK_IRQ = 0x21,
+ IBEX_UART0_RX_PARITY_ERR_IRQ = 8,
+ IBEX_UART0_RX_TIMEOUT_IRQ = 7,
+ IBEX_UART0_RX_BREAK_ERR_IRQ = 6,
+ IBEX_UART0_RX_FRAME_ERR_IRQ = 5,
+ IBEX_UART0_RX_OVERFLOW_IRQ = 4,
+ IBEX_UART0_TX_EMPTY_IRQ = 3,
+ IBEX_UART0_RX_WATERMARK_IRQ = 2,
+ IBEX_UART0_TX_WATERMARK_IRQ = 1,
};
#endif
diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h
new file mode 100644
index 0000000000..50a2b79086
--- /dev/null
+++ b/include/hw/riscv/shakti_c.h
@@ -0,0 +1,75 @@
+/*
+ * Shakti C-class SoC emulation
+ *
+ * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
+ *
+ * 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/>.
+ */
+
+#ifndef HW_SHAKTI_H
+#define HW_SHAKTI_H
+
+#include "hw/riscv/riscv_hart.h"
+#include "hw/boards.h"
+#include "hw/char/shakti_uart.h"
+
+#define TYPE_RISCV_SHAKTI_SOC "riscv.shakti.cclass.soc"
+#define RISCV_SHAKTI_SOC(obj) \
+ OBJECT_CHECK(ShaktiCSoCState, (obj), TYPE_RISCV_SHAKTI_SOC)
+
+typedef struct ShaktiCSoCState {
+ /*< private >*/
+ DeviceState parent_obj;
+
+ /*< public >*/
+ RISCVHartArrayState cpus;
+ DeviceState *plic;
+ ShaktiUartState uart;
+ MemoryRegion rom;
+
+} ShaktiCSoCState;
+
+#define TYPE_RISCV_SHAKTI_MACHINE MACHINE_TYPE_NAME("shakti_c")
+#define RISCV_SHAKTI_MACHINE(obj) \
+ OBJECT_CHECK(ShaktiCMachineState, (obj), TYPE_RISCV_SHAKTI_MACHINE)
+typedef struct ShaktiCMachineState {
+ /*< private >*/
+ MachineState parent_obj;
+
+ /*< public >*/
+ ShaktiCSoCState soc;
+} ShaktiCMachineState;
+
+enum {
+ SHAKTI_C_ROM,
+ SHAKTI_C_RAM,
+ SHAKTI_C_UART,
+ SHAKTI_C_GPIO,
+ SHAKTI_C_PLIC,
+ SHAKTI_C_CLINT,
+ SHAKTI_C_I2C,
+};
+
+#define SHAKTI_C_PLIC_HART_CONFIG "MS"
+/* Including Interrupt ID 0 (no interrupt)*/
+#define SHAKTI_C_PLIC_NUM_SOURCES 28
+/* Excluding Priority 0 */
+#define SHAKTI_C_PLIC_NUM_PRIORITIES 2
+#define SHAKTI_C_PLIC_PRIORITY_BASE 0x04
+#define SHAKTI_C_PLIC_PENDING_BASE 0x1000
+#define SHAKTI_C_PLIC_ENABLE_BASE 0x2000
+#define SHAKTI_C_PLIC_ENABLE_STRIDE 0x80
+#define SHAKTI_C_PLIC_CONTEXT_BASE 0x200000
+#define SHAKTI_C_PLIC_CONTEXT_STRIDE 0x1000
+
+#endif
diff --git a/include/hw/tricore/tricore_testdevice.h b/include/hw/tricore/tricore_testdevice.h
new file mode 100644
index 0000000000..2c56c51bcb
--- /dev/null
+++ b/include/hw/tricore/tricore_testdevice.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018-2021 Bastian Koppelmann Paderborn University
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef HW_TRICORE_TESTDEV_H
+#define HW_TRICORE_TESTDEV_H
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+
+#define TYPE_TRICORE_TESTDEVICE "tricore_testdevice"
+#define TRICORE_TESTDEVICE(obj) \
+ OBJECT_CHECK(TriCoreTestDeviceState, (obj), TYPE_TRICORE_TESTDEVICE)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+
+} TriCoreTestDeviceState;
+
+#endif
diff --git a/include/hw/unicore32/puv3.h b/include/hw/unicore32/puv3.h
deleted file mode 100644
index f587a1f622..0000000000
--- a/include/hw/unicore32/puv3.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Misc PKUnity SoC declarations
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef QEMU_HW_PUV3_H
-#define QEMU_HW_PUV3_H
-
-#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */
-
-/* Hardware interrupts */
-#define PUV3_IRQS_NR (32)
-
-#define PUV3_IRQS_GPIOLOW0 (0)
-#define PUV3_IRQS_GPIOLOW1 (1)
-#define PUV3_IRQS_GPIOLOW2 (2)
-#define PUV3_IRQS_GPIOLOW3 (3)
-#define PUV3_IRQS_GPIOLOW4 (4)
-#define PUV3_IRQS_GPIOLOW5 (5)
-#define PUV3_IRQS_GPIOLOW6 (6)
-#define PUV3_IRQS_GPIOLOW7 (7)
-#define PUV3_IRQS_GPIOHIGH (8)
-#define PUV3_IRQS_PS2_KBD (22)
-#define PUV3_IRQS_PS2_AUX (23)
-#define PUV3_IRQS_OST0 (26)
-
-/* All puv3_*.c use DPRINTF for debug. */
-#ifdef DEBUG_PUV3
-#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#endif /* QEMU_HW_PUV3_H */
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
index 9b81a409da..28ca65018e 100644
--- a/include/hw/virtio/vhost-vdpa.h
+++ b/include/hw/virtio/vhost-vdpa.h
@@ -22,6 +22,4 @@ typedef struct vhost_vdpa {
} VhostVDPA;
extern AddressSpace address_space_memory;
-extern int vhost_vdpa_get_device_id(struct vhost_dev *dev,
- uint32_t *device_id);
#endif
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 4a8bc75415..21a9a52088 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -74,6 +74,8 @@ struct vhost_dev {
int nvqs;
/* the first virtqueue which would be used by this vhost dev */
int vq_index;
+ /* if non-zero, minimum required value for max_queues */
+ int num_queues;
uint64_t features;
uint64_t acked_features;
uint64_t backend_features;
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index fae149235c..8ca2c55d9a 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -29,7 +29,10 @@ OBJECT_DECLARE_TYPE(VirtIOGPUBase, VirtIOGPUBaseClass,
VIRTIO_GPU_BASE)
#define TYPE_VIRTIO_GPU "virtio-gpu-device"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPU, VIRTIO_GPU)
+OBJECT_DECLARE_TYPE(VirtIOGPU, VirtIOGPUClass, VIRTIO_GPU)
+
+#define TYPE_VIRTIO_GPU_GL "virtio-gpu-gl-device"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL)
#define TYPE_VHOST_USER_GPU "vhost-user-gpu"
OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU)
@@ -108,7 +111,6 @@ struct VirtIOGPUBase {
struct virtio_gpu_config virtio_config;
const GraphicHwOps *hw_ops;
- bool use_virgl_renderer;
int renderer_blocked;
int enable;
@@ -149,8 +151,6 @@ struct VirtIOGPU {
uint64_t hostmem;
bool processing_cmdq;
- bool renderer_inited;
- bool renderer_reset;
QEMUTimer *fence_poll;
QEMUTimer *print_stats;
@@ -163,6 +163,23 @@ struct VirtIOGPU {
} stats;
};
+struct VirtIOGPUClass {
+ VirtIOGPUBaseClass parent;
+
+ void (*handle_ctrl)(VirtIODevice *vdev, VirtQueue *vq);
+ void (*process_cmd)(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd);
+ void (*update_cursor_data)(VirtIOGPU *g,
+ struct virtio_gpu_scanout *s,
+ uint32_t resource_id);
+};
+
+struct VirtIOGPUGL {
+ struct VirtIOGPU parent_obj;
+
+ bool renderer_inited;
+ bool renderer_reset;
+};
+
struct VhostUserGPU {
VirtIOGPUBase parent_obj;
@@ -209,10 +226,17 @@ void virtio_gpu_get_edid(VirtIOGPU *g,
int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
struct virtio_gpu_resource_attach_backing *ab,
struct virtio_gpu_ctrl_command *cmd,
- uint64_t **addr, struct iovec **iov);
+ uint64_t **addr, struct iovec **iov,
+ uint32_t *niov);
void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
struct iovec *iov, uint32_t count);
void virtio_gpu_process_cmdq(VirtIOGPU *g);
+void virtio_gpu_device_realize(DeviceState *qdev, Error **errp);
+void virtio_gpu_reset(VirtIODevice *vdev);
+void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd);
+void virtio_gpu_update_cursor_data(VirtIOGPU *g,
+ struct virtio_gpu_scanout *s,
+ uint32_t resource_id);
/* virtio-gpu-3d.c */
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmio.h
index d4c4c386ab..090f7730e7 100644
--- a/include/hw/virtio/virtio-mmio.h
+++ b/include/hw/virtio/virtio-mmio.h
@@ -49,12 +49,17 @@ typedef struct VirtIOMMIOQueue {
uint32_t used[2];
} VirtIOMMIOQueue;
+#define VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD \
+ (1 << VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT)
+
struct VirtIOMMIOProxy {
/* Generic */
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
bool legacy;
+ uint32_t flags;
/* Guest accessible state needing migration and reset */
uint32_t host_features_sel;
uint32_t guest_features_sel;
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index b7ece7a6a8..8bab9cfb75 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -43,7 +43,7 @@ typedef struct VirtIOFeature {
size_t end;
} VirtIOFeature;
-size_t virtio_feature_get_config_size(VirtIOFeature *features,
+size_t virtio_feature_get_config_size(const VirtIOFeature *features,
uint64_t host_features);
typedef struct VirtQueue VirtQueue;
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 82e56339dd..a8118b41ac 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -134,6 +134,12 @@ static inline xenforeignmemory_resource_handle *xenforeignmemory_map_resource(
return NULL;
}
+static inline int xenforeignmemory_unmap_resource(
+ xenforeignmemory_handle *fmem, xenforeignmemory_resource_handle *fres)
+{
+ return 0;
+}
+
#endif /* CONFIG_XEN_CTRL_INTERFACE_VERSION < 41100 */
#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 41000
diff --git a/include/migration/misc.h b/include/migration/misc.h
index 738675ef52..465906710d 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -37,7 +37,6 @@ void precopy_infrastructure_init(void);
void precopy_add_notifier(NotifierWithReturn *n);
void precopy_remove_notifier(NotifierWithReturn *n);
int precopy_notify(PrecopyNotifyReason reason, Error **errp);
-void precopy_enable_free_page_optimization(void);
void ram_mig_init(void);
void qemu_guest_free_page_hint(void *addr, size_t len);
diff --git a/include/qemu/accel.h b/include/qemu/accel.h
index b9d6d69eb8..4f4c283f6f 100644
--- a/include/qemu/accel.h
+++ b/include/qemu/accel.h
@@ -78,4 +78,17 @@ int accel_init_machine(AccelState *accel, MachineState *ms);
void accel_setup_post(MachineState *ms);
#endif /* !CONFIG_USER_ONLY */
+/**
+ * accel_cpu_instance_init:
+ * @cpu: The CPU that needs to do accel-specific object initializations.
+ */
+void accel_cpu_instance_init(CPUState *cpu);
+
+/**
+ * accel_cpu_realizefn:
+ * @cpu: The CPU that needs to call accel-specific cpu realization.
+ * @errp: currently unused.
+ */
+bool accel_cpu_realizefn(CPUState *cpu, Error **errp);
+
#endif /* QEMU_ACCEL_H */
diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index cdca2991d8..711b221704 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -26,6 +26,7 @@
#ifndef HOST_UTILS_H
#define HOST_UTILS_H
+#include "qemu/compiler.h"
#include "qemu/bswap.h"
#ifdef CONFIG_INT128
@@ -272,6 +273,9 @@ static inline int ctpop64(uint64_t val)
*/
static inline uint8_t revbit8(uint8_t x)
{
+#if __has_builtin(__builtin_bitreverse8)
+ return __builtin_bitreverse8(x);
+#else
/* Assign the correct nibble position. */
x = ((x & 0xf0) >> 4)
| ((x & 0x0f) << 4);
@@ -281,6 +285,7 @@ static inline uint8_t revbit8(uint8_t x)
| ((x & 0x22) << 1)
| ((x & 0x11) << 3);
return x;
+#endif
}
/**
@@ -289,6 +294,9 @@ static inline uint8_t revbit8(uint8_t x)
*/
static inline uint16_t revbit16(uint16_t x)
{
+#if __has_builtin(__builtin_bitreverse16)
+ return __builtin_bitreverse16(x);
+#else
/* Assign the correct byte position. */
x = bswap16(x);
/* Assign the correct nibble position. */
@@ -300,6 +308,7 @@ static inline uint16_t revbit16(uint16_t x)
| ((x & 0x2222) << 1)
| ((x & 0x1111) << 3);
return x;
+#endif
}
/**
@@ -308,6 +317,9 @@ static inline uint16_t revbit16(uint16_t x)
*/
static inline uint32_t revbit32(uint32_t x)
{
+#if __has_builtin(__builtin_bitreverse32)
+ return __builtin_bitreverse32(x);
+#else
/* Assign the correct byte position. */
x = bswap32(x);
/* Assign the correct nibble position. */
@@ -319,6 +331,7 @@ static inline uint32_t revbit32(uint32_t x)
| ((x & 0x22222222u) << 1)
| ((x & 0x11111111u) << 3);
return x;
+#endif
}
/**
@@ -327,6 +340,9 @@ static inline uint32_t revbit32(uint32_t x)
*/
static inline uint64_t revbit64(uint64_t x)
{
+#if __has_builtin(__builtin_bitreverse64)
+ return __builtin_bitreverse64(x);
+#else
/* Assign the correct byte position. */
x = bswap64(x);
/* Assign the correct nibble position. */
@@ -338,6 +354,281 @@ static inline uint64_t revbit64(uint64_t x)
| ((x & 0x2222222222222222ull) << 1)
| ((x & 0x1111111111111111ull) << 3);
return x;
+#endif
+}
+
+/**
+ * sadd32_overflow - addition with overflow indication
+ * @x, @y: addends
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x + @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool sadd32_overflow(int32_t x, int32_t y, int32_t *ret)
+{
+#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
+ return __builtin_add_overflow(x, y, ret);
+#else
+ *ret = x + y;
+ return ((*ret ^ x) & ~(x ^ y)) < 0;
+#endif
+}
+
+/**
+ * sadd64_overflow - addition with overflow indication
+ * @x, @y: addends
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x + @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool sadd64_overflow(int64_t x, int64_t y, int64_t *ret)
+{
+#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
+ return __builtin_add_overflow(x, y, ret);
+#else
+ *ret = x + y;
+ return ((*ret ^ x) & ~(x ^ y)) < 0;
+#endif
+}
+
+/**
+ * uadd32_overflow - addition with overflow indication
+ * @x, @y: addends
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x + @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool uadd32_overflow(uint32_t x, uint32_t y, uint32_t *ret)
+{
+#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
+ return __builtin_add_overflow(x, y, ret);
+#else
+ *ret = x + y;
+ return *ret < x;
+#endif
+}
+
+/**
+ * uadd64_overflow - addition with overflow indication
+ * @x, @y: addends
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x + @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool uadd64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
+{
+#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
+ return __builtin_add_overflow(x, y, ret);
+#else
+ *ret = x + y;
+ return *ret < x;
+#endif
+}
+
+/**
+ * ssub32_overflow - subtraction with overflow indication
+ * @x: Minuend
+ * @y: Subtrahend
+ * @ret: Output for difference
+ *
+ * Computes *@ret = @x - @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool ssub32_overflow(int32_t x, int32_t y, int32_t *ret)
+{
+#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5
+ return __builtin_sub_overflow(x, y, ret);
+#else
+ *ret = x - y;
+ return ((*ret ^ x) & (x ^ y)) < 0;
+#endif
+}
+
+/**
+ * ssub64_overflow - subtraction with overflow indication
+ * @x: Minuend
+ * @y: Subtrahend
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x - @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool ssub64_overflow(int64_t x, int64_t y, int64_t *ret)
+{
+#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5
+ return __builtin_sub_overflow(x, y, ret);
+#else
+ *ret = x - y;
+ return ((*ret ^ x) & (x ^ y)) < 0;
+#endif
+}
+
+/**
+ * usub32_overflow - subtraction with overflow indication
+ * @x: Minuend
+ * @y: Subtrahend
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x - @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool usub32_overflow(uint32_t x, uint32_t y, uint32_t *ret)
+{
+#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5
+ return __builtin_sub_overflow(x, y, ret);
+#else
+ *ret = x - y;
+ return x < y;
+#endif
+}
+
+/**
+ * usub64_overflow - subtraction with overflow indication
+ * @x: Minuend
+ * @y: Subtrahend
+ * @ret: Output for sum
+ *
+ * Computes *@ret = @x - @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
+{
+#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5
+ return __builtin_sub_overflow(x, y, ret);
+#else
+ *ret = x - y;
+ return x < y;
+#endif
+}
+
+/**
+ * smul32_overflow - multiplication with overflow indication
+ * @x, @y: Input multipliers
+ * @ret: Output for product
+ *
+ * Computes *@ret = @x * @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool smul32_overflow(int32_t x, int32_t y, int32_t *ret)
+{
+#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5
+ return __builtin_mul_overflow(x, y, ret);
+#else
+ int64_t z = (int64_t)x * y;
+ *ret = z;
+ return *ret != z;
+#endif
+}
+
+/**
+ * smul64_overflow - multiplication with overflow indication
+ * @x, @y: Input multipliers
+ * @ret: Output for product
+ *
+ * Computes *@ret = @x * @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool smul64_overflow(int64_t x, int64_t y, int64_t *ret)
+{
+#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5
+ return __builtin_mul_overflow(x, y, ret);
+#else
+ uint64_t hi, lo;
+ muls64(&lo, &hi, x, y);
+ *ret = lo;
+ return hi != ((int64_t)lo >> 63);
+#endif
+}
+
+/**
+ * umul32_overflow - multiplication with overflow indication
+ * @x, @y: Input multipliers
+ * @ret: Output for product
+ *
+ * Computes *@ret = @x * @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool umul32_overflow(uint32_t x, uint32_t y, uint32_t *ret)
+{
+#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5
+ return __builtin_mul_overflow(x, y, ret);
+#else
+ uint64_t z = (uint64_t)x * y;
+ *ret = z;
+ return z > UINT32_MAX;
+#endif
+}
+
+/**
+ * umul64_overflow - multiplication with overflow indication
+ * @x, @y: Input multipliers
+ * @ret: Output for product
+ *
+ * Computes *@ret = @x * @y, and returns true if and only if that
+ * value has been truncated.
+ */
+static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
+{
+#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5
+ return __builtin_mul_overflow(x, y, ret);
+#else
+ uint64_t hi;
+ mulu64(ret, &hi, x, y);
+ return hi != 0;
+#endif
+}
+
+/**
+ * uadd64_carry - addition with carry-in and carry-out
+ * @x, @y: addends
+ * @pcarry: in-out carry value
+ *
+ * Computes @x + @y + *@pcarry, placing the carry-out back
+ * into *@pcarry and returning the 64-bit sum.
+ */
+static inline uint64_t uadd64_carry(uint64_t x, uint64_t y, bool *pcarry)
+{
+#if __has_builtin(__builtin_addcll)
+ unsigned long long c = *pcarry;
+ x = __builtin_addcll(x, y, c, &c);
+ *pcarry = c & 1;
+ return x;
+#else
+ bool c = *pcarry;
+ /* This is clang's internal expansion of __builtin_addc. */
+ c = uadd64_overflow(x, c, &x);
+ c |= uadd64_overflow(x, y, &x);
+ *pcarry = c;
+ return x;
+#endif
+}
+
+/**
+ * usub64_borrow - subtraction with borrow-in and borrow-out
+ * @x, @y: addends
+ * @pborrow: in-out borrow value
+ *
+ * Computes @x - @y - *@pborrow, placing the borrow-out back
+ * into *@pborrow and returning the 64-bit sum.
+ */
+static inline uint64_t usub64_borrow(uint64_t x, uint64_t y, bool *pborrow)
+{
+#if __has_builtin(__builtin_subcll)
+ unsigned long long b = *pborrow;
+ x = __builtin_subcll(x, y, b, &b);
+ *pborrow = b & 1;
+ return x;
+#else
+ bool b = *pborrow;
+ b = usub64_overflow(x, b, &x);
+ b |= usub64_overflow(x, y, &x);
+ *pborrow = b;
+ return x;
+#endif
}
/* Host type specific sizes of these routines. */
diff --git a/include/qemu/job.h b/include/qemu/job.h
index efc6fa7544..41162ed494 100644
--- a/include/qemu/job.h
+++ b/include/qemu/job.h
@@ -254,7 +254,7 @@ struct JobDriver {
/**
* If the callback is not NULL, it will be invoked in job_cancel_async
*/
- void (*cancel)(Job *job);
+ void (*cancel)(Job *job, bool force);
/** Called when the job is freed */
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index d6892fd208..98aef5647c 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -234,24 +234,6 @@ void event_notifier_set_handler(EventNotifier *e,
GSource *iohandler_get_g_source(void);
AioContext *iohandler_get_aio_context(void);
-#ifdef CONFIG_POSIX
-/**
- * qemu_add_child_watch: Register a child process for reaping.
- *
- * Under POSIX systems, a parent process must read the exit status of
- * its child processes using waitpid, or the operating system will not
- * free some of the resources attached to that process.
- *
- * This function directs the QEMU main loop to observe a child process
- * and call waitpid as soon as it exits; the watch is then removed
- * automatically. It is useful whenever QEMU forks a child process
- * but will find out about its termination by other means such as a
- * "broken pipe".
- *
- * @pid: The pid that QEMU should observe.
- */
-int qemu_add_child_watch(pid_t pid);
-#endif
/**
* qemu_mutex_iothread_locked: Return lock status of the main loop mutex.
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 16da279696..e723c467eb 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -9,7 +9,6 @@ enum {
QEMU_ARCH_CRIS = (1 << 2),
QEMU_ARCH_I386 = (1 << 3),
QEMU_ARCH_M68K = (1 << 4),
- QEMU_ARCH_LM32 = (1 << 5),
QEMU_ARCH_MICROBLAZE = (1 << 6),
QEMU_ARCH_MIPS = (1 << 7),
QEMU_ARCH_PPC = (1 << 8),
@@ -18,8 +17,6 @@ enum {
QEMU_ARCH_SPARC = (1 << 11),
QEMU_ARCH_XTENSA = (1 << 12),
QEMU_ARCH_OPENRISC = (1 << 13),
- QEMU_ARCH_UNICORE32 = (1 << 14),
- QEMU_ARCH_MOXIE = (1 << 15),
QEMU_ARCH_TRICORE = (1 << 16),
QEMU_ARCH_NIOS2 = (1 << 17),
QEMU_ARCH_HPPA = (1 << 18),
diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h
index 12fb54f990..247f0661d1 100644
--- a/include/sysemu/hax.h
+++ b/include/sysemu/hax.h
@@ -24,6 +24,8 @@
int hax_sync_vcpus(void);
+#ifdef NEED_CPU_H
+
#ifdef CONFIG_HAX
int hax_enabled(void);
@@ -34,4 +36,6 @@ int hax_enabled(void);
#endif /* CONFIG_HAX */
+#endif /* NEED_CPU_H */
+
#endif /* QEMU_HAX_H */
diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
index c98636bc81..bb70082e45 100644
--- a/include/sysemu/hvf.h
+++ b/include/sysemu/hvf.h
@@ -16,6 +16,8 @@
#include "qemu/accel.h"
#include "qom/object.h"
+#ifdef NEED_CPU_H
+
#ifdef CONFIG_HVF
uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
int reg);
@@ -26,6 +28,8 @@ extern bool hvf_allowed;
#define hvf_get_supported_cpuid(func, idx, reg) 0
#endif /* !CONFIG_HVF */
+#endif /* NEED_CPU_H */
+
#define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf")
typedef struct HVFState HVFState;
diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h
index 8ca1c1c4ac..2889fa2278 100644
--- a/include/sysemu/whpx.h
+++ b/include/sysemu/whpx.h
@@ -13,6 +13,8 @@
#ifndef QEMU_WHPX_H
#define QEMU_WHPX_H
+#ifdef NEED_CPU_H
+
#ifdef CONFIG_WHPX
int whpx_enabled(void);
@@ -25,4 +27,6 @@ bool whpx_apic_in_platform(void);
#endif /* CONFIG_WHPX */
+#endif /* NEED_CPU_H */
+
#endif /* QEMU_WHPX_H */
diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h
index 2cd1faf9c4..ef8a008ea7 100644
--- a/include/tcg/tcg-op.h
+++ b/include/tcg/tcg-op.h
@@ -1096,6 +1096,7 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
#define tcg_gen_sextract_tl tcg_gen_sextract_i64
#define tcg_gen_extract2_tl tcg_gen_extract2_i64
#define tcg_const_tl tcg_const_i64
+#define tcg_constant_tl tcg_constant_i64
#define tcg_const_local_tl tcg_const_local_i64
#define tcg_gen_movcond_tl tcg_gen_movcond_i64
#define tcg_gen_add2_tl tcg_gen_add2_i64
@@ -1209,6 +1210,7 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t);
#define tcg_gen_sextract_tl tcg_gen_sextract_i32
#define tcg_gen_extract2_tl tcg_gen_extract2_i32
#define tcg_const_tl tcg_const_i32
+#define tcg_constant_tl tcg_constant_i32
#define tcg_const_local_tl tcg_const_local_i32
#define tcg_gen_movcond_tl tcg_gen_movcond_i32
#define tcg_gen_add2_tl tcg_gen_add2_i32
diff --git a/job.c b/job.c
index 4aff13d95a..8775c1803b 100644
--- a/job.c
+++ b/job.c
@@ -716,7 +716,7 @@ static int job_finalize_single(Job *job)
static void job_cancel_async(Job *job, bool force)
{
if (job->driver->cancel) {
- job->driver->cancel(job);
+ job->driver->cancel(job, force);
}
if (job->user_paused) {
/* Do not call job_enter here, the caller will handle it. */
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index b591790c22..662bcd1c4e 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -561,11 +561,7 @@ long do_rt_sigreturn(CPUARMState *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c
index c5c27ce084..1129ffeea1 100644
--- a/linux-user/alpha/signal.c
+++ b/linux-user/alpha/signal.c
@@ -138,8 +138,8 @@ void setup_frame(int sig, struct target_sigaction *ka,
setup_sigcontext(&frame->sc, env, frame_addr, set);
- if (ka->sa_restorer) {
- r26 = ka->sa_restorer;
+ if (ka->ka_restorer) {
+ r26 = ka->ka_restorer;
} else {
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
__put_user(INSN_LDI_R0 + TARGET_NR_sigreturn,
@@ -192,15 +192,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
}
- if (ka->sa_restorer) {
- r26 = ka->sa_restorer;
+ if (ka->ka_restorer) {
+ r26 = ka->ka_restorer;
} else {
__put_user(INSN_MOV_R30_R16, &frame->retcode[0]);
__put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn,
&frame->retcode[1]);
__put_user(INSN_CALLSYS, &frame->retcode[2]);
/* imb(); */
- r26 = frame_addr + offsetof(struct target_sigframe, retcode);
+ r26 = frame_addr + offsetof(struct target_rt_sigframe, retcode);
}
if (err) {
@@ -257,11 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->ir[IR_SP]) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h
index 0b90d3a897..250642913e 100644
--- a/linux-user/alpha/target_signal.h
+++ b/linux-user/alpha/target_signal.h
@@ -92,6 +92,7 @@ typedef struct target_sigaltstack {
#define TARGET_GEN_SUBRNG7 -25
#define TARGET_ARCH_HAS_SETUP_FRAME
+#define TARGET_ARCH_HAS_KA_RESTORER
/* bit-flags */
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index 989d03cd89..69632d15be 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -224,6 +224,64 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb)
}
}
+static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
+{
+ TaskState *ts = env_cpu(env)->opaque;
+ int rc = EmulateAll(opcode, &ts->fpa, env);
+ int raise, enabled;
+
+ if (rc == 0) {
+ /* Illegal instruction */
+ return false;
+ }
+ if (rc > 0) {
+ /* Everything ok. */
+ env->regs[15] += 4;
+ return true;
+ }
+
+ /* FP exception */
+ rc = -rc;
+ raise = 0;
+
+ /* Translate softfloat flags to FPSR flags */
+ if (rc & float_flag_invalid) {
+ raise |= BIT_IOC;
+ }
+ if (rc & float_flag_divbyzero) {
+ raise |= BIT_DZC;
+ }
+ if (rc & float_flag_overflow) {
+ raise |= BIT_OFC;
+ }
+ if (rc & float_flag_underflow) {
+ raise |= BIT_UFC;
+ }
+ if (rc & float_flag_inexact) {
+ raise |= BIT_IXC;
+ }
+
+ /* Accumulate unenabled exceptions */
+ enabled = ts->fpa.fpsr >> 16;
+ ts->fpa.fpsr |= raise & ~enabled;
+
+ if (raise & enabled) {
+ target_siginfo_t info = { };
+
+ /*
+ * The kernel's nwfpe emulator does not pass a real si_code.
+ * It merely uses send_sig(SIGFPE, current, 1).
+ */
+ info.si_signo = TARGET_SIGFPE;
+ info.si_code = TARGET_SI_KERNEL;
+
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ } else {
+ env->regs[15] += 4;
+ }
+ return true;
+}
+
void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
@@ -244,9 +302,7 @@ void cpu_loop(CPUARMState *env)
case EXCP_NOCP:
case EXCP_INVSTATE:
{
- TaskState *ts = cs->opaque;
uint32_t opcode;
- int rc;
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
@@ -263,64 +319,15 @@ void cpu_loop(CPUARMState *env)
goto excp_debug;
}
- rc = EmulateAll(opcode, &ts->fpa, env);
- if (rc == 0) { /* illegal instruction */
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else if (rc < 0) { /* FP exception */
- int arm_fpe=0;
-
- /* translate softfloat flags to FPSR flags */
- if (-rc & float_flag_invalid)
- arm_fpe |= BIT_IOC;
- if (-rc & float_flag_divbyzero)
- arm_fpe |= BIT_DZC;
- if (-rc & float_flag_overflow)
- arm_fpe |= BIT_OFC;
- if (-rc & float_flag_underflow)
- arm_fpe |= BIT_UFC;
- if (-rc & float_flag_inexact)
- arm_fpe |= BIT_IXC;
-
- FPSR fpsr = ts->fpa.fpsr;
- //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe);
-
- if (fpsr & (arm_fpe << 16)) { /* exception enabled? */
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
-
- /* ordered by priority, least first */
- if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES;
- if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND;
- if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF;
- if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV;
- if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV;
-
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
- } else {
- env->regs[15] += 4;
- }
-
- /* accumulate unenabled exceptions */
- if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC))
- fpsr |= BIT_IXC;
- if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC))
- fpsr |= BIT_UFC;
- if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC))
- fpsr |= BIT_OFC;
- if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC))
- fpsr |= BIT_DZC;
- if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC))
- fpsr |= BIT_IOC;
- ts->fpa.fpsr=fpsr;
- } else { /* everything OK */
- /* increment PC */
- env->regs[15] += 4;
+ if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
+ break;
}
+
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->regs[15];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
}
break;
case EXCP_SWI:
diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c
index f21d1535e4..32b68ee302 100644
--- a/linux-user/arm/signal.c
+++ b/linux-user/arm/signal.c
@@ -685,11 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env,
}
}
- if (do_sigaltstack(context_addr
- + offsetof(struct target_ucontext_v2, tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- return 1;
- }
+ target_restore_altstack(&uc->tuc_stack, env);
#if 0
/* Send SIGTRAP if we're single-stepping */
@@ -773,8 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->uc.tuc_stack, env);
#if 0
/* Send SIGTRAP if we're single-stepping */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index fc9c4f12be..0e832b2649 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -676,48 +676,25 @@ static uint32_t get_elf_hwcap2(void)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_SPARCV9
-
-#define STACK_BIAS 2047
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
-#ifndef TARGET_ABI32
- regs->tstate = 0;
-#endif
- regs->pc = infop->entry;
- regs->npc = regs->pc + 4;
- regs->y = 0;
-#ifdef TARGET_ABI32
- regs->u_regs[14] = infop->start_stack - 16 * 4;
-#else
- if (personality(infop->personality) == PER_LINUX32)
- regs->u_regs[14] = infop->start_stack - 16 * 4;
- else
- regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-#endif
-}
-
#else
#define ELF_START_MMAP 0x80000000
#define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \
| HWCAP_SPARC_MULDIV)
-
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_SPARC
+#endif /* TARGET_SPARC64 */
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
- regs->psr = 0;
+ /* Note that target_cpu_copy_regs does not read psr/tstate. */
regs->pc = infop->entry;
regs->npc = regs->pc + 4;
regs->y = 0;
- regs->u_regs[14] = infop->start_stack - 16 * 4;
+ regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong)
+ - TARGET_STACK_BIAS);
}
-
-#endif
-#endif
+#endif /* TARGET_SPARC */
#ifdef TARGET_PPC
@@ -1398,6 +1375,39 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
regs->gprs[15] = infop->start_stack;
}
+/* See linux kernel: arch/s390/include/uapi/asm/ptrace.h (s390_regs). */
+#define ELF_NREG 27
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+enum {
+ TARGET_REG_PSWM = 0,
+ TARGET_REG_PSWA = 1,
+ TARGET_REG_GPRS = 2,
+ TARGET_REG_ARS = 18,
+ TARGET_REG_ORIG_R2 = 26,
+};
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUS390XState *env)
+{
+ int i;
+ uint32_t *aregs;
+
+ (*regs)[TARGET_REG_PSWM] = tswapreg(env->psw.mask);
+ (*regs)[TARGET_REG_PSWA] = tswapreg(env->psw.addr);
+ for (i = 0; i < 16; i++) {
+ (*regs)[TARGET_REG_GPRS + i] = tswapreg(env->regs[i]);
+ }
+ aregs = (uint32_t *)&((*regs)[TARGET_REG_ARS]);
+ for (i = 0; i < 16; i++) {
+ aregs[i] = tswap32(env->aregs[i]);
+ }
+ (*regs)[TARGET_REG_ORIG_R2] = 0;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
#endif /* TARGET_S390X */
#ifdef TARGET_RISCV
@@ -3399,7 +3409,6 @@ static size_t note_size(const struct memelfnote *);
static void free_note_info(struct elf_note_info *);
static int fill_note_info(struct elf_note_info *, long, const CPUArchState *);
static void fill_thread_info(struct elf_note_info *, const CPUArchState *);
-static int core_dump_filename(const TaskState *, char *, size_t);
static int dump_write(int, const void *, size_t);
static int write_note(struct memelfnote *, int);
@@ -3642,11 +3651,12 @@ static int fill_psinfo(struct target_elf_prpsinfo *psinfo, const TaskState *ts)
(void) memset(psinfo, 0, sizeof (*psinfo));
- len = ts->info->arg_end - ts->info->arg_start;
+ len = ts->info->env_strings - ts->info->arg_strings;
if (len >= ELF_PRARGSZ)
len = ELF_PRARGSZ - 1;
- if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_start, len))
+ if (copy_from_user(&psinfo->pr_psargs, ts->info->arg_strings, len)) {
return -EFAULT;
+ }
for (i = 0; i < len; i++)
if (psinfo->pr_psargs[i] == 0)
psinfo->pr_psargs[i] = ' ';
@@ -3698,32 +3708,16 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
* for the name:
* qemu_<basename-of-target-binary>_<date>-<time>_<pid>.core
*
- * Returns 0 in case of success, -1 otherwise (errno is set).
+ * Returns the filename
*/
-static int core_dump_filename(const TaskState *ts, char *buf,
- size_t bufsize)
+static char *core_dump_filename(const TaskState *ts)
{
- char timestamp[64];
- char *base_filename = NULL;
- struct timeval tv;
- struct tm tm;
-
- assert(bufsize >= PATH_MAX);
-
- if (gettimeofday(&tv, NULL) < 0) {
- (void) fprintf(stderr, "unable to get current timestamp: %s",
- strerror(errno));
- return (-1);
- }
+ g_autoptr(GDateTime) now = g_date_time_new_now_local();
+ g_autofree char *nowstr = g_date_time_format(now, "%Y%m%d-%H%M%S");
+ g_autofree char *base_filename = g_path_get_basename(ts->bprm->filename);
- base_filename = g_path_get_basename(ts->bprm->filename);
- (void) strftime(timestamp, sizeof (timestamp), "%Y%m%d-%H%M%S",
- localtime_r(&tv.tv_sec, &tm));
- (void) snprintf(buf, bufsize, "qemu_%s_%s_%d.core",
- base_filename, timestamp, (int)getpid());
- g_free(base_filename);
-
- return (0);
+ return g_strdup_printf("qemu_%s_%s_%d.core",
+ base_filename, nowstr, (int)getpid());
}
static int dump_write(int fd, const void *ptr, size_t size)
@@ -3951,7 +3945,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
const CPUState *cpu = env_cpu((CPUArchState *)env);
const TaskState *ts = (const TaskState *)cpu->opaque;
struct vm_area_struct *vma = NULL;
- char corefile[PATH_MAX];
+ g_autofree char *corefile = NULL;
struct elf_note_info info;
struct elfhdr elf;
struct elf_phdr phdr;
@@ -3968,8 +3962,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
if (dumpsize.rlim_cur == 0)
return 0;
- if (core_dump_filename(ts, corefile, sizeof (corefile)) < 0)
- return (-errno);
+ corefile = core_dump_filename(ts);
if ((fd = open(corefile, O_WRONLY | O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c
index fde8dc93b7..85eab5e943 100644
--- a/linux-user/hexagon/signal.c
+++ b/linux-user/hexagon/signal.c
@@ -260,11 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env)
}
restore_ucontext(env, &frame->uc);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.uc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c
index d1a58feeb3..0e266f472d 100644
--- a/linux-user/hppa/signal.c
+++ b/linux-user/hppa/signal.c
@@ -187,13 +187,7 @@ long do_rt_sigreturn(CPUArchState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- unlock_user_struct(frame, frame_addr, 0);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.tuc_stack),
- 0, env->gr[30]) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 9320e1d472..8701774e37 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -581,10 +581,7 @@ long do_rt_sigreturn(CPUX86State *env)
goto badframe;
}
- if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c
index 49ff87c77b..d06230655e 100644
--- a/linux-user/m68k/signal.c
+++ b/linux-user/m68k/signal.c
@@ -400,10 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env)
if (target_rt_restore_ucontext(env, &frame->uc))
goto badframe;
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/main.c b/linux-user/main.c
index 57ba1b45ab..4dfc47ad3b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -205,7 +205,6 @@ CPUArchState *cpu_copy(CPUArchState *env)
CPUState *new_cpu = cpu_create(cpu_type);
CPUArchState *new_env = new_cpu->env_ptr;
CPUBreakpoint *bp;
- CPUWatchpoint *wp;
/* Reset non arch specific state */
cpu_reset(new_cpu);
@@ -217,13 +216,9 @@ CPUArchState *cpu_copy(CPUArchState *env)
Note: Once we support ptrace with hw-debug register access, make sure
BP_CPU break/watchpoints are handled correctly on clone. */
QTAILQ_INIT(&new_cpu->breakpoints);
- QTAILQ_INIT(&new_cpu->watchpoints);
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
}
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- cpu_watchpoint_insert(new_cpu, wp->vaddr, wp->len, wp->flags, NULL);
- }
return new_env;
}
@@ -729,8 +724,8 @@ int main(int argc, char **argv, char **envp)
{
AccelClass *ac = ACCEL_GET_CLASS(current_accel());
- ac->init_machine(NULL);
accel_init_interfaces(ac);
+ ac->init_machine(NULL);
}
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 7fe28d659e..9549f81682 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -32,7 +32,6 @@ subdir('mips')
subdir('ppc')
subdir('s390x')
subdir('sh4')
-subdir('sparc64')
subdir('sparc')
subdir('x86_64')
subdir('xtensa')
diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c
index cf0707b556..4c483bd8c6 100644
--- a/linux-user/microblaze/signal.c
+++ b/linux-user/microblaze/signal.c
@@ -209,11 +209,7 @@ long do_rt_sigreturn(CPUMBState *env)
restore_sigcontext(&frame->uc.tuc_mcontext, env);
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 455a8a229a..e6be807a81 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -368,11 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env)
set_sigmask(&blocked);
restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
+ target_restore_altstack(&frame->rs_uc.tuc_stack, env);
env->active_tc.PC = env->CP0_EPC;
mips_set_hflags_isa_mode_from_pc(env);
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 7d535065ed..cc3872f11d 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -82,9 +82,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
int *pr2)
{
int temp;
- abi_ulong off, frame_addr = env->regs[R_SP];
unsigned long *gregs = uc->tuc_mcontext.gregs;
- int err;
/* Always make any pending restarted system calls return -EINTR */
/* current->restart_block.fn = do_no_restart_syscall; */
@@ -130,11 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
__get_user(env->regs[R_RA], &gregs[23]);
__get_user(env->regs[R_SP], &gregs[28]);
- off = offsetof(struct target_rt_sigframe, uc.tuc_stack);
- err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env));
- if (err == -EFAULT) {
- return 1;
- }
+ target_restore_altstack(&uc->tuc_stack, env);
*pr2 = env->regs[2];
return 0;
diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c
index 232ad82b98..5c5640a284 100644
--- a/linux-user/openrisc/signal.c
+++ b/linux-user/openrisc/signal.c
@@ -158,10 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env)
set_sigmask(&set);
restore_sigcontext(env, &frame->uc.tuc_mcontext);
- if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack),
- 0, frame_addr) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return cpu_get_gpr(env, 11);
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 4a0f6c8dc2..fa91ea0eed 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -423,12 +423,6 @@ void cpu_loop(CPUPPCState *env)
cpu_abort(cs, "Maintenance exception while in user mode. "
"Aborting\n");
break;
- case POWERPC_EXCP_STOP: /* stop translation */
- /* We did invalidate the instruction cache. Go on */
- break;
- case POWERPC_EXCP_BRANCH: /* branch instruction: */
- /* We just stopped because of a branch. Go on */
- break;
case POWERPC_EXCP_SYSCALL_USER:
/* system call in user-mode emulation */
/* WARNING:
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index bad38f8ed9..edfad28a37 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -655,9 +655,7 @@ long do_rt_sigreturn(CPUPPCState *env)
if (do_setcontext(&rt_sf->uc, env, 1))
goto sigsegv;
- do_sigaltstack(rt_sf_addr
- + offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, env->gpr[1]);
+ target_restore_altstack(&rt_sf->uc.tuc_stack, env);
unlock_user_struct(rt_sf, rt_sf_addr, 1);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 74e06e7121..3b0b6b75fe 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -432,7 +432,8 @@ int target_to_host_signal(int sig);
int host_to_target_signal(int sig);
long do_sigreturn(CPUArchState *env);
long do_rt_sigreturn(CPUArchState *env);
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+ CPUArchState *env);
int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
abi_ulong unew_ctx, abi_long ctx_size);
diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
index 67a95dbc7b..9405c7fd9a 100644
--- a/linux-user/riscv/signal.c
+++ b/linux-user/riscv/signal.c
@@ -192,11 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env)
}
restore_ucontext(env, &frame->uc);
-
- if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
- uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.uc_stack, env);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c
index 7107c5fb53..ef136dae33 100644
--- a/linux-user/s390x/signal.c
+++ b/linux-user/s390x/signal.c
@@ -25,25 +25,24 @@
#define __NUM_FPRS 16
#define __NUM_ACRS 16
-#define S390_SYSCALL_SIZE 2
#define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */
#define _SIGCONTEXT_NSIG 64
#define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */
#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
-#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */
#define S390_SYSCALL_OPCODE ((uint16_t)0x0a00)
typedef struct {
target_psw_t psw;
- target_ulong gprs[__NUM_GPRS];
- unsigned int acrs[__NUM_ACRS];
+ abi_ulong gprs[__NUM_GPRS];
+ abi_uint acrs[__NUM_ACRS];
} target_s390_regs_common;
typedef struct {
- unsigned int fpc;
- double fprs[__NUM_FPRS];
+ uint32_t fpc;
+ uint32_t pad;
+ uint64_t fprs[__NUM_FPRS];
} target_s390_fp_regs;
typedef struct {
@@ -51,30 +50,41 @@ typedef struct {
target_s390_fp_regs fpregs;
} target_sigregs;
-struct target_sigcontext {
- target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
- target_sigregs *sregs;
-};
+typedef struct {
+ uint64_t vxrs_low[16];
+ uint64_t vxrs_high[16][2];
+ uint8_t reserved[128];
+} target_sigregs_ext;
+
+typedef struct {
+ abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS];
+ abi_ulong sregs;
+} target_sigcontext;
typedef struct {
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
- struct target_sigcontext sc;
+ target_sigcontext sc;
target_sigregs sregs;
int signo;
- uint8_t retcode[S390_SYSCALL_SIZE];
+ target_sigregs_ext sregs_ext;
+ uint16_t retcode;
} sigframe;
+#define TARGET_UC_VXRS 2
+
struct target_ucontext {
- target_ulong tuc_flags;
- struct target_ucontext *tuc_link;
+ abi_ulong tuc_flags;
+ abi_ulong tuc_link;
target_stack_t tuc_stack;
target_sigregs tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
+ target_sigset_t tuc_sigmask;
+ uint8_t reserved[128 - sizeof(target_sigset_t)];
+ target_sigregs_ext tuc_mcontext_ext;
};
typedef struct {
uint8_t callee_used_stack[__SIGNAL_FRAMESIZE];
- uint8_t retcode[S390_SYSCALL_SIZE];
+ uint16_t retcode;
struct target_siginfo info;
struct target_ucontext uc;
} rt_sigframe;
@@ -105,151 +115,191 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
{
int i;
- //save_access_regs(current->thread.acrs); FIXME
- /* Copy a 'clean' PSW mask to the user to avoid leaking
- information about whether PER is currently on. */
+ /*
+ * Copy a 'clean' PSW mask to the user to avoid leaking
+ * information about whether PER is currently on.
+ */
__put_user(env->psw.mask, &sregs->regs.psw.mask);
__put_user(env->psw.addr, &sregs->regs.psw.addr);
+
for (i = 0; i < 16; i++) {
__put_user(env->regs[i], &sregs->regs.gprs[i]);
}
for (i = 0; i < 16; i++) {
__put_user(env->aregs[i], &sregs->regs.acrs[i]);
}
+
/*
* We have to store the fp registers to current->thread.fp_regs
* to merge them with the emulated registers.
*/
- //save_fp_regs(&current->thread.fp_regs); FIXME
for (i = 0; i < 16; i++) {
__put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]);
}
}
+static void save_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext)
+{
+ int i;
+
+ /*
+ * if (MACHINE_HAS_VX) ...
+ * That said, we always allocate the stack storage and the
+ * space is always available in env.
+ */
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->vregs[i][1], &ext->vxrs_low[i]);
+ }
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]);
+ __put_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]);
+ }
+}
+
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUS390XState *env)
{
sigframe *frame;
abi_ulong frame_addr;
+ abi_ulong restorer;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
+ force_sigsegv(sig);
+ return;
}
+ /* Set up backchain. */
+ __put_user(env->regs[15], (abi_ulong *) frame);
+
+ /* Create struct sigcontext on the signal stack. */
+ /* Make sure that we're initializing all of oldmask. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(frame->sc.oldmask) != 1);
__put_user(set->sig[0], &frame->sc.oldmask[0]);
+ __put_user(frame_addr + offsetof(sigframe, sregs), &frame->sc.sregs);
+ /* Create _sigregs on the signal stack */
save_sigregs(env, &frame->sregs);
- __put_user((abi_ulong)(unsigned long)&frame->sregs,
- (abi_ulong *)&frame->sc.sregs);
+ /*
+ * ??? The kernel uses regs->gprs[2] here, which is not yet the signo.
+ * Moreover the comment talks about allowing backtrace, which is really
+ * done by the r15 copy above.
+ */
+ __put_user(sig, &frame->signo);
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
+ /* Create sigregs_ext on the signal stack. */
+ save_sigregs_ext(env, &frame->sregs_ext);
+
+ /*
+ * Set up to return from userspace.
+ * If provided, use a stub already in userspace.
+ */
if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = (unsigned long)
- ka->sa_restorer | PSW_ADDR_AMODE;
+ restorer = ka->sa_restorer;
} else {
- env->regs[14] = (frame_addr + offsetof(sigframe, retcode))
- | PSW_ADDR_AMODE;
+ restorer = frame_addr + offsetof(sigframe, retcode);
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn,
- (uint16_t *)(frame->retcode));
+ &frame->retcode);
}
- /* Set up backchain. */
- __put_user(env->regs[15], (abi_ulong *) frame);
-
/* Set up registers for signal handler */
+ env->regs[14] = restorer;
env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+ /* Force default amode and default user address space control. */
+ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY
+ | (env->psw.mask & ~PSW_MASK_ASC);
+ env->psw.addr = ka->_sa_handler;
- env->regs[2] = sig; //map_signal(sig);
- env->regs[3] = frame_addr += offsetof(typeof(*frame), sc);
+ env->regs[2] = sig;
+ env->regs[3] = frame_addr + offsetof(typeof(*frame), sc);
- /* We forgot to include these in the sigcontext.
- To avoid breaking binary compatibility, they are passed as args. */
- env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no;
- env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr;
+ /*
+ * We forgot to include these in the sigcontext.
+ * To avoid breaking binary compatibility, they are passed as args.
+ */
+ env->regs[4] = 0; /* FIXME: regs->int_code & 127 */
+ env->regs[5] = 0; /* FIXME: regs->int_parm_long */
+ env->regs[6] = 0; /* FIXME: current->thread.last_break */
- /* Place signal number on stack to allow backtrace from handler. */
- __put_user(env->regs[2], &frame->signo);
unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUS390XState *env)
{
- int i;
rt_sigframe *frame;
abi_ulong frame_addr;
+ abi_ulong restorer;
+ abi_ulong uc_flags;
frame_addr = get_sigframe(ka, env, sizeof *frame);
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
+ force_sigsegv(sig);
+ return;
}
- tswap_siginfo(&frame->info, info);
-
- /* Create the ucontext. */
- __put_user(0, &frame->uc.tuc_flags);
- __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link);
- target_save_altstack(&frame->uc.tuc_stack, env);
- save_sigregs(env, &frame->uc.tuc_mcontext);
- for (i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user((abi_ulong)set->sig[i],
- (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]);
- }
+ /* Set up backchain. */
+ __put_user(env->regs[15], (abi_ulong *) frame);
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
+ /*
+ * Set up to return from userspace.
+ * If provided, use a stub already in userspace.
+ */
if (ka->sa_flags & TARGET_SA_RESTORER) {
- env->regs[14] = ka->sa_restorer | PSW_ADDR_AMODE;
+ restorer = ka->sa_restorer;
} else {
- env->regs[14] = (frame_addr + offsetof(typeof(*frame), retcode))
- | PSW_ADDR_AMODE;
+ restorer = frame_addr + offsetof(typeof(*frame), retcode);
__put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn,
- (uint16_t *)(frame->retcode));
+ &frame->retcode);
}
- /* Set up backchain. */
- __put_user(env->regs[15], (abi_ulong *) frame);
+ /* Create siginfo on the signal stack. */
+ tswap_siginfo(&frame->info, info);
+
+ /* Create ucontext on the signal stack. */
+ uc_flags = 0;
+ if (s390_has_feat(S390_FEAT_VECTOR)) {
+ uc_flags |= TARGET_UC_VXRS;
+ }
+ __put_user(uc_flags, &frame->uc.tuc_flags);
+ __put_user(0, &frame->uc.tuc_link);
+ target_save_altstack(&frame->uc.tuc_stack, env);
+ save_sigregs(env, &frame->uc.tuc_mcontext);
+ save_sigregs_ext(env, &frame->uc.tuc_mcontext_ext);
+ tswap_sigset(&frame->uc.tuc_sigmask, set);
/* Set up registers for signal handler */
+ env->regs[14] = restorer;
env->regs[15] = frame_addr;
- env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE;
+ /* Force default amode and default user address space control. */
+ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY
+ | (env->psw.mask & ~PSW_MASK_ASC);
+ env->psw.addr = ka->_sa_handler;
- env->regs[2] = sig; //map_signal(sig);
+ env->regs[2] = sig;
env->regs[3] = frame_addr + offsetof(typeof(*frame), info);
env->regs[4] = frame_addr + offsetof(typeof(*frame), uc);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
+ env->regs[5] = 0; /* FIXME: current->thread.last_break */
}
-static int
-restore_sigregs(CPUS390XState *env, target_sigregs *sc)
+static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
{
- int err = 0;
+ target_ulong prev_addr;
int i;
for (i = 0; i < 16; i++) {
__get_user(env->regs[i], &sc->regs.gprs[i]);
}
+ prev_addr = env->psw.addr;
__get_user(env->psw.mask, &sc->regs.psw.mask);
- trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr,
- (unsigned long long)env->psw.addr);
__get_user(env->psw.addr, &sc->regs.psw.addr);
- /* FIXME: 31-bit -> | PSW_ADDR_AMODE */
+ trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr);
for (i = 0; i < 16; i++) {
__get_user(env->aregs[i], &sc->regs.acrs[i]);
@@ -257,8 +307,24 @@ restore_sigregs(CPUS390XState *env, target_sigregs *sc)
for (i = 0; i < 16; i++) {
__get_user(*get_freg(env, i), &sc->fpregs.fprs[i]);
}
+}
+
+static void restore_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext)
+{
+ int i;
- return err;
+ /*
+ * if (MACHINE_HAS_VX) ...
+ * That said, we always allocate the stack storage and the
+ * space is always available in env.
+ */
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->vregs[i][1], &ext->vxrs_low[i]);
+ }
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]);
+ __get_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]);
+ }
}
long do_sigreturn(CPUS390XState *env)
@@ -270,23 +336,22 @@ long do_sigreturn(CPUS390XState *env)
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
+
+ /* Make sure that we're initializing all of target_set. */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(target_set.sig) != 1);
__get_user(target_set.sig[0], &frame->sc.oldmask[0]);
target_to_host_sigset_internal(&set, &target_set);
set_sigmask(&set); /* ~_BLOCKABLE? */
- if (restore_sigregs(env, &frame->sregs)) {
- goto badframe;
- }
+ restore_sigregs(env, &frame->sregs);
+ restore_sigregs_ext(env, &frame->sregs_ext);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
}
long do_rt_sigreturn(CPUS390XState *env)
@@ -297,25 +362,18 @@ long do_rt_sigreturn(CPUS390XState *env)
trace_user_do_rt_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
set_sigmask(&set); /* ~_BLOCKABLE? */
- if (restore_sigregs(env, &frame->uc.tuc_mcontext)) {
- goto badframe;
- }
+ restore_sigregs(env, &frame->uc.tuc_mcontext);
+ restore_sigregs_ext(env, &frame->uc.tuc_mcontext_ext);
- if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0,
- get_sp_from_cpustate(env)) == -EFAULT) {
- goto badframe;
- }
- unlock_user_struct(frame, frame_addr, 0);
- return -TARGET_QEMU_ESIGRETURN;
+ target_restore_altstack(&frame->uc.tuc_stack, env);
-badframe:
unlock_user_struct(frame, frame_addr, 0);
- force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 29c1ee30e6..0451e65806 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -323,12 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
set_sigmask(&blocked);
restore_sigcontext(regs, &frame->uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(regs)) == -EFAULT) {
- goto badframe;
- }
+ target_restore_altstack(&frame->uc.tuc_stack, regs);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 1df1068552..ea86328b28 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -24,6 +24,7 @@ int on_sig_stack(unsigned long sp);
int sas_ss_flags(unsigned long sp);
abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka);
void target_save_altstack(target_stack_t *uss, CPUArchState *env);
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env);
static inline void target_sigemptyset(target_sigset_t *set)
{
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 7eecec46c4..9016896dcd 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -297,6 +297,50 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env)
__put_user(ts->sigaltstack_used.ss_size, &uss->ss_size);
}
+abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ size_t minstacksize = TARGET_MINSIGSTKSZ;
+ target_stack_t ss;
+
+#if defined(TARGET_PPC64)
+ /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
+ struct image_info *image = ts->info;
+ if (get_ppc64_abi(image) > 1) {
+ minstacksize = 4096;
+ }
+#endif
+
+ __get_user(ss.ss_sp, &uss->ss_sp);
+ __get_user(ss.ss_size, &uss->ss_size);
+ __get_user(ss.ss_flags, &uss->ss_flags);
+
+ if (on_sig_stack(get_sp_from_cpustate(env))) {
+ return -TARGET_EPERM;
+ }
+
+ switch (ss.ss_flags) {
+ default:
+ return -TARGET_EINVAL;
+
+ case TARGET_SS_DISABLE:
+ ss.ss_size = 0;
+ ss.ss_sp = 0;
+ break;
+
+ case TARGET_SS_ONSTACK:
+ case 0:
+ if (ss.ss_size < minstacksize) {
+ return -TARGET_ENOMEM;
+ }
+ break;
+ }
+
+ ts->sigaltstack_used.ss_sp = ss.ss_sp;
+ ts->sigaltstack_used.ss_size = ss.ss_size;
+ return 0;
+}
+
/* siginfo conversion */
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
@@ -756,81 +800,49 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
/* do_sigaltstack() returns target values and errnos. */
/* compare linux/kernel/signal.c:do_sigaltstack() */
-abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp)
+abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr,
+ CPUArchState *env)
{
- int ret;
- struct target_sigaltstack oss;
- TaskState *ts = (TaskState *)thread_cpu->opaque;
+ target_stack_t oss, *uoss = NULL;
+ abi_long ret = -TARGET_EFAULT;
- /* XXX: test errors */
- if(uoss_addr)
- {
- __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp);
- __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size);
- __put_user(sas_ss_flags(sp), &oss.ss_flags);
+ if (uoss_addr) {
+ /* Verify writability now, but do not alter user memory yet. */
+ if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) {
+ goto out;
+ }
+ target_save_altstack(&oss, env);
}
- if(uss_addr)
- {
- struct target_sigaltstack *uss;
- struct target_sigaltstack ss;
- size_t minstacksize = TARGET_MINSIGSTKSZ;
+ if (uss_addr) {
+ target_stack_t *uss;
-#if defined(TARGET_PPC64)
- /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */
- struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
- if (get_ppc64_abi(image) > 1) {
- minstacksize = 4096;
- }
-#endif
-
- ret = -TARGET_EFAULT;
if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) {
goto out;
}
- __get_user(ss.ss_sp, &uss->ss_sp);
- __get_user(ss.ss_size, &uss->ss_size);
- __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_restore_altstack(uss, env);
+ if (ret) {
goto out;
-
- 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) {
- ss.ss_size = 0;
- ss.ss_sp = 0;
- } else {
- ret = -TARGET_ENOMEM;
- if (ss.ss_size < minstacksize) {
- goto out;
- }
}
-
- ts->sigaltstack_used.ss_sp = ss.ss_sp;
- ts->sigaltstack_used.ss_size = ss.ss_size;
}
if (uoss_addr) {
- ret = -TARGET_EFAULT;
- if (copy_to_user(uoss_addr, &oss, sizeof(oss)))
- goto out;
+ memcpy(uoss, &oss, sizeof(oss));
+ unlock_user_struct(uoss, uoss_addr, 1);
+ uoss = NULL;
}
-
ret = 0;
-out:
+
+ out:
+ if (uoss) {
+ unlock_user_struct(uoss, uoss_addr, 0);
+ }
return ret;
}
/* do_sigaction() return target values and host errnos */
int do_sigaction(int sig, const struct target_sigaction *act,
- struct target_sigaction *oact)
+ struct target_sigaction *oact, abi_ulong ka_restorer)
{
struct target_sigaction *k;
struct sigaction act1;
@@ -864,6 +876,9 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#ifdef TARGET_ARCH_HAS_SA_RESTORER
__get_user(k->sa_restorer, &act->sa_restorer);
#endif
+#ifdef TARGET_ARCH_HAS_KA_RESTORER
+ k->ka_restorer = ka_restorer;
+#endif
/* To be swapped in target_to_host_sigset. */
k->sa_mask = act->sa_mask;
diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c
index d27b7a3af7..0cc3db5570 100644
--- a/linux-user/sparc/signal.c
+++ b/linux-user/sparc/signal.c
@@ -21,107 +21,96 @@
#include "signal-common.h"
#include "linux-user/trace.h"
-#define __SUNOS_MAXWIN 31
-
-/* This is what SunOS does, so shall I. */
-struct target_sigcontext {
- abi_ulong sigc_onstack; /* state to restore */
-
- abi_ulong sigc_mask; /* sigmask to restore */
- abi_ulong sigc_sp; /* stack pointer */
- abi_ulong sigc_pc; /* program counter */
- abi_ulong sigc_npc; /* next program counter */
- abi_ulong sigc_psr; /* for condition codes etc */
- abi_ulong sigc_g1; /* User uses these two registers */
- abi_ulong sigc_o0; /* within the trampoline code. */
-
- /* Now comes information regarding the users window set
- * at the time of the signal.
- */
- abi_ulong sigc_oswins; /* outstanding windows */
-
- /* stack ptrs for each regwin buf */
- char *sigc_spbuf[__SUNOS_MAXWIN];
-
- /* Windows to restore after signal */
- struct {
- abi_ulong locals[8];
- abi_ulong ins[8];
- } sigc_wbuf[__SUNOS_MAXWIN];
-};
-/* A Sparc stack frame */
-struct sparc_stackf {
+/* A Sparc register window */
+struct target_reg_window {
abi_ulong locals[8];
abi_ulong ins[8];
- /* It's simpler to treat fp and callers_pc as elements of ins[]
- * since we never need to access them ourselves.
- */
- char *structptr;
- abi_ulong xargs[6];
- abi_ulong xxargs[1];
};
-typedef struct {
- struct {
- abi_ulong psr;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong u_regs[16]; /* globals and ins */
- } si_regs;
- int si_mask;
-} __siginfo_t;
+/* A Sparc stack frame. */
+struct target_stackf {
+ /*
+ * Since qemu does not reference fp or callers_pc directly,
+ * it's simpler to treat fp and callers_pc as elements of ins[],
+ * and then bundle locals[] and ins[] into reg_window.
+ */
+ struct target_reg_window win;
+ /*
+ * Similarly, bundle structptr and xxargs into xargs[].
+ * This portion of the struct is part of the function call abi,
+ * and belongs to the callee for spilling argument registers.
+ */
+ abi_ulong xargs[8];
+};
-typedef struct {
- abi_ulong si_float_regs[32];
- unsigned long si_fsr;
- unsigned long si_fpqdepth;
+struct target_siginfo_fpu {
+#ifdef TARGET_SPARC64
+ uint64_t si_double_regs[32];
+ uint64_t si_fsr;
+ uint64_t si_gsr;
+ uint64_t si_fprs;
+#else
+ /* It is more convenient for qemu to move doubles, not singles. */
+ uint64_t si_double_regs[16];
+ uint32_t si_fsr;
+ uint32_t si_fpqdepth;
struct {
- unsigned long *insn_addr;
- unsigned long insn;
+ uint32_t insn_addr;
+ uint32_t insn;
} si_fpqueue [16];
-} qemu_siginfo_fpu_t;
-
+#endif
+};
+#ifdef TARGET_ARCH_HAS_SETUP_FRAME
struct target_signal_frame {
- struct sparc_stackf ss;
- __siginfo_t info;
- abi_ulong fpu_save;
- uint32_t insns[2] QEMU_ALIGNED(8);
- abi_ulong extramask[TARGET_NSIG_WORDS - 1];
- abi_ulong extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
+ struct target_stackf ss;
+ struct target_pt_regs regs;
+ uint32_t si_mask;
+ abi_ulong fpu_save;
+ uint32_t insns[2] QEMU_ALIGNED(8);
+ abi_ulong extramask[TARGET_NSIG_WORDS - 1];
+ abi_ulong extra_size; /* Should be 0 */
+ abi_ulong rwin_save;
};
+#endif
+
struct target_rt_signal_frame {
- struct sparc_stackf ss;
- siginfo_t info;
- abi_ulong regs[20];
- sigset_t mask;
- abi_ulong fpu_save;
- uint32_t insns[2];
- stack_t stack;
- unsigned int extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
+ struct target_stackf ss;
+ target_siginfo_t info;
+ struct target_pt_regs regs;
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ abi_ulong fpu_save;
+ target_stack_t stack;
+ target_sigset_t mask;
+#else
+ target_sigset_t mask;
+ abi_ulong fpu_save;
+ uint32_t insns[2];
+ target_stack_t stack;
+ abi_ulong extra_size; /* Should be 0 */
+#endif
+ abi_ulong rwin_save;
};
-static inline abi_ulong get_sigframe(struct target_sigaction *sa,
- CPUSPARCState *env,
- unsigned long framesize)
+static abi_ulong get_sigframe(struct target_sigaction *sa,
+ CPUSPARCState *env,
+ size_t framesize)
{
abi_ulong sp = get_sp_from_cpustate(env);
/*
* If we are on the alternate signal stack and would overflow it, don't.
* Return an always-bogus address instead so we will die with SIGSEGV.
- */
+ */
if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
- return -1;
+ return -1;
}
/* This is the X/Open sanctioned signal stack switching. */
sp = target_sigsp(sp, sa) - framesize;
- /* Always align the stack frame. This handles two cases. First,
+ /*
+ * Always align the stack frame. This handles two cases. First,
* sigaltstack need not be mindful of platform specific stack
* alignment. Second, if we took this signal because the stack
* is not aligned properly, we'd like to take the signal cleanly
@@ -132,175 +121,310 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa,
return sp;
}
-static int
-setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask)
+static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+ int i;
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ __put_user(sparc64_tstate(env), &regs->tstate);
+ /* TODO: magic should contain PT_REG_MAGIC + %tt. */
+ __put_user(0, &regs->magic);
+#else
+ __put_user(cpu_get_psr(env), &regs->psr);
+#endif
+
+ __put_user(env->pc, &regs->pc);
+ __put_user(env->npc, &regs->npc);
+ __put_user(env->y, &regs->y);
+
+ for (i = 0; i < 8; i++) {
+ __put_user(env->gregs[i], &regs->u_regs[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+ }
+}
+
+static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env)
+{
+ int i;
+
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+ /* User can only change condition codes and %asi in %tstate. */
+ uint64_t tstate;
+ __get_user(tstate, &regs->tstate);
+ cpu_put_ccr(env, tstate >> 32);
+ env->asi = extract64(tstate, 24, 8);
+#else
+ /*
+ * User can only change condition codes and FPU enabling in %psr.
+ * But don't bother with FPU enabling, since a real kernel would
+ * just re-enable the FPU upon the next fpu trap.
+ */
+ uint32_t psr;
+ __get_user(psr, &regs->psr);
+ env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC);
+#endif
+
+ /* Note that pc and npc are handled in the caller. */
+
+ __get_user(env->y, &regs->y);
+
+ for (i = 0; i < 8; i++) {
+ __get_user(env->gregs[i], &regs->u_regs[i]);
+ }
+ for (i = 0; i < 8; i++) {
+ __get_user(env->regwptr[WREG_O0 + i], &regs->u_regs[i + 8]);
+ }
+}
+
+static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env)
{
- int err = 0, i;
+ int i;
- __put_user(env->psr, &si->si_regs.psr);
- __put_user(env->pc, &si->si_regs.pc);
- __put_user(env->npc, &si->si_regs.npc);
- __put_user(env->y, &si->si_regs.y);
- for (i=0; i < 8; i++) {
- __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[i + WREG_L0], &win->locals[i]);
}
- for (i=0; i < 8; i++) {
- __put_user(env->regwptr[WREG_O0 + i], &si->si_regs.u_regs[i + 8]);
+ for (i = 0; i < 8; i++) {
+ __put_user(env->regwptr[i + WREG_I0], &win->ins[i]);
}
- __put_user(mask, &si->si_mask);
- return err;
}
-#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
+static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
+{
+ int i;
+#ifdef TARGET_SPARC64
+ for (i = 0; i < 32; ++i) {
+ __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+ }
+ __put_user(env->fsr, &fpu->si_fsr);
+ __put_user(env->gsr, &fpu->si_gsr);
+ __put_user(env->fprs, &fpu->si_fprs);
+#else
+ for (i = 0; i < 16; ++i) {
+ __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+ }
+ __put_user(env->fsr, &fpu->si_fsr);
+ __put_user(0, &fpu->si_fpqdepth);
+#endif
+}
+
+static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env)
+{
+ int i;
+
+#ifdef TARGET_SPARC64
+ uint64_t fprs;
+ __get_user(fprs, &fpu->si_fprs);
+
+ /* In case the user mucks about with FPRS, restore as directed. */
+ if (fprs & FPRS_DL) {
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+ }
+ }
+ if (fprs & FPRS_DU) {
+ for (i = 16; i < 32; ++i) {
+ __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+ }
+ }
+ __get_user(env->fsr, &fpu->si_fsr);
+ __get_user(env->gsr, &fpu->si_gsr);
+ env->fprs |= fprs;
+#else
+ for (i = 0; i < 16; ++i) {
+ __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]);
+ }
+ __get_user(env->fsr, &fpu->si_fsr);
+#endif
+}
+
+#ifdef TARGET_ARCH_HAS_SETUP_FRAME
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUSPARCState *env)
{
abi_ulong sf_addr;
struct target_signal_frame *sf;
- int sigframe_size, err, i;
-
- /* 1. Make sure everything is clean */
- //synchronize_user_stack();
+ size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu);
+ int i;
- sigframe_size = NF_ALIGNEDSZ;
- sf_addr = get_sigframe(ka, env, sigframe_size);
+ sf_addr = get_sigframe(ka, env, sf_size);
trace_user_setup_frame(env, sf_addr);
- sf = lock_user(VERIFY_WRITE, sf_addr,
- sizeof(struct target_signal_frame), 0);
+ sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0);
if (!sf) {
- goto sigsegv;
+ force_sigsegv(sig);
+ return;
}
-#if 0
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill_and_return;
-#endif
+
/* 2. Save the current process state */
- err = setup___siginfo(&sf->info, env, set->sig[0]);
+ save_pt_regs(&sf->regs, env);
__put_user(0, &sf->extra_size);
- //save_fpu_state(regs, &sf->fpu_state);
- //__put_user(&sf->fpu_state, &sf->fpu_save);
+ save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
+ __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
+
+ __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */
- __put_user(set->sig[0], &sf->info.si_mask);
+ __put_user(set->sig[0], &sf->si_mask);
for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
__put_user(set->sig[i + 1], &sf->extramask[i]);
}
- for (i = 0; i < 8; i++) {
- __put_user(env->regwptr[i + WREG_L0], &sf->ss.locals[i]);
- }
- for (i = 0; i < 8; i++) {
- __put_user(env->regwptr[i + WREG_I0], &sf->ss.ins[i]);
- }
- if (err)
- goto sigsegv;
+ save_reg_win(&sf->ss.win, env);
/* 3. signal handler back-trampoline and parameters */
env->regwptr[WREG_SP] = sf_addr;
env->regwptr[WREG_O0] = sig;
env->regwptr[WREG_O1] = sf_addr +
- offsetof(struct target_signal_frame, info);
+ offsetof(struct target_signal_frame, regs);
env->regwptr[WREG_O2] = sf_addr +
- offsetof(struct target_signal_frame, info);
+ offsetof(struct target_signal_frame, regs);
/* 4. signal handler */
env->pc = ka->_sa_handler;
- env->npc = (env->pc + 4);
+ env->npc = env->pc + 4;
+
/* 5. return to kernel instructions */
if (ka->ka_restorer) {
env->regwptr[WREG_O7] = ka->ka_restorer;
} else {
- uint32_t val32;
-
env->regwptr[WREG_O7] = sf_addr +
offsetof(struct target_signal_frame, insns) - 2 * 4;
/* mov __NR_sigreturn, %g1 */
- val32 = 0x821020d8;
- __put_user(val32, &sf->insns[0]);
-
+ __put_user(0x821020d8u, &sf->insns[0]);
/* t 0x10 */
- val32 = 0x91d02010;
- __put_user(val32, &sf->insns[1]);
+ __put_user(0x91d02010u, &sf->insns[1]);
}
- unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
- return;
-#if 0
-sigill_and_return:
- force_sig(TARGET_SIGILL);
-#endif
-sigsegv:
- unlock_user(sf, sf_addr, sizeof(struct target_signal_frame));
- force_sigsegv(sig);
+ unlock_user(sf, sf_addr, sf_size);
}
+#endif /* TARGET_ARCH_HAS_SETUP_FRAME */
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUSPARCState *env)
{
- qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");
+ abi_ulong sf_addr;
+ struct target_rt_signal_frame *sf;
+ size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu);
+
+ sf_addr = get_sigframe(ka, env, sf_size);
+ trace_user_setup_rt_frame(env, sf_addr);
+
+ sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0);
+ if (!sf) {
+ force_sigsegv(sig);
+ return;
+ }
+
+ /* 2. Save the current process state */
+ save_reg_win(&sf->ss.win, env);
+ save_pt_regs(&sf->regs, env);
+
+ save_fpu((struct target_siginfo_fpu *)(sf + 1), env);
+ __put_user(sf_addr + sizeof(*sf), &sf->fpu_save);
+
+ __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */
+
+ tswap_siginfo(&sf->info, info);
+ tswap_sigset(&sf->mask, set);
+ target_save_altstack(&sf->stack, env);
+
+#ifdef TARGET_ABI32
+ __put_user(0, &sf->extra_size);
+#endif
+
+ /* 3. signal handler back-trampoline and parameters */
+ env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS;
+ env->regwptr[WREG_O0] = sig;
+ env->regwptr[WREG_O1] =
+ sf_addr + offsetof(struct target_rt_signal_frame, info);
+#ifdef TARGET_ABI32
+ env->regwptr[WREG_O2] =
+ sf_addr + offsetof(struct target_rt_signal_frame, regs);
+#else
+ env->regwptr[WREG_O2] = env->regwptr[WREG_O1];
+#endif
+
+ /* 4. signal handler */
+ env->pc = ka->_sa_handler;
+ env->npc = env->pc + 4;
+
+ /* 5. return to kernel instructions */
+#ifdef TARGET_ABI32
+ if (ka->ka_restorer) {
+ env->regwptr[WREG_O7] = ka->ka_restorer;
+ } else {
+ env->regwptr[WREG_O7] =
+ sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4;
+
+ /* mov __NR_rt_sigreturn, %g1 */
+ __put_user(0x82102065u, &sf->insns[0]);
+ /* t 0x10 */
+ __put_user(0x91d02010u, &sf->insns[1]);
+ }
+#else
+ env->regwptr[WREG_O7] = ka->ka_restorer;
+#endif
+
+ unlock_user(sf, sf_addr, sf_size);
}
long do_sigreturn(CPUSPARCState *env)
{
+#ifdef TARGET_ARCH_HAS_SETUP_FRAME
abi_ulong sf_addr;
- struct target_signal_frame *sf;
- abi_ulong up_psr, pc, npc;
+ struct target_signal_frame *sf = NULL;
+ abi_ulong pc, npc, ptr;
target_sigset_t set;
sigset_t host_set;
int i;
sf_addr = env->regwptr[WREG_SP];
trace_user_do_sigreturn(env, sf_addr);
- if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
- goto segv_and_exit;
- }
/* 1. Make sure we are not getting garbage from the user */
-
- if (sf_addr & 3)
+ if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
goto segv_and_exit;
+ }
- __get_user(pc, &sf->info.si_regs.pc);
- __get_user(npc, &sf->info.si_regs.npc);
+ /* Make sure stack pointer is aligned. */
+ __get_user(ptr, &sf->regs.u_regs[14]);
+ if (ptr & 7) {
+ goto segv_and_exit;
+ }
+ /* Make sure instruction pointers are aligned. */
+ __get_user(pc, &sf->regs.pc);
+ __get_user(npc, &sf->regs.npc);
if ((pc | npc) & 3) {
goto segv_and_exit;
}
/* 2. Restore the state */
- __get_user(up_psr, &sf->info.si_regs.psr);
-
- /* User can only change condition codes and FPU enabling in %psr. */
- env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
- | (env->psr & ~(PSR_ICC /* | PSR_EF */));
-
+ restore_pt_regs(&sf->regs, env);
env->pc = pc;
env->npc = npc;
- __get_user(env->y, &sf->info.si_regs.y);
- for (i=0; i < 8; i++) {
- __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
- }
- for (i=0; i < 8; i++) {
- __get_user(env->regwptr[i + WREG_O0], &sf->info.si_regs.u_regs[i + 8]);
+
+ __get_user(ptr, &sf->fpu_save);
+ if (ptr) {
+ struct target_siginfo_fpu *fpu;
+ if ((ptr & 3) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
+ goto segv_and_exit;
+ }
+ restore_fpu(fpu, env);
+ unlock_user_struct(fpu, ptr, 0);
}
- /* FIXME: implement FPU save/restore:
- * __get_user(fpu_save, &sf->fpu_save);
- * if (fpu_save) {
- * if (restore_fpu_state(env, fpu_save)) {
- * goto segv_and_exit;
- * }
- * }
- */
+ __get_user(ptr, &sf->rwin_save);
+ if (ptr) {
+ goto segv_and_exit; /* TODO: restore_rwin */
+ }
- /* This is pretty much atomic, no amount locking would prevent
- * the races which exist anyways.
- */
- __get_user(set.sig[0], &sf->info.si_mask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(set.sig[0], &sf->si_mask);
+ for (i = 1; i < TARGET_NSIG_WORDS; i++) {
__get_user(set.sig[i], &sf->extramask[i - 1]);
}
@@ -310,17 +434,74 @@ long do_sigreturn(CPUSPARCState *env)
unlock_user_struct(sf, sf_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
-segv_and_exit:
+ segv_and_exit:
unlock_user_struct(sf, sf_addr, 0);
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
+#else
+ return -TARGET_ENOSYS;
+#endif
}
long do_rt_sigreturn(CPUSPARCState *env)
{
- trace_user_do_rt_sigreturn(env, 0);
- qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
+ abi_ulong sf_addr, tpc, tnpc, ptr;
+ struct target_rt_signal_frame *sf = NULL;
+ sigset_t set;
+
+ sf_addr = get_sp_from_cpustate(env);
+ trace_user_do_rt_sigreturn(env, sf_addr);
+
+ /* 1. Make sure we are not getting garbage from the user */
+ if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) {
+ goto segv_and_exit;
+ }
+
+ /* Validate SP alignment. */
+ __get_user(ptr, &sf->regs.u_regs[8 + WREG_SP]);
+ if ((ptr + TARGET_STACK_BIAS) & 7) {
+ goto segv_and_exit;
+ }
+
+ /* Validate PC and NPC alignment. */
+ __get_user(tpc, &sf->regs.pc);
+ __get_user(tnpc, &sf->regs.npc);
+ if ((tpc | tnpc) & 3) {
+ goto segv_and_exit;
+ }
+
+ /* 2. Restore the state */
+ restore_pt_regs(&sf->regs, env);
+
+ __get_user(ptr, &sf->fpu_save);
+ if (ptr) {
+ struct target_siginfo_fpu *fpu;
+ if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) {
+ goto segv_and_exit;
+ }
+ restore_fpu(fpu, env);
+ unlock_user_struct(fpu, ptr, 0);
+ }
+
+ __get_user(ptr, &sf->rwin_save);
+ if (ptr) {
+ goto segv_and_exit; /* TODO: restore_rwin_state */
+ }
+
+ target_restore_altstack(&sf->stack, env);
+ target_to_host_sigset(&set, &sf->mask);
+ set_sigmask(&set);
+
+ env->pc = tpc;
+ env->npc = tnpc;
+
+ unlock_user_struct(sf, sf_addr, 0);
+ return -TARGET_QEMU_ESIGRETURN;
+
+ segv_and_exit:
+ unlock_user_struct(sf, sf_addr, 0);
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
}
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
@@ -388,14 +569,6 @@ struct target_ucontext {
target_mcontext_t tuc_mcontext;
};
-/* A V9 register window */
-struct target_reg_window {
- abi_ulong locals[8];
- abi_ulong ins[8];
-};
-
-#define TARGET_STACK_BIAS 2047
-
/* {set, get}context() needed for 64-bit SparcLinux userland. */
void sparc64_set_context(CPUSPARCState *env)
{
diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h
index 1fa1011775..1f4bed50f4 100644
--- a/linux-user/sparc/target_cpu.h
+++ b/linux-user/sparc/target_cpu.h
@@ -20,6 +20,12 @@
#ifndef SPARC_TARGET_CPU_H
#define SPARC_TARGET_CPU_H
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
+# define TARGET_STACK_BIAS 2047
+#else
+# define TARGET_STACK_BIAS 0
+#endif
+
static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
unsigned flags)
{
@@ -40,6 +46,7 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp,
#endif
/* ??? The kernel appears to copy one stack frame to the new stack. */
/* ??? The kernel force aligns the new stack. */
+ /* Userspace provides a biased stack pointer value. */
env->regwptr[WREG_SP] = newsp;
}
@@ -77,7 +84,7 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls)
static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
{
- return state->regwptr[WREG_SP];
+ return state->regwptr[WREG_SP] + TARGET_STACK_BIAS;
}
#endif
diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
index 911a3f5af5..34f9a12519 100644
--- a/linux-user/sparc/target_signal.h
+++ b/linux-user/sparc/target_signal.h
@@ -67,7 +67,9 @@ typedef struct target_sigaltstack {
#define TARGET_MINSIGSTKSZ 4096
#define TARGET_SIGSTKSZ 16384
+#ifdef TARGET_ABI32
#define TARGET_ARCH_HAS_SETUP_FRAME
+#endif
/* bit-flags */
#define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */
diff --git a/linux-user/sparc/target_structs.h b/linux-user/sparc/target_structs.h
index 9953540759..beeace8fb2 100644
--- a/linux-user/sparc/target_structs.h
+++ b/linux-user/sparc/target_structs.h
@@ -26,13 +26,10 @@ struct target_ipc_perm {
abi_uint cuid; /* Creator's user ID. */
abi_uint cgid; /* Creator's group ID. */
#if TARGET_ABI_BITS == 32
- abi_ushort __pad1;
+ abi_ushort __pad0;
+#endif
abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad2;
-#else
- abi_ushort mode;
abi_ushort __pad1;
-#endif
abi_ushort __seq; /* Sequence number. */
uint64_t __unused1;
uint64_t __unused2;
@@ -40,22 +37,17 @@ struct target_ipc_perm {
struct target_shmid_ds {
struct target_ipc_perm shm_perm; /* operation permission struct */
-#if TARGET_ABI_BITS == 32
- abi_uint __pad1;
-#endif
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_uint __pad2;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_uint __pad3;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_cpid; /* pid of creator */
- abi_ulong shm_lpid; /* pid of last shmop */
- abi_long shm_nattch; /* number of current attaches */
+ /*
+ * Note that sparc32 splits these into hi/lo parts.
+ * For simplicity in qemu, always use a 64-bit type.
+ */
+ int64_t shm_atime; /* last attach time */
+ int64_t shm_dtime; /* last detach time */
+ int64_t shm_ctime; /* last change time */
+ abi_ulong shm_segsz; /* size of segment in bytes */
+ abi_int shm_cpid; /* pid of creator */
+ abi_int shm_lpid; /* pid of last shmop */
+ abi_ulong shm_nattch; /* number of current attaches */
abi_ulong __unused1;
abi_ulong __unused2;
};
diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h
index d8ea04ea83..15d531f389 100644
--- a/linux-user/sparc/target_syscall.h
+++ b/linux-user/sparc/target_syscall.h
@@ -3,18 +3,34 @@
#include "target_errno.h"
+#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
struct target_pt_regs {
- abi_ulong psr;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong u_regs[16];
+ abi_ulong u_regs[16];
+ abi_ulong tstate;
+ abi_ulong pc;
+ abi_ulong npc;
+ uint32_t y;
+ uint32_t magic;
};
+#else
+struct target_pt_regs {
+ abi_ulong psr;
+ abi_ulong pc;
+ abi_ulong npc;
+ abi_ulong y;
+ abi_ulong u_regs[16];
+};
+#endif
-#define UNAME_MACHINE "sparc"
+#ifdef TARGET_SPARC64
+# define UNAME_MACHINE "sparc64"
+#else
+# define UNAME_MACHINE "sparc"
+#endif
#define UNAME_MINIMUM_RELEASE "2.6.32"
-/* SPARC kernels don't define this in their Kconfig, but they have the
+/*
+ * SPARC kernels don't define this in their Kconfig, but they have the
* same ABI as if they did, implemented by sparc-specific code which fishes
* directly in the u_regs() struct for half the parameters in sparc_do_fork()
* and copy_thread().
@@ -25,20 +41,24 @@ struct target_pt_regs {
#define TARGET_MCL_FUTURE 0x4000
#define TARGET_MCL_ONFAULT 0x8000
-/* For SPARC SHMLBA is determined at runtime in the kernel, and
- * libc has to runtime-detect it using the hwcaps (see glibc
- * sysdeps/unix/sysv/linux/sparc/getshmlba; we follow the same
- * logic here, though we know we're not the sparc v9 64-bit case).
+/*
+ * For SPARC SHMLBA is determined at runtime in the kernel, and
+ * libc has to runtime-detect it using the hwcaps.
+ * See glibc sysdeps/unix/sysv/linux/sparc/getshmlba.
*/
#define TARGET_FORCE_SHMLBA
static inline abi_ulong target_shmlba(CPUSPARCState *env)
{
+#ifdef TARGET_SPARC64
+ return MAX(TARGET_PAGE_SIZE, 16 * 1024);
+#else
if (!(env->def.features & CPU_FEATURE_FLUSH)) {
return 64 * 1024;
} else {
return 256 * 1024;
}
+#endif
}
#endif /* SPARC_TARGET_SYSCALL_H */
diff --git a/linux-user/sparc64/cpu_loop.c b/linux-user/sparc64/cpu_loop.c
deleted file mode 100644
index 4fd44e1b1e..0000000000
--- a/linux-user/sparc64/cpu_loop.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * qemu user cpu loop
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * 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 "../sparc/cpu_loop.c"
diff --git a/linux-user/sparc64/meson.build b/linux-user/sparc64/meson.build
deleted file mode 100644
index 9527a40ed4..0000000000
--- a/linux-user/sparc64/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-syscall_nr_generators += {
- 'sparc64': generator(sh,
- arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
- output: '@BASENAME@_nr.h')
-}
diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c
deleted file mode 100644
index 170ebac232..0000000000
--- a/linux-user/sparc64/signal.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Emulation of Linux signals
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * 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 "../sparc/signal.c"
diff --git a/linux-user/sparc64/sockbits.h b/linux-user/sparc64/sockbits.h
deleted file mode 100644
index 658899e4d3..0000000000
--- a/linux-user/sparc64/sockbits.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../sparc/sockbits.h"
diff --git a/linux-user/sparc64/syscall.tbl b/linux-user/sparc64/syscall.tbl
deleted file mode 100644
index 4af114e84f..0000000000
--- a/linux-user/sparc64/syscall.tbl
+++ /dev/null
@@ -1,487 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
-#
-# system call numbers and entry vectors for sparc
-#
-# The format is:
-# <number> <abi> <name> <entry point> <compat entry point>
-#
-# The <abi> can be common, 64, or 32 for this file.
-#
-0 common restart_syscall sys_restart_syscall
-1 32 exit sys_exit sparc_exit
-1 64 exit sparc_exit
-2 common fork sys_fork
-3 common read sys_read
-4 common write sys_write
-5 common open sys_open compat_sys_open
-6 common close sys_close
-7 common wait4 sys_wait4 compat_sys_wait4
-8 common creat sys_creat
-9 common link sys_link
-10 common unlink sys_unlink
-11 32 execv sunos_execv
-11 64 execv sys_nis_syscall
-12 common chdir sys_chdir
-13 32 chown sys_chown16
-13 64 chown sys_chown
-14 common mknod sys_mknod
-15 common chmod sys_chmod
-16 32 lchown sys_lchown16
-16 64 lchown sys_lchown
-17 common brk sys_brk
-18 common perfctr sys_nis_syscall
-19 common lseek sys_lseek compat_sys_lseek
-20 common getpid sys_getpid
-21 common capget sys_capget
-22 common capset sys_capset
-23 32 setuid sys_setuid16
-23 64 setuid sys_setuid
-24 32 getuid sys_getuid16
-24 64 getuid sys_getuid
-25 common vmsplice sys_vmsplice compat_sys_vmsplice
-26 common ptrace sys_ptrace compat_sys_ptrace
-27 common alarm sys_alarm
-28 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
-29 32 pause sys_pause
-29 64 pause sys_nis_syscall
-30 32 utime sys_utime32
-30 64 utime sys_utime
-31 32 lchown32 sys_lchown
-32 32 fchown32 sys_fchown
-33 common access sys_access
-34 common nice sys_nice
-35 32 chown32 sys_chown
-36 common sync sys_sync
-37 common kill sys_kill
-38 common stat sys_newstat compat_sys_newstat
-39 32 sendfile sys_sendfile compat_sys_sendfile
-39 64 sendfile sys_sendfile64
-40 common lstat sys_newlstat compat_sys_newlstat
-41 common dup sys_dup
-42 common pipe sys_sparc_pipe
-43 common times sys_times compat_sys_times
-44 32 getuid32 sys_getuid
-45 common umount2 sys_umount
-46 32 setgid sys_setgid16
-46 64 setgid sys_setgid
-47 32 getgid sys_getgid16
-47 64 getgid sys_getgid
-48 common signal sys_signal
-49 32 geteuid sys_geteuid16
-49 64 geteuid sys_geteuid
-50 32 getegid sys_getegid16
-50 64 getegid sys_getegid
-51 common acct sys_acct
-52 64 memory_ordering sys_memory_ordering
-53 32 getgid32 sys_getgid
-54 common ioctl sys_ioctl compat_sys_ioctl
-55 common reboot sys_reboot
-56 32 mmap2 sys_mmap2 sys32_mmap2
-57 common symlink sys_symlink
-58 common readlink sys_readlink
-59 32 execve sys_execve sys32_execve
-59 64 execve sys64_execve
-60 common umask sys_umask
-61 common chroot sys_chroot
-62 common fstat sys_newfstat compat_sys_newfstat
-63 common fstat64 sys_fstat64 compat_sys_fstat64
-64 common getpagesize sys_getpagesize
-65 common msync sys_msync
-66 common vfork sys_vfork
-67 common pread64 sys_pread64 compat_sys_pread64
-68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
-69 32 geteuid32 sys_geteuid
-70 32 getegid32 sys_getegid
-71 common mmap sys_mmap
-72 32 setreuid32 sys_setreuid
-73 32 munmap sys_munmap
-73 64 munmap sys_64_munmap
-74 common mprotect sys_mprotect
-75 common madvise sys_madvise
-76 common vhangup sys_vhangup
-77 32 truncate64 sys_truncate64 compat_sys_truncate64
-78 common mincore sys_mincore
-79 32 getgroups sys_getgroups16
-79 64 getgroups sys_getgroups
-80 32 setgroups sys_setgroups16
-80 64 setgroups sys_setgroups
-81 common getpgrp sys_getpgrp
-82 32 setgroups32 sys_setgroups
-83 common setitimer sys_setitimer compat_sys_setitimer
-84 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
-85 common swapon sys_swapon
-86 common getitimer sys_getitimer compat_sys_getitimer
-87 32 setuid32 sys_setuid
-88 common sethostname sys_sethostname
-89 32 setgid32 sys_setgid
-90 common dup2 sys_dup2
-91 32 setfsuid32 sys_setfsuid
-92 common fcntl sys_fcntl compat_sys_fcntl
-93 common select sys_select
-94 32 setfsgid32 sys_setfsgid
-95 common fsync sys_fsync
-96 common setpriority sys_setpriority
-97 common socket sys_socket
-98 common connect sys_connect
-99 common accept sys_accept
-100 common getpriority sys_getpriority
-101 common rt_sigreturn sys_rt_sigreturn sys32_rt_sigreturn
-102 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
-103 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
-104 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
-105 32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
-105 64 rt_sigtimedwait sys_rt_sigtimedwait
-106 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
-107 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
-108 32 setresuid32 sys_setresuid
-108 64 setresuid sys_setresuid
-109 32 getresuid32 sys_getresuid
-109 64 getresuid sys_getresuid
-110 32 setresgid32 sys_setresgid
-110 64 setresgid sys_setresgid
-111 32 getresgid32 sys_getresgid
-111 64 getresgid sys_getresgid
-112 32 setregid32 sys_setregid
-113 common recvmsg sys_recvmsg compat_sys_recvmsg
-114 common sendmsg sys_sendmsg compat_sys_sendmsg
-115 32 getgroups32 sys_getgroups
-116 common gettimeofday sys_gettimeofday compat_sys_gettimeofday
-117 common getrusage sys_getrusage compat_sys_getrusage
-118 common getsockopt sys_getsockopt sys_getsockopt
-119 common getcwd sys_getcwd
-120 common readv sys_readv compat_sys_readv
-121 common writev sys_writev compat_sys_writev
-122 common settimeofday sys_settimeofday compat_sys_settimeofday
-123 32 fchown sys_fchown16
-123 64 fchown sys_fchown
-124 common fchmod sys_fchmod
-125 common recvfrom sys_recvfrom
-126 32 setreuid sys_setreuid16
-126 64 setreuid sys_setreuid
-127 32 setregid sys_setregid16
-127 64 setregid sys_setregid
-128 common rename sys_rename
-129 common truncate sys_truncate compat_sys_truncate
-130 common ftruncate sys_ftruncate compat_sys_ftruncate
-131 common flock sys_flock
-132 common lstat64 sys_lstat64 compat_sys_lstat64
-133 common sendto sys_sendto
-134 common shutdown sys_shutdown
-135 common socketpair sys_socketpair
-136 common mkdir sys_mkdir
-137 common rmdir sys_rmdir
-138 32 utimes sys_utimes_time32
-138 64 utimes sys_utimes
-139 common stat64 sys_stat64 compat_sys_stat64
-140 common sendfile64 sys_sendfile64
-141 common getpeername sys_getpeername
-142 32 futex sys_futex_time32
-142 64 futex sys_futex
-143 common gettid sys_gettid
-144 common getrlimit sys_getrlimit compat_sys_getrlimit
-145 common setrlimit sys_setrlimit compat_sys_setrlimit
-146 common pivot_root sys_pivot_root
-147 common prctl sys_prctl
-148 common pciconfig_read sys_pciconfig_read
-149 common pciconfig_write sys_pciconfig_write
-150 common getsockname sys_getsockname
-151 common inotify_init sys_inotify_init
-152 common inotify_add_watch sys_inotify_add_watch
-153 common poll sys_poll
-154 common getdents64 sys_getdents64
-155 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
-156 common inotify_rm_watch sys_inotify_rm_watch
-157 common statfs sys_statfs compat_sys_statfs
-158 common fstatfs sys_fstatfs compat_sys_fstatfs
-159 common umount sys_oldumount
-160 common sched_set_affinity sys_sched_setaffinity compat_sys_sched_setaffinity
-161 common sched_get_affinity sys_sched_getaffinity compat_sys_sched_getaffinity
-162 common getdomainname sys_getdomainname
-163 common setdomainname sys_setdomainname
-164 64 utrap_install sys_utrap_install
-165 common quotactl sys_quotactl
-166 common set_tid_address sys_set_tid_address
-167 common mount sys_mount compat_sys_mount
-168 common ustat sys_ustat compat_sys_ustat
-169 common setxattr sys_setxattr
-170 common lsetxattr sys_lsetxattr
-171 common fsetxattr sys_fsetxattr
-172 common getxattr sys_getxattr
-173 common lgetxattr sys_lgetxattr
-174 common getdents sys_getdents compat_sys_getdents
-175 common setsid sys_setsid
-176 common fchdir sys_fchdir
-177 common fgetxattr sys_fgetxattr
-178 common listxattr sys_listxattr
-179 common llistxattr sys_llistxattr
-180 common flistxattr sys_flistxattr
-181 common removexattr sys_removexattr
-182 common lremovexattr sys_lremovexattr
-183 32 sigpending sys_sigpending compat_sys_sigpending
-183 64 sigpending sys_nis_syscall
-184 common query_module sys_ni_syscall
-185 common setpgid sys_setpgid
-186 common fremovexattr sys_fremovexattr
-187 common tkill sys_tkill
-188 32 exit_group sys_exit_group sparc_exit_group
-188 64 exit_group sparc_exit_group
-189 common uname sys_newuname
-190 common init_module sys_init_module
-191 32 personality sys_personality sys_sparc64_personality
-191 64 personality sys_sparc64_personality
-192 32 remap_file_pages sys_sparc_remap_file_pages sys_remap_file_pages
-192 64 remap_file_pages sys_remap_file_pages
-193 common epoll_create sys_epoll_create
-194 common epoll_ctl sys_epoll_ctl
-195 common epoll_wait sys_epoll_wait
-196 common ioprio_set sys_ioprio_set
-197 common getppid sys_getppid
-198 32 sigaction sys_sparc_sigaction compat_sys_sparc_sigaction
-198 64 sigaction sys_nis_syscall
-199 common sgetmask sys_sgetmask
-200 common ssetmask sys_ssetmask
-201 32 sigsuspend sys_sigsuspend
-201 64 sigsuspend sys_nis_syscall
-202 common oldlstat sys_newlstat compat_sys_newlstat
-203 common uselib sys_uselib
-204 32 readdir sys_old_readdir compat_sys_old_readdir
-204 64 readdir sys_nis_syscall
-205 common readahead sys_readahead compat_sys_readahead
-206 common socketcall sys_socketcall sys32_socketcall
-207 common syslog sys_syslog
-208 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
-209 common fadvise64 sys_fadvise64 compat_sys_fadvise64
-210 common fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
-211 common tgkill sys_tgkill
-212 common waitpid sys_waitpid
-213 common swapoff sys_swapoff
-214 common sysinfo sys_sysinfo compat_sys_sysinfo
-215 32 ipc sys_ipc compat_sys_ipc
-215 64 ipc sys_sparc_ipc
-216 32 sigreturn sys_sigreturn sys32_sigreturn
-216 64 sigreturn sys_nis_syscall
-217 common clone sys_clone
-218 common ioprio_get sys_ioprio_get
-219 32 adjtimex sys_adjtimex_time32
-219 64 adjtimex sys_sparc_adjtimex
-220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask
-220 64 sigprocmask sys_nis_syscall
-221 common create_module sys_ni_syscall
-222 common delete_module sys_delete_module
-223 common get_kernel_syms sys_ni_syscall
-224 common getpgid sys_getpgid
-225 common bdflush sys_bdflush
-226 common sysfs sys_sysfs
-227 common afs_syscall sys_nis_syscall
-228 common setfsuid sys_setfsuid16
-229 common setfsgid sys_setfsgid16
-230 common _newselect sys_select compat_sys_select
-231 32 time sys_time32
-232 common splice sys_splice
-233 32 stime sys_stime32
-233 64 stime sys_stime
-234 common statfs64 sys_statfs64 compat_sys_statfs64
-235 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
-236 common _llseek sys_llseek
-237 common mlock sys_mlock
-238 common munlock sys_munlock
-239 common mlockall sys_mlockall
-240 common munlockall sys_munlockall
-241 common sched_setparam sys_sched_setparam
-242 common sched_getparam sys_sched_getparam
-243 common sched_setscheduler sys_sched_setscheduler
-244 common sched_getscheduler sys_sched_getscheduler
-245 common sched_yield sys_sched_yield
-246 common sched_get_priority_max sys_sched_get_priority_max
-247 common sched_get_priority_min sys_sched_get_priority_min
-248 32 sched_rr_get_interval sys_sched_rr_get_interval_time32
-248 64 sched_rr_get_interval sys_sched_rr_get_interval
-249 32 nanosleep sys_nanosleep_time32
-249 64 nanosleep sys_nanosleep
-250 32 mremap sys_mremap
-250 64 mremap sys_64_mremap
-251 common _sysctl sys_ni_syscall
-252 common getsid sys_getsid
-253 common fdatasync sys_fdatasync
-254 32 nfsservctl sys_ni_syscall sys_nis_syscall
-254 64 nfsservctl sys_nis_syscall
-255 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
-256 32 clock_settime sys_clock_settime32
-256 64 clock_settime sys_clock_settime
-257 32 clock_gettime sys_clock_gettime32
-257 64 clock_gettime sys_clock_gettime
-258 32 clock_getres sys_clock_getres_time32
-258 64 clock_getres sys_clock_getres
-259 32 clock_nanosleep sys_clock_nanosleep_time32
-259 64 clock_nanosleep sys_clock_nanosleep
-260 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
-261 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
-262 32 timer_settime sys_timer_settime32
-262 64 timer_settime sys_timer_settime
-263 32 timer_gettime sys_timer_gettime32
-263 64 timer_gettime sys_timer_gettime
-264 common timer_getoverrun sys_timer_getoverrun
-265 common timer_delete sys_timer_delete
-266 common timer_create sys_timer_create compat_sys_timer_create
-# 267 was vserver
-267 common vserver sys_nis_syscall
-268 common io_setup sys_io_setup compat_sys_io_setup
-269 common io_destroy sys_io_destroy
-270 common io_submit sys_io_submit compat_sys_io_submit
-271 common io_cancel sys_io_cancel
-272 32 io_getevents sys_io_getevents_time32
-272 64 io_getevents sys_io_getevents
-273 common mq_open sys_mq_open compat_sys_mq_open
-274 common mq_unlink sys_mq_unlink
-275 32 mq_timedsend sys_mq_timedsend_time32
-275 64 mq_timedsend sys_mq_timedsend
-276 32 mq_timedreceive sys_mq_timedreceive_time32
-276 64 mq_timedreceive sys_mq_timedreceive
-277 common mq_notify sys_mq_notify compat_sys_mq_notify
-278 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
-279 common waitid sys_waitid compat_sys_waitid
-280 common tee sys_tee
-281 common add_key sys_add_key
-282 common request_key sys_request_key
-283 common keyctl sys_keyctl compat_sys_keyctl
-284 common openat sys_openat compat_sys_openat
-285 common mkdirat sys_mkdirat
-286 common mknodat sys_mknodat
-287 common fchownat sys_fchownat
-288 32 futimesat sys_futimesat_time32
-288 64 futimesat sys_futimesat
-289 common fstatat64 sys_fstatat64 compat_sys_fstatat64
-290 common unlinkat sys_unlinkat
-291 common renameat sys_renameat
-292 common linkat sys_linkat
-293 common symlinkat sys_symlinkat
-294 common readlinkat sys_readlinkat
-295 common fchmodat sys_fchmodat
-296 common faccessat sys_faccessat
-297 32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
-297 64 pselect6 sys_pselect6
-298 32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
-298 64 ppoll sys_ppoll
-299 common unshare sys_unshare
-300 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
-301 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
-302 common migrate_pages sys_migrate_pages compat_sys_migrate_pages
-303 common mbind sys_mbind compat_sys_mbind
-304 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
-305 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy
-306 common kexec_load sys_kexec_load compat_sys_kexec_load
-307 common move_pages sys_move_pages compat_sys_move_pages
-308 common getcpu sys_getcpu
-309 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
-310 32 utimensat sys_utimensat_time32
-310 64 utimensat sys_utimensat
-311 common signalfd sys_signalfd compat_sys_signalfd
-312 common timerfd_create sys_timerfd_create
-313 common eventfd sys_eventfd
-314 common fallocate sys_fallocate compat_sys_fallocate
-315 32 timerfd_settime sys_timerfd_settime32
-315 64 timerfd_settime sys_timerfd_settime
-316 32 timerfd_gettime sys_timerfd_gettime32
-316 64 timerfd_gettime sys_timerfd_gettime
-317 common signalfd4 sys_signalfd4 compat_sys_signalfd4
-318 common eventfd2 sys_eventfd2
-319 common epoll_create1 sys_epoll_create1
-320 common dup3 sys_dup3
-321 common pipe2 sys_pipe2
-322 common inotify_init1 sys_inotify_init1
-323 common accept4 sys_accept4
-324 common preadv sys_preadv compat_sys_preadv
-325 common pwritev sys_pwritev compat_sys_pwritev
-326 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
-327 common perf_event_open sys_perf_event_open
-328 32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
-328 64 recvmmsg sys_recvmmsg
-329 common fanotify_init sys_fanotify_init
-330 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark
-331 common prlimit64 sys_prlimit64
-332 common name_to_handle_at sys_name_to_handle_at
-333 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at
-334 32 clock_adjtime sys_clock_adjtime32
-334 64 clock_adjtime sys_sparc_clock_adjtime
-335 common syncfs sys_syncfs
-336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
-337 common setns sys_setns
-338 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv
-339 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev
-340 32 kern_features sys_ni_syscall sys_kern_features
-340 64 kern_features sys_kern_features
-341 common kcmp sys_kcmp
-342 common finit_module sys_finit_module
-343 common sched_setattr sys_sched_setattr
-344 common sched_getattr sys_sched_getattr
-345 common renameat2 sys_renameat2
-346 common seccomp sys_seccomp
-347 common getrandom sys_getrandom
-348 common memfd_create sys_memfd_create
-349 common bpf sys_bpf
-350 32 execveat sys_execveat sys32_execveat
-350 64 execveat sys64_execveat
-351 common membarrier sys_membarrier
-352 common userfaultfd sys_userfaultfd
-353 common bind sys_bind
-354 common listen sys_listen
-355 common setsockopt sys_setsockopt sys_setsockopt
-356 common mlock2 sys_mlock2
-357 common copy_file_range sys_copy_file_range
-358 common preadv2 sys_preadv2 compat_sys_preadv2
-359 common pwritev2 sys_pwritev2 compat_sys_pwritev2
-360 common statx sys_statx
-361 32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
-361 64 io_pgetevents sys_io_pgetevents
-362 common pkey_mprotect sys_pkey_mprotect
-363 common pkey_alloc sys_pkey_alloc
-364 common pkey_free sys_pkey_free
-365 common rseq sys_rseq
-# room for arch specific syscalls
-392 64 semtimedop sys_semtimedop
-393 common semget sys_semget
-394 common semctl sys_semctl compat_sys_semctl
-395 common shmget sys_shmget
-396 common shmctl sys_shmctl compat_sys_shmctl
-397 common shmat sys_shmat compat_sys_shmat
-398 common shmdt sys_shmdt
-399 common msgget sys_msgget
-400 common msgsnd sys_msgsnd compat_sys_msgsnd
-401 common msgrcv sys_msgrcv compat_sys_msgrcv
-402 common msgctl sys_msgctl compat_sys_msgctl
-403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime
-404 32 clock_settime64 sys_clock_settime sys_clock_settime
-405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime
-406 32 clock_getres_time64 sys_clock_getres sys_clock_getres
-407 32 clock_nanosleep_time64 sys_clock_nanosleep sys_clock_nanosleep
-408 32 timer_gettime64 sys_timer_gettime sys_timer_gettime
-409 32 timer_settime64 sys_timer_settime sys_timer_settime
-410 32 timerfd_gettime64 sys_timerfd_gettime sys_timerfd_gettime
-411 32 timerfd_settime64 sys_timerfd_settime sys_timerfd_settime
-412 32 utimensat_time64 sys_utimensat sys_utimensat
-413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64
-414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64
-416 32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents
-417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
-418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend
-419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive
-420 32 semtimedop_time64 sys_semtimedop sys_semtimedop
-421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
-422 32 futex_time64 sys_futex sys_futex
-423 32 sched_rr_get_interval_time64 sys_sched_rr_get_interval sys_sched_rr_get_interval
-424 common pidfd_send_signal sys_pidfd_send_signal
-425 common io_uring_setup sys_io_uring_setup
-426 common io_uring_enter sys_io_uring_enter
-427 common io_uring_register sys_io_uring_register
-428 common open_tree sys_open_tree
-429 common move_mount sys_move_mount
-430 common fsopen sys_fsopen
-431 common fsconfig sys_fsconfig
-432 common fsmount sys_fsmount
-433 common fspick sys_fspick
-434 common pidfd_open sys_pidfd_open
-# 435 reserved for clone3
-436 common close_range sys_close_range
-437 common openat2 sys_openat2
-438 common pidfd_getfd sys_pidfd_getfd
-439 common faccessat2 sys_faccessat2
diff --git a/linux-user/sparc64/syscallhdr.sh b/linux-user/sparc64/syscallhdr.sh
deleted file mode 100644
index 08c7e39bb3..0000000000
--- a/linux-user/sparc64/syscallhdr.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-in="$1"
-out="$2"
-my_abis=`echo "($3)" | tr ',' '|'`
-prefix="$4"
-offset="$5"
-
-fileguard=LINUX_USER_SPARC64_`basename "$out" | sed \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
- -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'`
-grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | (
- printf "#ifndef %s\n" "${fileguard}"
- printf "#define %s\n" "${fileguard}"
- printf "\n"
-
- nxt=0
- while read nr abi name entry compat ; do
- if [ -z "$offset" ]; then
- printf "#define TARGET_NR_%s%s\t%s\n" \
- "${prefix}" "${name}" "${nr}"
- else
- printf "#define TARGET_NR_%s%s\t(%s + %s)\n" \
- "${prefix}" "${name}" "${offset}" "${nr}"
- fi
- nxt=$((nr+1))
- done
-
- printf "\n"
- printf "#endif /* %s */" "${fileguard}"
-) > "$out"
diff --git a/linux-user/sparc64/target_cpu.h b/linux-user/sparc64/target_cpu.h
deleted file mode 100644
index b22263d2db..0000000000
--- a/linux-user/sparc64/target_cpu.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../sparc/target_cpu.h"
diff --git a/linux-user/sparc64/target_elf.h b/linux-user/sparc64/target_elf.h
deleted file mode 100644
index d6e388f1cf..0000000000
--- a/linux-user/sparc64/target_elf.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-
-#ifndef SPARC64_TARGET_ELF_H
-#define SPARC64_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "TI UltraSparc II";
-}
-#endif
diff --git a/linux-user/sparc64/target_fcntl.h b/linux-user/sparc64/target_fcntl.h
deleted file mode 100644
index 053c774257..0000000000
--- a/linux-user/sparc64/target_fcntl.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../sparc/target_fcntl.h"
diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h
deleted file mode 100644
index 6a7d57d024..0000000000
--- a/linux-user/sparc64/target_signal.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../sparc/target_signal.h"
diff --git a/linux-user/sparc64/target_structs.h b/linux-user/sparc64/target_structs.h
deleted file mode 100644
index 4a8ed48df7..0000000000
--- a/linux-user/sparc64/target_structs.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * SPARC64 specific structures for linux-user
- *
- * Copyright (c) 2013 Fabrice Bellard
- *
- * 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.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef SPARC64_TARGET_STRUCTS_H
-#define SPARC64_TARGET_STRUCTS_H
-
-struct target_ipc_perm {
- abi_int __key; /* Key. */
- abi_uint uid; /* Owner's user ID. */
- abi_uint gid; /* Owner's group ID. */
- abi_uint cuid; /* Creator's user ID. */
- abi_uint cgid; /* Creator's group ID. */
- abi_ushort mode; /* Read/write permission. */
- abi_ushort __pad1;
- abi_ushort __seq; /* Sequence number. */
- abi_ushort __pad2;
- abi_ulong __unused1;
- abi_ulong __unused2;
-};
-
-struct target_shmid_ds {
- struct target_ipc_perm shm_perm; /* operation permission struct */
- abi_long shm_segsz; /* size of segment in bytes */
- abi_ulong shm_atime; /* time of last shmat() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused1;
-#endif
- abi_ulong shm_dtime; /* time of last shmdt() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused2;
-#endif
- abi_ulong shm_ctime; /* time of last change by shmctl() */
-#if TARGET_ABI_BITS == 32
- abi_ulong __unused3;
-#endif
- abi_int shm_cpid; /* pid of creator */
- abi_int shm_lpid; /* pid of last shmop */
- abi_ulong shm_nattch; /* number of current attaches */
- abi_ulong __unused4;
- abi_ulong __unused5;
-};
-
-#endif
diff --git a/linux-user/sparc64/target_syscall.h b/linux-user/sparc64/target_syscall.h
deleted file mode 100644
index 696a68b1ed..0000000000
--- a/linux-user/sparc64/target_syscall.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef SPARC64_TARGET_SYSCALL_H
-#define SPARC64_TARGET_SYSCALL_H
-
-#include "../sparc/target_errno.h"
-
-struct target_pt_regs {
- abi_ulong u_regs[16];
- abi_ulong tstate;
- abi_ulong pc;
- abi_ulong npc;
- abi_ulong y;
- abi_ulong fprs;
-};
-
-#define UNAME_MACHINE "sparc64"
-#define UNAME_MINIMUM_RELEASE "2.6.32"
-
-/* SPARC kernels don't define this in their Kconfig, but they have the
- * same ABI as if they did, implemented by sparc-specific code which fishes
- * directly in the u_regs() struct for half the parameters in sparc_do_fork()
- * and copy_thread().
- */
-#define TARGET_CLONE_BACKWARDS
-#define TARGET_MINSIGSTKSZ 4096
-#define TARGET_MCL_CURRENT 0x2000
-#define TARGET_MCL_FUTURE 0x4000
-#define TARGET_MCL_ONFAULT 0x8000
-
-#define TARGET_FORCE_SHMLBA
-
-static inline abi_ulong target_shmlba(CPUSPARCState *env)
-{
- return MAX(TARGET_PAGE_SIZE, 16 * 1024);
-}
-#endif /* SPARC64_TARGET_SYSCALL_H */
diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h
deleted file mode 100644
index 1ab1e80db5..0000000000
--- a/linux-user/sparc64/termbits.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/* from asm/termbits.h */
-
-#ifndef LINUX_USER_SPARC64_TERMBITS_H
-#define LINUX_USER_SPARC64_TERMBITS_H
-
-#define TARGET_NCCS 19
-
-typedef unsigned char target_cc_t; /* cc_t */
-typedef unsigned int target_speed_t; /* speed_t */
-typedef unsigned int target_tcflag_t; /* tcflag_t */
-
-struct target_termios {
- target_tcflag_t c_iflag; /* input mode flags */
- target_tcflag_t c_oflag; /* output mode flags */
- target_tcflag_t c_cflag; /* control mode flags */
- target_tcflag_t c_lflag; /* local mode flags */
- target_cc_t c_line; /* line discipline */
- target_cc_t c_cc[TARGET_NCCS]; /* control characters */
-};
-
-
-/* c_cc characters */
-#define TARGET_VINTR 0
-#define TARGET_VQUIT 1
-#define TARGET_VERASE 2
-#define TARGET_VKILL 3
-#define TARGET_VEOF 4
-#define TARGET_VEOL 5
-#define TARGET_VEOL2 6
-#define TARGET_VSWTC 7
-#define TARGET_VSTART 8
-#define TARGET_VSTOP 9
-
-#define TARGET_VSUSP 10
-#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
-#define TARGET_VREPRINT 12
-#define TARGET_VDISCARD 13
-#define TARGET_VWERASE 14
-#define TARGET_VLNEXT 15
-
-/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
- * shared with eof/eol
- */
-#define TARGET_VMIN TARGET_VEOF
-#define TARGET_VTIME TARGET_VEOL
-
-/* c_iflag bits */
-#define TARGET_IGNBRK 0x00000001
-#define TARGET_BRKINT 0x00000002
-#define TARGET_IGNPAR 0x00000004
-#define TARGET_PARMRK 0x00000008
-#define TARGET_INPCK 0x00000010
-#define TARGET_ISTRIP 0x00000020
-#define TARGET_INLCR 0x00000040
-#define TARGET_IGNCR 0x00000080
-#define TARGET_ICRNL 0x00000100
-#define TARGET_IUCLC 0x00000200
-#define TARGET_IXON 0x00000400
-#define TARGET_IXANY 0x00000800
-#define TARGET_IXOFF 0x00001000
-#define TARGET_IMAXBEL 0x00002000
-#define TARGET_IUTF8 0x00004000
-
-/* c_oflag bits */
-#define TARGET_OPOST 0x00000001
-#define TARGET_OLCUC 0x00000002
-#define TARGET_ONLCR 0x00000004
-#define TARGET_OCRNL 0x00000008
-#define TARGET_ONOCR 0x00000010
-#define TARGET_ONLRET 0x00000020
-#define TARGET_OFILL 0x00000040
-#define TARGET_OFDEL 0x00000080
-#define TARGET_NLDLY 0x00000100
-#define TARGET_NL0 0x00000000
-#define TARGET_NL1 0x00000100
-#define TARGET_CRDLY 0x00000600
-#define TARGET_CR0 0x00000000
-#define TARGET_CR1 0x00000200
-#define TARGET_CR2 0x00000400
-#define TARGET_CR3 0x00000600
-#define TARGET_TABDLY 0x00001800
-#define TARGET_TAB0 0x00000000
-#define TARGET_TAB1 0x00000800
-#define TARGET_TAB2 0x00001000
-#define TARGET_TAB3 0x00001800
-#define TARGET_XTABS 0x00001800
-#define TARGET_BSDLY 0x00002000
-#define TARGET_BS0 0x00000000
-#define TARGET_BS1 0x00002000
-#define TARGET_VTDLY 0x00004000
-#define TARGET_VT0 0x00000000
-#define TARGET_VT1 0x00004000
-#define TARGET_FFDLY 0x00008000
-#define TARGET_FF0 0x00000000
-#define TARGET_FF1 0x00008000
-#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
-#define TARGET_WRAP 0x00020000 /* SUNOS specific */
-
-/* c_cflag bit meaning */
-#define TARGET_CBAUD 0x0000100f
-#define TARGET_B0 0x00000000 /* hang up */
-#define TARGET_B50 0x00000001
-#define TARGET_B75 0x00000002
-#define TARGET_B110 0x00000003
-#define TARGET_B134 0x00000004
-#define TARGET_B150 0x00000005
-#define TARGET_B200 0x00000006
-#define TARGET_B300 0x00000007
-#define TARGET_B600 0x00000008
-#define TARGET_B1200 0x00000009
-#define TARGET_B1800 0x0000000a
-#define TARGET_B2400 0x0000000b
-#define TARGET_B4800 0x0000000c
-#define TARGET_B9600 0x0000000d
-#define TARGET_B19200 0x0000000e
-#define TARGET_B38400 0x0000000f
-#define TARGET_EXTA B19200
-#define TARGET_EXTB B38400
-#define TARGET_CSIZE 0x00000030
-#define TARGET_CS5 0x00000000
-#define TARGET_CS6 0x00000010
-#define TARGET_CS7 0x00000020
-#define TARGET_CS8 0x00000030
-#define TARGET_CSTOPB 0x00000040
-#define TARGET_CREAD 0x00000080
-#define TARGET_PARENB 0x00000100
-#define TARGET_PARODD 0x00000200
-#define TARGET_HUPCL 0x00000400
-#define TARGET_CLOCAL 0x00000800
-#define TARGET_CBAUDEX 0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
-#define TARGET_B57600 0x00001001
-#define TARGET_B115200 0x00001002
-#define TARGET_B230400 0x00001003
-#define TARGET_B460800 0x00001004
-/* This is what we can do with the Zilogs. */
-#define TARGET_B76800 0x00001005
-/* This is what we can do with the SAB82532. */
-#define TARGET_B153600 0x00001006
-#define TARGET_B307200 0x00001007
-#define TARGET_B614400 0x00001008
-#define TARGET_B921600 0x00001009
-/* And these are the rest... */
-#define TARGET_B500000 0x0000100a
-#define TARGET_B576000 0x0000100b
-#define TARGET_B1000000 0x0000100c
-#define TARGET_B1152000 0x0000100d
-#define TARGET_B1500000 0x0000100e
-#define TARGET_B2000000 0x0000100f
-/* These have totally bogus values and nobody uses them
- so far. Later on we'd have to use say 0x10000x and
- adjust CBAUD constant and drivers accordingly.
-#define B2500000 0x00001010
-#define B3000000 0x00001011
-#define B3500000 0x00001012
-#define B4000000 0x00001013 */
-#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
-#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
-#define TARGET_CRTSCTS 0x80000000 /* flow control */
-
-/* c_lflag bits */
-#define TARGET_ISIG 0x00000001
-#define TARGET_ICANON 0x00000002
-#define TARGET_XCASE 0x00000004
-#define TARGET_ECHO 0x00000008
-#define TARGET_ECHOE 0x00000010
-#define TARGET_ECHOK 0x00000020
-#define TARGET_ECHONL 0x00000040
-#define TARGET_NOFLSH 0x00000080
-#define TARGET_TOSTOP 0x00000100
-#define TARGET_ECHOCTL 0x00000200
-#define TARGET_ECHOPRT 0x00000400
-#define TARGET_ECHOKE 0x00000800
-#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
-#define TARGET_FLUSHO 0x00002000
-#define TARGET_PENDIN 0x00004000
-#define TARGET_IEXTEN 0x00008000
-#define TARGET_EXTPROC 0x00010000
-
-/* ioctls */
-
-/* Big T */
-#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
-#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
-#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
-#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
-#define TARGET_TCSBRK TARGET_IO('T', 5)
-#define TARGET_TCXONC TARGET_IO('T', 6)
-#define TARGET_TCFLSH TARGET_IO('T', 7)
-#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
-#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
-#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
-#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
-
-/* Note that all the ioctls that are not available in Linux have a
- * double underscore on the front to: a) avoid some programs to
- * thing we support some ioctls under Linux (autoconfiguration stuff)
- */
-/* Little t */
-#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
-#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
-//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
-//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
-//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
-//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
-#define TARGET_TIOCEXCL TARGET_IO('t', 13)
-#define TARGET_TIOCNXCL TARGET_IO('t', 14)
-//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
-//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
-//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
-//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
-//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
-//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
-//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
-#define TARGET_TIOCCONS TARGET_IO('t', 36)
-//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
-//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
-#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
-#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
-//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
-#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
-//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
-#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
-#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
-#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
-#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
-#define TARGET_TIOCSTART TARGET_IO('t', 110)
-#define TARGET_TIOCSTOP TARGET_IO('t', 111)
-#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
-#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
-#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
-#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
-//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
-//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
-/* 118 is the non-posix setpgrp tty ioctl */
-/* 119 is the non-posix getpgrp tty ioctl */
-//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
-//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
-#define TARGET_TIOCCBRK TARGET_IO('t', 122)
-#define TARGET_TIOCSBRK TARGET_IO('t', 123)
-//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
-//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
-//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
-//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
-//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
-//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
-#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
-#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
-#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
-/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
-#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
-#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
-#define TARGET_TIOCGPTPEER TARGET_IO('t', 137) /* Safely open the slave */
-
-/* Little f */
-#define TARGET_FIOCLEX TARGET_IO('f', 1)
-#define TARGET_FIONCLEX TARGET_IO('f', 2)
-#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
-#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
-#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
-#define TARGET_TIOCINQ TARGET_FIONREAD
-
-/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
- * someday. This is completely bogus, I know...
- */
-//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
-//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
-
-/* Linux specific, no SunOS equivalent. */
-#define TARGET_TIOCLINUX 0x541C
-#define TARGET_TIOCGSERIAL 0x541E
-#define TARGET_TIOCSSERIAL 0x541F
-#define TARGET_TCSBRKP 0x5425
-#define TARGET_TIOCTTYGSTRUCT 0x5426
-#define TARGET_TIOCSERCONFIG 0x5453
-#define TARGET_TIOCSERGWILD 0x5454
-#define TARGET_TIOCSERSWILD 0x5455
-#define TARGET_TIOCGLCKTRMIOS 0x5456
-#define TARGET_TIOCSLCKTRMIOS 0x5457
-#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
-#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
-#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
-#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
-#define TARGET_TIOCMIWAIT 0x545C /* Wait input */
-#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
-
-#endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index e969121b6c..cce0a5d1e3 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1109,6 +1109,12 @@ UNUSED static struct flags clone_flags[] = {
#if defined(CLONE_NEWNET)
FLAG_GENERIC(CLONE_NEWNET),
#endif
+#if defined(CLONE_NEWCGROUP)
+ FLAG_GENERIC(CLONE_NEWCGROUP),
+#endif
+#if defined(CLONE_NEWTIME)
+ FLAG_GENERIC(CLONE_NEWTIME),
+#endif
#if defined(CLONE_IO)
FLAG_GENERIC(CLONE_IO),
#endif
@@ -2335,7 +2341,7 @@ print_linkat(void *cpu_env, const struct syscallname *name,
}
#endif
-#ifdef TARGET_NR__llseek
+#if defined(TARGET_NR__llseek) || defined(TARGET_NR_llseek)
static void
print__llseek(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
@@ -2355,6 +2361,7 @@ print__llseek(void *cpu_env, const struct syscallname *name,
qemu_log("%s", whence);
print_syscall_epilogue(name);
}
+#define print_llseek print__llseek
#endif
#ifdef TARGET_NR_lseek
@@ -3467,6 +3474,18 @@ print_unlinkat(void *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_unshare
+static void
+print_unshare(void *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ print_syscall_prologue(name);
+ print_flags(clone_flags, arg0, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_utime
static void
print_utime(void *cpu_env, const struct syscallname *name,
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 084048ab96..278596acd1 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -511,6 +511,9 @@
#ifdef TARGET_NR__llseek
{ TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL },
#endif
+#ifdef TARGET_NR_llseek
+{ TARGET_NR_llseek, "llseek" , NULL, print_llseek, NULL },
+#endif
#ifdef TARGET_NR_lock
{ TARGET_NR_lock, "lock" , NULL, NULL, NULL },
#endif
@@ -1573,7 +1576,7 @@
{ TARGET_NR_unlinkat, "unlinkat" , NULL, print_unlinkat, NULL },
#endif
#ifdef TARGET_NR_unshare
-{ TARGET_NR_unshare, "unshare" , NULL, NULL, NULL },
+{ TARGET_NR_unshare, "unshare" , NULL, print_unshare, NULL },
#endif
#ifdef TARGET_NR_userfaultfd
{ TARGET_NR_userfaultfd, "userfaultfd" , NULL, NULL, NULL },
@@ -1665,3 +1668,6 @@
#ifdef TARGET_NR_statx
{ TARGET_NR_statx, "statx", NULL, print_statx, NULL },
#endif
+#ifdef TARGET_NR_copy_file_range
+{ TARGET_NR_copy_file_range, "copy_file_range", "%s(%d,%p,%d,%p,"TARGET_ABI_FMT_lu",%u)", NULL, NULL },
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 95d79ddc43..c9f812091c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8980,29 +8980,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_sigaction
case TARGET_NR_sigaction:
{
-#if defined(TARGET_ALPHA)
- struct target_sigaction act, oact, *pact = 0;
- struct target_old_sigaction *old_act;
- if (arg2) {
- if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1))
- return -TARGET_EFAULT;
- act._sa_handler = old_act->_sa_handler;
- target_siginitset(&act.sa_mask, old_act->sa_mask);
- act.sa_flags = old_act->sa_flags;
- act.sa_restorer = 0;
- unlock_user_struct(old_act, arg2, 0);
- pact = &act;
- }
- ret = get_errno(do_sigaction(arg1, pact, &oact));
- if (!is_error(ret) && arg3) {
- if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
- return -TARGET_EFAULT;
- old_act->_sa_handler = oact._sa_handler;
- old_act->sa_mask = oact.sa_mask.sig[0];
- old_act->sa_flags = oact.sa_flags;
- unlock_user_struct(old_act, arg3, 1);
- }
-#elif defined(TARGET_MIPS)
+#if defined(TARGET_MIPS)
struct target_sigaction act, oact, *pact, *old_act;
if (arg2) {
@@ -9017,7 +8995,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
pact = NULL;
}
- ret = get_errno(do_sigaction(arg1, pact, &oact));
+ ret = get_errno(do_sigaction(arg1, pact, &oact, 0));
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
@@ -9039,23 +9017,24 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
act._sa_handler = old_act->_sa_handler;
target_siginitset(&act.sa_mask, old_act->sa_mask);
act.sa_flags = old_act->sa_flags;
+#ifdef TARGET_ARCH_HAS_SA_RESTORER
act.sa_restorer = old_act->sa_restorer;
-#ifdef TARGET_ARCH_HAS_KA_RESTORER
- act.ka_restorer = 0;
#endif
unlock_user_struct(old_act, arg2, 0);
pact = &act;
} else {
pact = NULL;
}
- ret = get_errno(do_sigaction(arg1, pact, &oact));
+ ret = get_errno(do_sigaction(arg1, pact, &oact, 0));
if (!is_error(ret) && arg3) {
if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0))
return -TARGET_EFAULT;
old_act->_sa_handler = oact._sa_handler;
old_act->sa_mask = oact.sa_mask.sig[0];
old_act->sa_flags = oact.sa_flags;
+#ifdef TARGET_ARCH_HAS_SA_RESTORER
old_act->sa_restorer = oact.sa_restorer;
+#endif
unlock_user_struct(old_act, arg3, 1);
}
#endif
@@ -9064,77 +9043,43 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#endif
case TARGET_NR_rt_sigaction:
{
-#if defined(TARGET_ALPHA)
- /* For Alpha and SPARC this is a 5 argument syscall, with
+ /*
+ * For Alpha and SPARC this is a 5 argument syscall, with
* a 'restorer' parameter which must be copied into the
* sa_restorer field of the sigaction struct.
* For Alpha that 'restorer' is arg5; for SPARC it is arg4,
* and arg5 is the sigsetsize.
- * Alpha also has a separate rt_sigaction struct that it uses
- * here; SPARC uses the usual sigaction struct.
*/
- struct target_rt_sigaction *rt_act;
- struct target_sigaction act, oact, *pact = 0;
-
- if (arg4 != sizeof(target_sigset_t)) {
- return -TARGET_EINVAL;
- }
- if (arg2) {
- if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1))
- return -TARGET_EFAULT;
- act._sa_handler = rt_act->_sa_handler;
- act.sa_mask = rt_act->sa_mask;
- act.sa_flags = rt_act->sa_flags;
- act.sa_restorer = arg5;
- unlock_user_struct(rt_act, arg2, 0);
- pact = &act;
- }
- ret = get_errno(do_sigaction(arg1, pact, &oact));
- if (!is_error(ret) && arg3) {
- if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0))
- return -TARGET_EFAULT;
- rt_act->_sa_handler = oact._sa_handler;
- rt_act->sa_mask = oact.sa_mask;
- rt_act->sa_flags = oact.sa_flags;
- unlock_user_struct(rt_act, arg3, 1);
- }
-#else
-#ifdef TARGET_SPARC
+#if defined(TARGET_ALPHA)
+ target_ulong sigsetsize = arg4;
+ target_ulong restorer = arg5;
+#elif defined(TARGET_SPARC)
target_ulong restorer = arg4;
target_ulong sigsetsize = arg5;
#else
target_ulong sigsetsize = arg4;
+ target_ulong restorer = 0;
#endif
- struct target_sigaction *act;
- struct target_sigaction *oact;
+ struct target_sigaction *act = NULL;
+ struct target_sigaction *oact = NULL;
if (sigsetsize != sizeof(target_sigset_t)) {
return -TARGET_EINVAL;
}
- if (arg2) {
- if (!lock_user_struct(VERIFY_READ, act, arg2, 1)) {
- return -TARGET_EFAULT;
- }
-#ifdef TARGET_ARCH_HAS_KA_RESTORER
- act->ka_restorer = restorer;
-#endif
- } else {
- act = NULL;
+ if (arg2 && !lock_user_struct(VERIFY_READ, act, arg2, 1)) {
+ return -TARGET_EFAULT;
}
- if (arg3) {
- if (!lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
- ret = -TARGET_EFAULT;
- goto rt_sigaction_fail;
+ if (arg3 && !lock_user_struct(VERIFY_WRITE, oact, arg3, 0)) {
+ ret = -TARGET_EFAULT;
+ } else {
+ ret = get_errno(do_sigaction(arg1, act, oact, restorer));
+ if (oact) {
+ unlock_user_struct(oact, arg3, 1);
}
- } else
- oact = NULL;
- ret = get_errno(do_sigaction(arg1, act, oact));
- rt_sigaction_fail:
- if (act)
+ }
+ if (act) {
unlock_user_struct(act, arg2, 0);
- if (oact)
- unlock_user_struct(oact, arg3, 1);
-#endif
+ }
}
return ret;
#ifdef TARGET_NR_sgetmask /* not on alpha */
@@ -11195,8 +11140,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
return ret;
}
case TARGET_NR_sigaltstack:
- return do_sigaltstack(arg1, arg2,
- get_sp_from_cpustate((CPUArchState *)cpu_env));
+ return do_sigaltstack(arg1, arg2, cpu_env);
#ifdef CONFIG_SENDFILE
#ifdef TARGET_NR_sendfile
@@ -13245,8 +13189,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
poutoff = &outoff;
}
+ /* Do not sign-extend the count parameter. */
ret = get_errno(safe_copy_file_range(arg1, pinoff, arg3, poutoff,
- arg5, arg6));
+ (abi_ulong)arg5, arg6));
if (!is_error(ret) && ret > 0) {
if (arg2) {
if (put_user_u64(inoff, arg2)) {
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 25be414727..18b031a2f6 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -492,7 +492,7 @@ void target_to_host_old_sigset(sigset_t *sigset,
const abi_ulong *old_sigset);
struct target_sigaction;
int do_sigaction(int sig, const struct target_sigaction *act,
- struct target_sigaction *oact);
+ struct target_sigaction *oact, abi_ulong ka_restorer);
#include "target_signal.h"
@@ -501,27 +501,12 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#endif
#if defined(TARGET_ALPHA)
-struct target_old_sigaction {
- abi_ulong _sa_handler;
- abi_ulong sa_mask;
- int32_t sa_flags;
-};
-
-struct target_rt_sigaction {
- abi_ulong _sa_handler;
- abi_ulong sa_flags;
- target_sigset_t sa_mask;
-};
+typedef int32_t target_old_sa_flags;
+#else
+typedef abi_ulong target_old_sa_flags;
+#endif
-/* This is the struct used inside the kernel. The ka_restorer
- field comes from the 5th argument to sys_rt_sigaction. */
-struct target_sigaction {
- abi_ulong _sa_handler;
- abi_ulong sa_flags;
- target_sigset_t sa_mask;
- abi_ulong sa_restorer;
-};
-#elif defined(TARGET_MIPS)
+#if defined(TARGET_MIPS)
struct target_sigaction {
uint32_t sa_flags;
#if defined(TARGET_ABI_MIPSN32)
@@ -539,7 +524,7 @@ struct target_sigaction {
struct target_old_sigaction {
abi_ulong _sa_handler;
abi_ulong sa_mask;
- abi_ulong sa_flags;
+ target_old_sa_flags sa_flags;
#ifdef TARGET_ARCH_HAS_SA_RESTORER
abi_ulong sa_restorer;
#endif
diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c
index 590f0313ff..72771e1294 100644
--- a/linux-user/xtensa/signal.c
+++ b/linux-user/xtensa/signal.c
@@ -253,12 +253,8 @@ long do_rt_sigreturn(CPUXtensaState *env)
set_sigmask(&set);
restore_sigcontext(env, frame);
+ target_restore_altstack(&frame->uc.tuc_stack, env);
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) {
- goto badframe;
- }
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
diff --git a/meson.build b/meson.build
index 0b41ff4118..1559e8d873 100644
--- a/meson.build
+++ b/meson.build
@@ -847,7 +847,7 @@ if 'CONFIG_VTE' in config_host
link_args: config_host['VTE_LIBS'].split())
endif
x11 = not_found
-if gtkx11.found() or 'lm32-softmmu' in target_dirs
+if gtkx11.found()
x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found(),
kwargs: static_kwargs)
endif
@@ -1210,11 +1210,9 @@ disassemblers = {
'i386' : ['CONFIG_I386_DIS'],
'x86_64' : ['CONFIG_I386_DIS'],
'x32' : ['CONFIG_I386_DIS'],
- 'lm32' : ['CONFIG_LM32_DIS'],
'm68k' : ['CONFIG_M68K_DIS'],
'microblaze' : ['CONFIG_MICROBLAZE_DIS'],
'mips' : ['CONFIG_MIPS_DIS'],
- 'moxie' : ['CONFIG_MOXIE_DIS'],
'nios2' : ['CONFIG_NIOS2_DIS'],
'or1k' : ['CONFIG_OPENRISC_DIS'],
'ppc' : ['CONFIG_PPC_DIS'],
@@ -1824,6 +1822,7 @@ if have_system
'hw/misc/macio',
'hw/net',
'hw/net/can',
+ 'hw/nvme',
'hw/nvram',
'hw/pci',
'hw/pci-host',
@@ -2635,7 +2634,6 @@ if have_block
summary_info += {'vvfat support': config_host.has_key('CONFIG_VVFAT')}
summary_info += {'qed support': config_host.has_key('CONFIG_QED')}
summary_info += {'parallels support': config_host.has_key('CONFIG_PARALLELS')}
- summary_info += {'sheepdog support': config_host.has_key('CONFIG_SHEEPDOG')}
summary_info += {'FUSE exports': fuse.found()}
endif
summary(summary_info, bool_yn: true, section: 'Block layer support')
diff --git a/migration/meson.build b/migration/meson.build
index 3ecedce94d..f8714dcb15 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -31,4 +31,5 @@ softmmu_ss.add(when: ['CONFIG_RDMA', rdma], if_true: files('rdma.c'))
softmmu_ss.add(when: 'CONFIG_LIVE_BLOCK_MIGRATION', if_true: files('block.c'))
softmmu_ss.add(when: zstd, if_true: files('multifd-zstd.c'))
-specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: files('dirtyrate.c', 'ram.c'))
+specific_ss.add(when: 'CONFIG_SOFTMMU',
+ if_true: files('dirtyrate.c', 'ram.c', 'target.c'))
diff --git a/migration/migration.c b/migration/migration.c
index 8ca034136b..1885860d7b 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -60,10 +60,6 @@
#include "qemu/yank.h"
#include "sysemu/cpus.h"
-#ifdef CONFIG_VFIO
-#include "hw/vfio/vfio-common.h"
-#endif
-
#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */
/* Amount of time to allocate to each "chunk" of bandwidth-throttled
@@ -223,13 +219,18 @@ void migration_object_init(void)
dirty_bitmap_mig_init();
}
+void migration_cancel(void)
+{
+ migrate_fd_cancel(current_migration);
+}
+
void migration_shutdown(void)
{
/*
* Cancel the current migration - that will (eventually)
* stop the migration using this structure
*/
- migrate_fd_cancel(current_migration);
+ migration_cancel();
object_unref(OBJECT(current_migration));
/*
@@ -1059,41 +1060,27 @@ static void populate_disk_info(MigrationInfo *info)
}
}
-static void populate_vfio_info(MigrationInfo *info)
-{
-#ifdef CONFIG_VFIO
- if (vfio_mig_active()) {
- info->has_vfio = true;
- info->vfio = g_malloc0(sizeof(*info->vfio));
- info->vfio->transferred = vfio_mig_bytes_transferred();
- }
-#endif
-}
-
static void fill_source_migration_info(MigrationInfo *info)
{
MigrationState *s = migrate_get_current();
+ GSList *cur_blocker = migration_blockers;
- info->blocked = migration_is_blocked(NULL);
- info->has_blocked_reasons = info->blocked;
info->blocked_reasons = NULL;
- if (info->blocked) {
- GSList *cur_blocker = migration_blockers;
- /*
- * There are two types of reasons a migration might be blocked;
- * a) devices marked in VMState as non-migratable, and
- * b) Explicit migration blockers
- * We need to add both of them here.
- */
- qemu_savevm_non_migratable_list(&info->blocked_reasons);
+ /*
+ * There are two types of reasons a migration might be blocked;
+ * a) devices marked in VMState as non-migratable, and
+ * b) Explicit migration blockers
+ * We need to add both of them here.
+ */
+ qemu_savevm_non_migratable_list(&info->blocked_reasons);
- while (cur_blocker) {
- QAPI_LIST_PREPEND(info->blocked_reasons,
- g_strdup(error_get_pretty(cur_blocker->data)));
- cur_blocker = g_slist_next(cur_blocker);
- }
+ while (cur_blocker) {
+ QAPI_LIST_PREPEND(info->blocked_reasons,
+ g_strdup(error_get_pretty(cur_blocker->data)));
+ cur_blocker = g_slist_next(cur_blocker);
}
+ info->has_blocked_reasons = info->blocked_reasons != NULL;
switch (s->state) {
case MIGRATION_STATUS_NONE:
@@ -2310,7 +2297,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
void qmp_migrate_cancel(Error **errp)
{
- migrate_fd_cancel(migrate_get_current());
+ migration_cancel();
}
void qmp_migrate_continue(MigrationStatus state, Error **errp)
diff --git a/migration/migration.h b/migration/migration.h
index db6708326b..b88bd8fe07 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -375,5 +375,8 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque);
void migration_make_urgent_request(void);
void migration_consume_urgent_request(void);
bool migration_rate_limit(void);
+void migration_cancel(void);
+
+void populate_vfio_info(MigrationInfo *info);
#endif
diff --git a/migration/multifd.c b/migration/multifd.c
index a6677c45c8..0a4803cfcc 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -361,7 +361,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
if (offset > (block->used_length - qemu_target_page_size())) {
error_setg(errp, "multifd: offset too long %" PRIu64
" (max " RAM_ADDR_FMT ")",
- offset, block->max_length);
+ offset, block->used_length);
return -1;
}
p->pages->iov[i].iov_base = block->host + offset;
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index ab482adef1..2e9697bdd2 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -17,6 +17,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/rcu.h"
#include "exec/target_page.h"
#include "migration.h"
#include "qemu-file.h"
@@ -30,6 +31,7 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/boards.h"
+#include "exec/ramblock.h"
/* Arbitrary limit on size of each discard command,
* keeps them around ~200 bytes
@@ -453,6 +455,13 @@ static int init_range(RAMBlock *rb, void *opaque)
trace_postcopy_init_range(block_name, host_addr, offset, length);
/*
+ * Save the used_length before running the guest. In case we have to
+ * resize RAM blocks when syncing RAM block sizes from the source during
+ * precopy, we'll update it manually via the ram block notifier.
+ */
+ rb->postcopy_length = length;
+
+ /*
* We need the whole of RAM to be truly empty for postcopy, so things
* like ROMs and any data tables built during init must be zero'd
* - we're going to get the copy from the source anyway.
@@ -474,7 +483,7 @@ static int cleanup_range(RAMBlock *rb, void *opaque)
const char *block_name = qemu_ram_get_idstr(rb);
void *host_addr = qemu_ram_get_host_addr(rb);
ram_addr_t offset = qemu_ram_get_offset(rb);
- ram_addr_t length = qemu_ram_get_used_length(rb);
+ ram_addr_t length = rb->postcopy_length;
MigrationIncomingState *mis = opaque;
struct uffdio_range range_struct;
trace_postcopy_cleanup_range(block_name, host_addr, offset, length);
@@ -580,7 +589,7 @@ static int nhp_range(RAMBlock *rb, void *opaque)
const char *block_name = qemu_ram_get_idstr(rb);
void *host_addr = qemu_ram_get_host_addr(rb);
ram_addr_t offset = qemu_ram_get_offset(rb);
- ram_addr_t length = qemu_ram_get_used_length(rb);
+ ram_addr_t length = rb->postcopy_length;
trace_postcopy_nhp_range(block_name, host_addr, offset, length);
/*
@@ -624,7 +633,7 @@ static int ram_block_enable_notify(RAMBlock *rb, void *opaque)
struct uffdio_register reg_struct;
reg_struct.range.start = (uintptr_t)qemu_ram_get_host_addr(rb);
- reg_struct.range.len = qemu_ram_get_used_length(rb);
+ reg_struct.range.len = rb->postcopy_length;
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
/* Now tell our userfault_fd that it's responsible for this area */
diff --git a/migration/ram.c b/migration/ram.c
index ace8ad431c..60ea913c54 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -240,7 +240,7 @@ int64_t ramblock_recv_bitmap_send(QEMUFile *file,
return -1;
}
- nbits = block->used_length >> TARGET_PAGE_BITS;
+ nbits = block->postcopy_length >> TARGET_PAGE_BITS;
/*
* Make sure the tmp bitmap buffer is big enough, e.g., on 32bit
@@ -311,10 +311,6 @@ struct RAMState {
ram_addr_t last_page;
/* last ram version we have seen */
uint32_t last_version;
- /* We are in the first round */
- bool ram_bulk_stage;
- /* The free page optimization is enabled */
- bool fpo_enabled;
/* How many times we have dirty too many pages */
int dirty_rate_high_cnt;
/* these variables are used for bitmap sync */
@@ -330,6 +326,8 @@ struct RAMState {
uint64_t xbzrle_pages_prev;
/* Amount of xbzrle encoded bytes since the beginning of the period */
uint64_t xbzrle_bytes_prev;
+ /* Start using XBZRLE (e.g., after the first round). */
+ bool xbzrle_enabled;
/* compression statistics since the beginning of the period */
/* amount of count that no free thread to compress data */
@@ -383,15 +381,6 @@ int precopy_notify(PrecopyNotifyReason reason, Error **errp)
return notifier_with_return_list_notify(&precopy_notifier_list, &pnd);
}
-void precopy_enable_free_page_optimization(void)
-{
- if (!ram_state) {
- return;
- }
-
- ram_state->fpo_enabled = true;
-}
-
uint64_t ram_bytes_remaining(void)
{
return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
@@ -664,7 +653,7 @@ static void mig_throttle_guest_down(uint64_t bytes_dirty_period,
*/
static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr)
{
- if (rs->ram_bulk_stage || !migrate_use_xbzrle()) {
+ if (!rs->xbzrle_enabled) {
return;
}
@@ -792,23 +781,12 @@ unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb,
{
unsigned long size = rb->used_length >> TARGET_PAGE_BITS;
unsigned long *bitmap = rb->bmap;
- unsigned long next;
if (ramblock_is_ignored(rb)) {
return size;
}
- /*
- * When the free page optimization is enabled, we need to check the bitmap
- * to send the non-free pages rather than all the pages in the bulk stage.
- */
- if (!rs->fpo_enabled && rs->ram_bulk_stage && start > 0) {
- next = start + 1;
- } else {
- next = find_next_bit(bitmap, size, start);
- }
-
- return next;
+ return find_next_bit(bitmap, size, start);
}
static inline bool migration_bitmap_clear_dirty(RAMState *rs,
@@ -1185,8 +1163,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
trace_ram_save_page(block->idstr, (uint64_t)offset, p);
XBZRLE_cache_lock();
- if (!rs->ram_bulk_stage && !migration_in_postcopy() &&
- migrate_use_xbzrle()) {
+ if (rs->xbzrle_enabled && !migration_in_postcopy()) {
pages = save_xbzrle_page(rs, &p, current_addr, block,
offset, last_stage);
if (!last_stage) {
@@ -1365,8 +1342,8 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again)
*again = false;
return false;
}
- if ((((ram_addr_t)pss->page) << TARGET_PAGE_BITS)
- >= pss->block->used_length) {
+ if (!offset_in_ramblock(pss->block,
+ ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)) {
/* Didn't find anything in this RAM Block */
pss->page = 0;
pss->block = QLIST_NEXT_RCU(pss->block, next);
@@ -1386,7 +1363,10 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again)
pss->block = QLIST_FIRST_RCU(&ram_list.blocks);
/* Flag that we've looped */
pss->complete_round = true;
- rs->ram_bulk_stage = false;
+ /* After the first round, enable XBZRLE. */
+ if (migrate_use_xbzrle()) {
+ rs->xbzrle_enabled = true;
+ }
}
/* Didn't find anything this time, but try again on the new block */
*again = true;
@@ -1801,14 +1781,6 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
if (block) {
/*
- * As soon as we start servicing pages out of order, then we have
- * to kill the bulk stage, since the bulk stage assumes
- * in (migration_bitmap_find_and_reset_dirty) that every page is
- * dirty, that's no longer true.
- */
- rs->ram_bulk_stage = false;
-
- /*
* We want the background search to continue from the queued page
* since the guest is likely to want other pages near to the page
* it just requested.
@@ -1891,7 +1863,7 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len)
rs->last_req_rb = ramblock;
}
trace_ram_save_queue_pages(ramblock->idstr, start, len);
- if (start + len > ramblock->used_length) {
+ if (!offset_in_ramblock(ramblock, start + len - 1)) {
error_report("%s request overrun start=" RAM_ADDR_FMT " len="
RAM_ADDR_FMT " blocklen=" RAM_ADDR_FMT,
__func__, start, len, ramblock->used_length);
@@ -1920,15 +1892,15 @@ static bool save_page_use_compression(RAMState *rs)
}
/*
- * If xbzrle is on, stop using the data compression after first
- * round of migration even if compression is enabled. In theory,
- * xbzrle can do better than compression.
+ * If xbzrle is enabled (e.g., after first round of migration), stop
+ * using the data compression. In theory, xbzrle can do better than
+ * compression.
*/
- if (rs->ram_bulk_stage || !migrate_use_xbzrle()) {
- return true;
+ if (rs->xbzrle_enabled) {
+ return false;
}
- return false;
+ return true;
}
/*
@@ -2041,6 +2013,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
int tmppages, pages = 0;
size_t pagesize_bits =
qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS;
+ unsigned long hostpage_boundary =
+ QEMU_ALIGN_UP(pss->page + 1, pagesize_bits);
unsigned long start_page = pss->page;
int res;
@@ -2051,25 +2025,27 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss,
do {
/* Check the pages is dirty and if it is send it */
- if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
- pss->page++;
- continue;
- }
+ if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
+ tmppages = ram_save_target_page(rs, pss, last_stage);
+ if (tmppages < 0) {
+ return tmppages;
+ }
- tmppages = ram_save_target_page(rs, pss, last_stage);
- if (tmppages < 0) {
- return tmppages;
+ pages += tmppages;
+ /*
+ * Allow rate limiting to happen in the middle of huge pages if
+ * something is sent in the current iteration.
+ */
+ if (pagesize_bits > 1 && tmppages > 0) {
+ migration_rate_limit();
+ }
}
-
- pages += tmppages;
- pss->page++;
- /* Allow rate limiting to happen in the middle of huge pages */
- migration_rate_limit();
- } while ((pss->page & (pagesize_bits - 1)) &&
+ pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page);
+ } while ((pss->page < hostpage_boundary) &&
offset_in_ramblock(pss->block,
((ram_addr_t)pss->page) << TARGET_PAGE_BITS));
- /* The offset we leave with is the last one we looked at */
- pss->page--;
+ /* The offset we leave with is the min boundary of host page and block */
+ pss->page = MIN(pss->page, hostpage_boundary) - 1;
res = ram_save_release_protection(rs, pss, start_page);
return (res < 0 ? res : pages);
@@ -2235,8 +2211,7 @@ static void ram_state_reset(RAMState *rs)
rs->last_sent_block = NULL;
rs->last_page = 0;
rs->last_version = ram_list.version;
- rs->ram_bulk_stage = true;
- rs->fpo_enabled = false;
+ rs->xbzrle_enabled = false;
}
#define MAX_WAIT 50 /* ms, half buffered_file limit */
@@ -2720,15 +2695,7 @@ static void ram_state_resume_prepare(RAMState *rs, QEMUFile *out)
/* This may not be aligned with current bitmaps. Recalculate. */
rs->migration_dirty_pages = pages;
- rs->last_seen_block = NULL;
- rs->last_sent_block = NULL;
- rs->last_page = 0;
- rs->last_version = ram_list.version;
- /*
- * Disable the bulk stage, otherwise we'll resend the whole RAM no
- * matter what we have sent.
- */
- rs->ram_bulk_stage = false;
+ ram_state_reset(rs);
/* Update RAMState cache of output QEMUFile */
rs->f = out;
@@ -3118,6 +3085,20 @@ static inline void *host_from_ram_block_offset(RAMBlock *block,
return block->host + offset;
}
+static void *host_page_from_ram_block_offset(RAMBlock *block,
+ ram_addr_t offset)
+{
+ /* Note: Explicitly no check against offset_in_ramblock(). */
+ return (void *)QEMU_ALIGN_DOWN((uintptr_t)(block->host + offset),
+ block->page_size);
+}
+
+static ram_addr_t host_page_offset_from_ram_block_offset(RAMBlock *block,
+ ram_addr_t offset)
+{
+ return ((uintptr_t)block->host + offset) & (block->page_size - 1);
+}
+
static inline void *colo_cache_from_block_offset(RAMBlock *block,
ram_addr_t offset, bool record_bitmap)
{
@@ -3345,16 +3326,9 @@ static void decompress_data_with_multi_threads(QEMUFile *f,
}
}
- /*
- * we must set ram_bulk_stage to false, otherwise in
- * migation_bitmap_find_dirty the bitmap will be unused and
- * all the pages in ram cache wil be flushed to the ram of
- * secondary VM.
- */
static void colo_init_ram_state(void)
{
ram_state_init(&ram_state);
- ram_state->ram_bulk_stage = false;
}
/*
@@ -3521,13 +3495,12 @@ static int ram_load_postcopy(QEMUFile *f)
MigrationIncomingState *mis = migration_incoming_get_current();
/* Temporary page that is later 'placed' */
void *postcopy_host_page = mis->postcopy_tmp_page;
- void *this_host = NULL;
+ void *host_page = NULL;
bool all_zero = true;
int target_pages = 0;
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
ram_addr_t addr;
- void *host = NULL;
void *page_buffer = NULL;
void *place_source = NULL;
RAMBlock *block = NULL;
@@ -3552,9 +3525,18 @@ static int ram_load_postcopy(QEMUFile *f)
if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE |
RAM_SAVE_FLAG_COMPRESS_PAGE)) {
block = ram_block_from_stream(f, flags);
+ if (!block) {
+ ret = -EINVAL;
+ break;
+ }
- host = host_from_ram_block_offset(block, addr);
- if (!host) {
+ /*
+ * Relying on used_length is racy and can result in false positives.
+ * We might place pages beyond used_length in case RAM was shrunk
+ * while in postcopy, which is fine - trying to place via
+ * UFFDIO_COPY/UFFDIO_ZEROPAGE will never segfault.
+ */
+ if (!block->host || addr >= block->postcopy_length) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
ret = -EINVAL;
break;
@@ -3572,19 +3554,17 @@ static int ram_load_postcopy(QEMUFile *f)
* of a host page in one chunk.
*/
page_buffer = postcopy_host_page +
- ((uintptr_t)host & (block->page_size - 1));
+ host_page_offset_from_ram_block_offset(block, addr);
+ /* If all TP are zero then we can optimise the place */
if (target_pages == 1) {
- this_host = (void *)QEMU_ALIGN_DOWN((uintptr_t)host,
- block->page_size);
- } else {
+ host_page = host_page_from_ram_block_offset(block, addr);
+ } else if (host_page != host_page_from_ram_block_offset(block,
+ addr)) {
/* not the 1st TP within the HP */
- if (QEMU_ALIGN_DOWN((uintptr_t)host, block->page_size) !=
- (uintptr_t)this_host) {
- error_report("Non-same host page %p/%p",
- host, this_host);
- ret = -EINVAL;
- break;
- }
+ error_report("Non-same host page %p/%p", host_page,
+ host_page_from_ram_block_offset(block, addr));
+ ret = -EINVAL;
+ break;
}
/*
@@ -3663,16 +3643,11 @@ static int ram_load_postcopy(QEMUFile *f)
}
if (!ret && place_needed) {
- /* This gets called at the last target page in the host page */
- void *place_dest = (void *)QEMU_ALIGN_DOWN((uintptr_t)host,
- block->page_size);
-
if (all_zero) {
- ret = postcopy_place_page_zero(mis, place_dest,
- block);
+ ret = postcopy_place_page_zero(mis, host_page, block);
} else {
- ret = postcopy_place_page(mis, place_dest,
- place_source, block);
+ ret = postcopy_place_page(mis, host_page, place_source,
+ block);
}
place_needed = false;
target_pages = 0;
@@ -3721,8 +3696,8 @@ void colo_flush_ram_cache(void)
while (block) {
offset = migration_bitmap_find_dirty(ram_state, block, offset);
- if (((ram_addr_t)offset) << TARGET_PAGE_BITS
- >= block->used_length) {
+ if (!offset_in_ramblock(block,
+ ((ram_addr_t)offset) << TARGET_PAGE_BITS)) {
offset = 0;
block = QLIST_NEXT_RCU(block, next);
} else {
@@ -4136,8 +4111,69 @@ static SaveVMHandlers savevm_ram_handlers = {
.resume_prepare = ram_resume_prepare,
};
+static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host,
+ size_t old_size, size_t new_size)
+{
+ PostcopyState ps = postcopy_state_get();
+ ram_addr_t offset;
+ RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset);
+ Error *err = NULL;
+
+ if (ramblock_is_ignored(rb)) {
+ return;
+ }
+
+ if (!migration_is_idle()) {
+ /*
+ * Precopy code on the source cannot deal with the size of RAM blocks
+ * changing at random points in time - especially after sending the
+ * RAM block sizes in the migration stream, they must no longer change.
+ * Abort and indicate a proper reason.
+ */
+ error_setg(&err, "RAM block '%s' resized during precopy.", rb->idstr);
+ migrate_set_error(migrate_get_current(), err);
+ error_free(err);
+ migration_cancel();
+ }
+
+ switch (ps) {
+ case POSTCOPY_INCOMING_ADVISE:
+ /*
+ * Update what ram_postcopy_incoming_init()->init_range() does at the
+ * time postcopy was advised. Syncing RAM blocks with the source will
+ * result in RAM resizes.
+ */
+ if (old_size < new_size) {
+ if (ram_discard_range(rb->idstr, old_size, new_size - old_size)) {
+ error_report("RAM block '%s' discard of resized RAM failed",
+ rb->idstr);
+ }
+ }
+ rb->postcopy_length = new_size;
+ break;
+ case POSTCOPY_INCOMING_NONE:
+ case POSTCOPY_INCOMING_RUNNING:
+ case POSTCOPY_INCOMING_END:
+ /*
+ * Once our guest is running, postcopy does no longer care about
+ * resizes. When growing, the new memory was not available on the
+ * source, no handler needed.
+ */
+ break;
+ default:
+ error_report("RAM block '%s' resized during postcopy state: %d",
+ rb->idstr, ps);
+ exit(-1);
+ }
+}
+
+static RAMBlockNotifier ram_mig_ram_notifier = {
+ .ram_block_resized = ram_mig_ram_block_resized,
+};
+
void ram_mig_init(void)
{
qemu_mutex_init(&XBZRLE.lock);
register_savevm_live("ram", 0, 4, &savevm_ram_handlers, &ram_state);
+ ram_block_notifier_add(&ram_mig_ram_notifier);
}
diff --git a/migration/target.c b/migration/target.c
new file mode 100644
index 0000000000..907ebf0a0a
--- /dev/null
+++ b/migration/target.c
@@ -0,0 +1,25 @@
+/*
+ * QEMU live migration - functions that need to be compiled target-specific
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2
+ * or (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-migration.h"
+#include "migration.h"
+
+#ifdef CONFIG_VFIO
+#include "hw/vfio/vfio-common.h"
+#endif
+
+void populate_vfio_info(MigrationInfo *info)
+{
+#ifdef CONFIG_VFIO
+ if (vfio_mig_active()) {
+ info->has_vfio = true;
+ info->vfio = g_malloc0(sizeof(*info->vfio));
+ info->vfio->transferred = vfio_mig_bytes_transferred();
+ }
+#endif
+}
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 0ad5b77477..d9bef63373 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -224,7 +224,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
migration_global_dump(mon);
- if (info->blocked) {
+ if (info->blocked_reasons) {
strList *reasons = info->blocked_reasons;
monitor_printf(mon, "Outgoing migration blocked:\n");
while (reasons) {
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 2b0308f933..092c527b6f 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -257,24 +257,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
trace_monitor_qmp_in_band_dequeue(req_obj,
req_obj->mon->qmp_requests->length);
- if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
- /*
- * Someone rescheduled us (probably because a new requests
- * came in), but we didn't actually yield. Do that now,
- * only to be immediately reentered and removed from the
- * list of scheduled coroutines.
- */
- qemu_coroutine_yield();
- }
-
- /*
- * Move the coroutine from iohandler_ctx to qemu_aio_context for
- * executing the command handler so that it can make progress if it
- * involves an AIO_WAIT_WHILE().
- */
- aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
- qemu_coroutine_yield();
-
/*
* @req_obj has a request, we hold req_obj->mon->qmp_queue_lock
*/
@@ -298,8 +280,30 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
monitor_resume(&mon->common);
}
+ /*
+ * Drop the queue mutex now, before yielding, otherwise we might
+ * deadlock if the main thread tries to lock it.
+ */
qemu_mutex_unlock(&mon->qmp_queue_lock);
+ if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) {
+ /*
+ * Someone rescheduled us (probably because a new requests
+ * came in), but we didn't actually yield. Do that now,
+ * only to be immediately reentered and removed from the
+ * list of scheduled coroutines.
+ */
+ qemu_coroutine_yield();
+ }
+
+ /*
+ * Move the coroutine from iohandler_ctx to qemu_aio_context for
+ * executing the command handler so that it can make progress if it
+ * involves an AIO_WAIT_WHILE().
+ */
+ aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
+ qemu_coroutine_yield();
+
/* Process request */
if (req_obj->req) {
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 5aaeac9f79..a560c1272f 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 29fd9019b8..cee9d2c63b 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -6,8 +6,8 @@ include ../../config-host.mak
CFLAGS = -O2 -g
quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1))
-cc-option = $(if $(shell $(CC) $1 -S -o /dev/null -xc /dev/null > /dev/null \
- 2>&1 && echo OK), $1, $2)
+cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
+ >/dev/null 2>&1 && echo OK),$2,$3)
VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.sh %.rc Kconfig% %.json.in
set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
@@ -30,10 +30,12 @@ OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o \
virtio.o virtio-scsi.o virtio-blkdev.o libc.o cio.o dasd-ipl.o
QEMU_CFLAGS := -Wall $(filter -W%, $(QEMU_CFLAGS))
+QEMU_CFLAGS += $(call cc-option,-Werror $(QEMU_CFLAGS),-Wno-stringop-overflow)
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
QEMU_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS), -fno-stack-protector)
-QEMU_CFLAGS += -msoft-float -march=z900
+QEMU_CFLAGS += -msoft-float
+QEMU_CFLAGS += $(call cc-option, $(QEMU_CFLAGS),-march=z900,-march=z10)
QEMU_CFLAGS += -std=gnu99
LDFLAGS += -Wl,-pie -nostdlib
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index 44df7d16af..56411ab3b6 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -213,7 +213,7 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
next_block_nr = eckd_block_num(&s1b->seek[i + 1].chs);
}
- if (next_block_nr) {
+ if (next_block_nr && !is_null_block_number(next_block_nr)) {
read_block(next_block_nr, s2_next_blk,
"Cannot read stage2 boot loader");
}
@@ -299,7 +299,7 @@ static void ipl_eckd_cdl(void)
sclp_print("Bad block size in zIPL section of IPL2 record.\n");
return;
}
- if (!mbr->dev_type == DEV_TYPE_ECKD) {
+ if (mbr->dev_type != DEV_TYPE_ECKD) {
sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n");
return;
}
diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h
index dfcfea0ff0..3d0731c4c6 100644
--- a/pc-bios/s390-ccw/helper.h
+++ b/pc-bios/s390-ccw/helper.h
@@ -31,7 +31,7 @@ static inline void *u32toptr(uint32_t n)
static inline void yield(void)
{
- asm volatile ("diag 0,0,0x44"
+ asm volatile ("diag %%r0,%%r0,0x44"
: :
: "memory", "cc");
}
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index b9c70d64a5..78f5f46533 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -64,8 +64,8 @@ void jump_to_IPL_code(uint64_t address)
* We use the load normal reset to keep r15 unchanged. jump_to_IPL_2
* can then use r15 as its stack pointer.
*/
- asm volatile("lghi 1,1\n\t"
- "diag 1,1,0x308\n\t"
+ asm volatile("lghi %%r1,1\n\t"
+ "diag %%r1,%%r1,0x308\n\t"
: : : "1", "memory");
panic("\n! IPL returns !\n");
}
@@ -82,8 +82,8 @@ void jump_to_low_kernel(void)
jump_to_IPL_code(KERN_IMAGE_START);
}
- /* Trying to get PSW at zero address */
- if (*((uint64_t *)0) & RESET_PSW_MASK) {
+ /* Trying to get PSW at zero address (pointed to by reset_psw) */
+ if (*reset_psw & RESET_PSW_MASK) {
/*
* Surely nobody will try running directly from lowcore, so
* let's use 0 as an indication that we want to load the reset
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index de8260a5d6..d601952d3e 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -36,9 +36,9 @@ static inline void enable_clock_int(void)
uint64_t tmp = 0;
asm volatile(
- "stctg 0,0,%0\n"
+ "stctg %%c0,%%c0,%0\n"
"oi 6+%0, 0x8\n"
- "lctlg 0,0,%0"
+ "lctlg %%c0,%%c0,%0"
: : "Q" (tmp) : "memory"
);
}
@@ -48,9 +48,9 @@ static inline void disable_clock_int(void)
uint64_t tmp = 0;
asm volatile(
- "stctg 0,0,%0\n"
+ "stctg %%c0,%%c0,%0\n"
"ni 6+%0, 0xf7\n"
- "lctlg 0,0,%0"
+ "lctlg %%c0,%%c0,%0"
: : "Q" (tmp) : "memory"
);
}
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
index 577c023afe..68b4d7edcb 100644
--- a/pc-bios/s390-ccw/netboot.mak
+++ b/pc-bios/s390-ccw/netboot.mak
@@ -6,7 +6,7 @@ NETOBJS := start.o sclp.o cio.o virtio.o virtio-net.o jump2ipl.o netmain.o
LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
-NETLDFLAGS := $(LDFLAGS) -Ttext=0x7800000
+NETLDFLAGS := $(LDFLAGS) -Wl,-Ttext=0x7800000
$(NETOBJS): QEMU_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 6cd92669e9..79db69ff54 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -89,6 +89,7 @@ bool menu_is_enabled_enum(void);
#define MAX_BOOT_ENTRIES 31
+__attribute__ ((__noreturn__))
static inline void panic(const char *string)
{
sclp_print(string);
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index ab49840db8..5d2c6e3381 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -54,7 +54,7 @@ static long kvm_hypercall(unsigned long nr, unsigned long param1,
register ulong r_param3 asm("4") = param3;
register long retval asm("2");
- asm volatile ("diag 2,4,0x500"
+ asm volatile ("diag %%r2,%%r4,0x500"
: "=d" (retval)
: "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3)
: "memory", "cc");
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
index 120bd40ca9..bc34af8a28 100644
--- a/pc-bios/s390-netboot.img
+++ b/pc-bios/s390-netboot.img
Binary files differ
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6d227924d0..2ea294129e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2818,7 +2818,6 @@
'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
- 'sheepdog',
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
##
@@ -3652,26 +3651,6 @@
'*server': ['InetSocketAddressBase'] } }
##
-# @BlockdevOptionsSheepdog:
-#
-# Driver specific block device options for sheepdog
-#
-# @vdi: Virtual disk image name
-# @server: The Sheepdog server to connect to
-# @snap-id: Snapshot ID
-# @tag: Snapshot tag name
-#
-# Only one of @snap-id and @tag may be present.
-#
-# Since: 2.9
-##
-{ 'struct': 'BlockdevOptionsSheepdog',
- 'data': { 'server': 'SocketAddress',
- 'vdi': 'str',
- '*snap-id': 'uint32',
- '*tag': 'str' } }
-
-##
# @ReplicationMode:
#
# An enumeration of replication modes.
@@ -4037,7 +4016,6 @@
'rbd': 'BlockdevOptionsRbd',
'replication': { 'type': 'BlockdevOptionsReplication',
'if': 'defined(CONFIG_REPLICATION)' },
- 'sheepdog': 'BlockdevOptionsSheepdog',
'ssh': 'BlockdevOptionsSsh',
'throttle': 'BlockdevOptionsThrottle',
'vdi': 'BlockdevOptionsGenericFormat',
@@ -4497,74 +4475,6 @@
##
-# @SheepdogRedundancyType:
-#
-# @full: Create a fully replicated vdi with x copies
-# @erasure-coded: Create an erasure coded vdi with x data strips and
-# y parity strips
-#
-# Since: 2.12
-##
-{ 'enum': 'SheepdogRedundancyType',
- 'data': [ 'full', 'erasure-coded' ] }
-
-##
-# @SheepdogRedundancyFull:
-#
-# @copies: Number of copies to use (between 1 and 31)
-#
-# Since: 2.12
-##
-{ 'struct': 'SheepdogRedundancyFull',
- 'data': { 'copies': 'int' }}
-
-##
-# @SheepdogRedundancyErasureCoded:
-#
-# @data-strips: Number of data strips to use (one of {2,4,8,16})
-# @parity-strips: Number of parity strips to use (between 1 and 15)
-#
-# Since: 2.12
-##
-{ 'struct': 'SheepdogRedundancyErasureCoded',
- 'data': { 'data-strips': 'int',
- 'parity-strips': 'int' }}
-
-##
-# @SheepdogRedundancy:
-#
-# Since: 2.12
-##
-{ 'union': 'SheepdogRedundancy',
- 'base': { 'type': 'SheepdogRedundancyType' },
- 'discriminator': 'type',
- 'data': { 'full': 'SheepdogRedundancyFull',
- 'erasure-coded': 'SheepdogRedundancyErasureCoded' } }
-
-##
-# @BlockdevCreateOptionsSheepdog:
-#
-# Driver specific image creation options for Sheepdog.
-#
-# @location: Where to store the new image file
-# @size: Size of the virtual disk in bytes
-# @backing-file: File name of a base image
-# @preallocation: Preallocation mode for the new image (default: off;
-# allowed values: off, full)
-# @redundancy: Redundancy of the image
-# @object-size: Object size of the image
-#
-# Since: 2.12
-##
-{ 'struct': 'BlockdevCreateOptionsSheepdog',
- 'data': { 'location': 'BlockdevOptionsSheepdog',
- 'size': 'size',
- '*backing-file': 'str',
- '*preallocation': 'PreallocMode',
- '*redundancy': 'SheepdogRedundancy',
- '*object-size': 'size' } }
-
-##
# @BlockdevCreateOptionsSsh:
#
# Driver specific image creation options for SSH.
@@ -4687,7 +4597,6 @@
'qcow2': 'BlockdevCreateOptionsQcow2',
'qed': 'BlockdevCreateOptionsQed',
'rbd': 'BlockdevCreateOptionsRbd',
- 'sheepdog': 'BlockdevCreateOptionsSheepdog',
'ssh': 'BlockdevCreateOptionsSsh',
'vdi': 'BlockdevCreateOptionsVdi',
'vhdx': 'BlockdevCreateOptionsVhdx',
@@ -5322,7 +5231,7 @@
#
# Notes: In transaction, if @name is empty, or any snapshot matching @name
# exists, the operation will fail. Only some image formats support it,
-# for example, qcow2, rbd, and sheepdog.
+# for example, qcow2, and rbd.
#
# Since: 1.7
##
diff --git a/qapi/machine.json b/qapi/machine.json
index 6e90d463fc..58a9c86b36 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -29,11 +29,11 @@
# Since: 3.0
##
{ 'enum' : 'SysEmuTarget',
- 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm32',
+ 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
- 'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc',
+ 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
- 'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32',
+ 'sh4eb', 'sparc', 'sparc64', 'tricore',
'x86_64', 'xtensa', 'xtensaeb' ] }
##
diff --git a/qapi/migration.json b/qapi/migration.json
index 0b17cce46b..7a5bdf9a0d 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -228,11 +228,6 @@
# Present and non-empty when migration is blocked.
# (since 6.0)
#
-# @blocked: True if outgoing migration is blocked (since 6.0)
-#
-# Features:
-# @deprecated: Member @blocked is deprecated. Use @blocked-reasons instead.
-#
# Since: 0.14
##
{ 'struct': 'MigrationInfo',
@@ -246,7 +241,6 @@
'*setup-time': 'int',
'*cpu-throttle-percentage': 'int',
'*error-desc': 'str',
- 'blocked': { 'type': 'bool', 'features': [ 'deprecated' ] },
'*blocked-reasons': ['str'],
'*postcopy-blocktime' : 'uint32',
'*postcopy-vcpu-blocktime': ['uint32'],
diff --git a/qapi/misc-target.json b/qapi/misc-target.json
index 0c7491cd82..6200c671be 100644
--- a/qapi/misc-target.json
+++ b/qapi/misc-target.json
@@ -23,7 +23,7 @@
##
{ 'event': 'RTC_CHANGE',
'data': { 'offset': 'int' },
- 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
+ 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' }
##
# @rtc-reset-reinjection:
diff --git a/qapi/qom.json b/qapi/qom.json
index cd0e76d564..40d70c434a 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -251,8 +251,8 @@
#
# @max_queue_size: the maximum number of packets to keep in the queue for
# comparing with incoming packets from @secondary_in. If the
-# queue is full and addtional packets are received, the
-# addtional packets are dropped. (default: 1024)
+# queue is full and additional packets are received, the
+# additional packets are dropped. (default: 1024)
#
# @vnet_hdr_support: if true, vnet header support is enabled (default: false)
#
diff --git a/qapi/transaction.json b/qapi/transaction.json
index 15ddebdbc3..894258d9e2 100644
--- a/qapi/transaction.json
+++ b/qapi/transaction.json
@@ -112,10 +112,10 @@
#
# On failure, the original disks pre-snapshot attempt will be used.
#
-# For internal snapshots, the dictionary contains the device and the snapshot's
-# name. If an internal snapshot matching name already exists, the request will
-# be rejected. Only some image formats support it, for example, qcow2, rbd,
-# and sheepdog.
+# For internal snapshots, the dictionary contains the device and the
+# snapshot's name. If an internal snapshot matching name already exists,
+# the request will be rejected. Only some image formats support it, for
+# example, qcow2, and rbd,
#
# On failure, qemu will try delete the newly created internal snapshot in the
# transaction. When an I/O error occurs during deletion, the user needs to fix
diff --git a/qemu-edid.c b/qemu-edid.c
index 1cd6a95172..c3a9fba10d 100644
--- a/qemu-edid.c
+++ b/qemu-edid.c
@@ -41,7 +41,8 @@ static void usage(FILE *out)
int main(int argc, char *argv[])
{
FILE *outfile = NULL;
- uint8_t blob[256];
+ uint8_t blob[512];
+ size_t size;
uint32_t dpi = 100;
int rc;
@@ -119,7 +120,8 @@ int main(int argc, char *argv[])
memset(blob, 0, sizeof(blob));
qemu_edid_generate(blob, sizeof(blob), &info);
- fwrite(blob, sizeof(blob), 1, outfile);
+ size = qemu_edid_size(blob);
+ fwrite(blob, size, 1, outfile);
fflush(outfile);
exit(0);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 97611969cb..998b67186d 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2457,9 +2457,12 @@ static const cmdinfo_t help_cmd = {
.oneline = "help for one or all commands",
};
+/*
+ * Called with aio context of blk acquired. Or with qemu_get_aio_context()
+ * context acquired if blk is NULL.
+ */
int qemuio_command(BlockBackend *blk, const char *cmd)
{
- AioContext *ctx;
char *input;
const cmdinfo_t *ct;
char **v;
@@ -2471,10 +2474,7 @@ int qemuio_command(BlockBackend *blk, const char *cmd)
if (c) {
ct = find_command(v[0]);
if (ct) {
- ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context();
- aio_context_acquire(ctx);
ret = command(blk, ct, c, v);
- aio_context_release(ctx);
} else {
fprintf(stderr, "command \"%s\" not found\n", v[0]);
ret = -EINVAL;
diff --git a/qemu-io.c b/qemu-io.c
index bf902302e9..57f07501df 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -411,6 +411,19 @@ static void prep_fetchline(void *opaque)
*fetchable= 1;
}
+static int do_qemuio_command(const char *cmd)
+{
+ int ret;
+ AioContext *ctx =
+ qemuio_blk ? blk_get_aio_context(qemuio_blk) : qemu_get_aio_context();
+
+ aio_context_acquire(ctx);
+ ret = qemuio_command(qemuio_blk, cmd);
+ aio_context_release(ctx);
+
+ return ret;
+}
+
static int command_loop(void)
{
int i, fetchable = 0, prompted = 0;
@@ -418,7 +431,7 @@ static int command_loop(void)
char *input;
for (i = 0; !quit_qemu_io && i < ncmdline; i++) {
- ret = qemuio_command(qemuio_blk, cmdline[i]);
+ ret = do_qemuio_command(cmdline[i]);
if (ret < 0) {
last_error = ret;
}
@@ -446,7 +459,7 @@ static int command_loop(void)
if (input == NULL) {
break;
}
- ret = qemuio_command(qemuio_blk, input);
+ ret = do_qemuio_command(input);
g_free(input);
if (ret < 0) {
diff --git a/qemu-options.hx b/qemu-options.hx
index 7c825f81fc..e22fb94d99 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2370,7 +2370,9 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
" specify SMBIOS type 11 fields\n"
"-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n"
" [,asset=str][,part=str][,speed=%d]\n"
- " specify SMBIOS type 17 fields\n",
+ " specify SMBIOS type 17 fields\n"
+ "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n"
+ " specify SMBIOS type 41 fields\n",
QEMU_ARCH_I386 | QEMU_ARCH_ARM)
SRST
``-smbios file=binary``
@@ -2432,6 +2434,32 @@ SRST
``-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str][,asset=str][,part=str][,speed=%d]``
Specify SMBIOS type 17 fields
+
+``-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]``
+ Specify SMBIOS type 41 fields
+
+ This argument can be repeated multiple times. Its main use is to allow network interfaces be created
+ as ``enoX`` on Linux, with X being the instance number, instead of the name depending on the interface
+ position on the PCI bus.
+
+ Here is an example of use:
+
+ .. parsed-literal::
+
+ -netdev user,id=internet \\
+ -device virtio-net-pci,mac=50:54:00:00:00:42,netdev=internet,id=internet-dev \\
+ -smbios type=41,designation='Onboard LAN',instance=1,kind=ethernet,pcidev=internet-dev
+
+ In the guest OS, the device should then appear as ``eno1``:
+
+ ..parsed-literal::
+
+ $ ip -brief l
+ lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
+ eno1 UP 50:54:00:00:00:42 <BROADCAST,MULTICAST,UP,LOWER_UP>
+
+ Currently, the PCI device has to be attached to the root bus.
+
ERST
DEFHEADING()
@@ -4288,7 +4316,7 @@ SRST
ERST
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
- QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
+ QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
SRST
``-semihosting``
@@ -4303,7 +4331,7 @@ ERST
DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config,
"-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \
" semihosting configuration\n",
-QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 |
+QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
SRST
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 8f7053ec9b..3d185cceac 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1532,6 +1532,7 @@ sub process {
($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
(defined($1) || defined($2)))) &&
!(($realfile ne '') &&
+ defined($acpi_testexpected) &&
($realfile eq $acpi_testexpected))) {
$reported_maintainer_file = 1;
WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md
new file mode 100644
index 0000000000..02a3447dab
--- /dev/null
+++ b/scripts/coverity-scan/COMPONENTS.md
@@ -0,0 +1,154 @@
+This is the list of currently configured Coverity components:
+
+alpha
+ ~ (/qemu)?((/include)?/hw/alpha/.*|/target/alpha/.*)
+
+arm
+ ~ (/qemu)?((/include)?/hw/arm/.*|(/include)?/hw/.*/(arm|allwinner-a10|bcm28|digic|exynos|imx|omap|stellaris|pxa2xx|versatile|zynq|cadence).*|/hw/net/xgmac.c|/hw/ssi/xilinx_spips.c|/target/arm/.*)
+
+avr
+ ~ (/qemu)?((/include)?/hw/avr/.*|/target/avr/.*)
+
+cris
+ ~ (/qemu)?((/include)?/hw/cris/.*|/target/cris/.*)
+
+hexagon
+ ~ (/qemu)?(/target/hexagon/.*)
+
+hppa
+ ~ (/qemu)?((/include)?/hw/hppa/.*|/target/hppa/.*)
+
+i386
+ ~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c)
+
+lm32
+ ~ (/qemu)?((/include)?/hw/lm32/.*|/target/lm32/.*|/hw/.*/(milkymist|lm32).*)
+
+m68k
+ ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*)
+
+microblaze
+ ~ (/qemu)?((/include)?/hw/microblaze/.*|/target/microblaze/.*)
+
+mips
+ ~ (/qemu)?((/include)?/hw/mips/.*|/target/mips/.*)
+
+nios2
+ ~ (/qemu)?((/include)?/hw/nios2/.*|/target/nios2/.*)
+
+ppc
+ ~ (/qemu)?((/include)?/hw/ppc/.*|/target/ppc/.*|/hw/pci-host/(uninorth.*|dec.*|prep.*|ppc.*)|/hw/misc/macio/.*|(/include)?/hw/.*/(xics|openpic|spapr).*)
+
+riscv
+ ~ (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*)
+
+rx
+ ~ (/qemu)?((/include)?/hw/rx/.*|/target/rx/.*)
+
+s390
+ ~ (/qemu)?((/include)?/hw/s390x/.*|/target/s390x/.*|/hw/.*/s390_.*)
+
+sh4
+ ~ (/qemu)?((/include)?/hw/sh4/.*|/target/sh4/.*)
+
+sparc
+ ~ (/qemu)?((/include)?/hw/sparc(64)?.*|/target/sparc/.*|/hw/.*/grlib.*|/hw/display/cg3.c)
+
+tilegx
+ ~ (/qemu)?(/target/tilegx/.*)
+
+tricore
+ ~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*)
+
+unicore32
+ ~ (/qemu)?((/include)?/hw/unicore32/.*|/target/unicore32/.*)
+
+9pfs
+ ~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*)
+
+audio
+ ~ (/qemu)?((/include)?/(audio|hw/audio)/.*)
+
+block
+ ~ (/qemu)?(/block.*|(/include?)(/hw)?/(block|storage-daemon)/.*|(/include)?/hw/ide/.*|/qemu-(img|io).*|/util/(aio|async|thread-pool).*)
+
+char
+ ~ (/qemu)?(/qemu-char\.c|/include/sysemu/char\.h|(/include)?/hw/char/.*)
+
+capstone
+ ~ (/qemu)?(/capstone/.*)
+
+crypto
+ ~ (/qemu)?((/include)?/crypto/.*|/hw/.*/crypto.*)
+
+disas
+ ~ (/qemu)?((/include)?/disas.*)
+
+fpu
+ ~ (/qemu)?((/include)?(/fpu|/libdecnumber)/.*)
+
+io
+ ~ (/qemu)?((/include)?/io/.*)
+
+ipmi
+ ~ (/qemu)?((/include)?/hw/ipmi/.*)
+
+libvixl
+ ~ (/qemu)?(/disas/libvixl/.*)
+
+migration
+ ~ (/qemu)?((/include)?/migration/.*)
+
+monitor
+ ~ (/qemu)?(/qapi.*|/qobject/.*|/monitor\..*|/[hq]mp\..*)
+
+nbd
+ ~ (/qemu)?(/nbd/.*|/include/block/nbd.*|/qemu-nbd\.c)
+
+net
+ ~ (/qemu)?((/include)?(/hw)?/(net|rdma)/.*)
+
+pci
+ ~ (/qemu)?(/hw/pci.*|/include/hw/pci.*)
+
+qemu-ga
+ ~ (/qemu)?(/qga/.*)
+
+scsi
+ ~ (/qemu)?(/scsi/.*|/hw/scsi/.*|/include/hw/scsi/.*)
+
+slirp
+ ~ (/qemu)?(/.*slirp.*)
+
+tcg
+ ~ (/qemu)?(/accel/tcg/.*|/replay/.*|/(.*/)?softmmu.*)
+
+trace
+ ~ (/qemu)?(/.*trace.*\.[ch])
+
+ui
+ ~ (/qemu)?((/include)?(/ui|/hw/display|/hw/input)/.*)
+
+usb
+ ~ (/qemu)?(/hw/usb/.*|/include/hw/usb/.*)
+
+user
+ ~ (/qemu)?(/linux-user/.*|/bsd-user/.*|/user-exec\.c|/thunk\.c|/include/exec/user/.*)
+
+util
+ ~ (/qemu)?(/util/.*|/include/qemu/.*)
+
+xen
+ ~ (/qemu)?(.*/xen.*)
+
+virtiofsd
+ ~ (/qemu)?(/tools/virtiofsd/.*)
+
+(headers)
+ ~ (/qemu)?(/include/.*)
+
+testlibs
+ ~ (/qemu)?(/tests/qtest(/libqos/.*|/libqtest.*))
+
+tests
+ ~ (/qemu)?(/tests/.*)
diff --git a/scripts/coverity-model.c b/scripts/coverity-scan/model.c
index 2c0346ff25..2c0346ff25 100644
--- a/scripts/coverity-model.c
+++ b/scripts/coverity-scan/model.c
diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c
index f09bab830c..6ff9f30bad 100644
--- a/softmmu/arch_init.c
+++ b/softmmu/arch_init.c
@@ -56,16 +56,12 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_HPPA
#elif defined(TARGET_I386)
#define QEMU_ARCH QEMU_ARCH_I386
-#elif defined(TARGET_LM32)
-#define QEMU_ARCH QEMU_ARCH_LM32
#elif defined(TARGET_M68K)
#define QEMU_ARCH QEMU_ARCH_M68K
#elif defined(TARGET_MICROBLAZE)
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
#elif defined(TARGET_MIPS)
#define QEMU_ARCH QEMU_ARCH_MIPS
-#elif defined(TARGET_MOXIE)
-#define QEMU_ARCH QEMU_ARCH_MOXIE
#elif defined(TARGET_NIOS2)
#define QEMU_ARCH QEMU_ARCH_NIOS2
#elif defined(TARGET_OPENRISC)
@@ -84,8 +80,6 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_SPARC
#elif defined(TARGET_TRICORE)
#define QEMU_ARCH QEMU_ARCH_TRICORE
-#elif defined(TARGET_UNICORE32)
-#define QEMU_ARCH QEMU_ARCH_UNICORE32
#elif defined(TARGET_XTENSA)
#define QEMU_ARCH QEMU_ARCH_XTENSA
#elif defined(TARGET_AVR)
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 5232696571..e1da81ed2f 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -1694,6 +1694,11 @@ ram_addr_t qemu_ram_get_used_length(RAMBlock *rb)
return rb->used_length;
}
+ram_addr_t qemu_ram_get_max_length(RAMBlock *rb)
+{
+ return rb->max_length;
+}
+
bool qemu_ram_is_shared(RAMBlock *rb)
{
return rb->flags & RAM_SHARED;
@@ -1793,8 +1798,9 @@ static int memory_try_enable_merging(void *addr, size_t len)
return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
}
-/* Only legal before guest might have detected the memory size: e.g. on
- * incoming migration, or right after reset.
+/*
+ * Resizing RAM while migrating can result in the migration being canceled.
+ * Care has to be taken if the guest might have already detected the memory.
*
* As memory core doesn't know how is memory accessed, it is up to
* resize callback to update device state and/or add assertions to detect
@@ -1802,6 +1808,7 @@ static int memory_try_enable_merging(void *addr, size_t len)
*/
int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
{
+ const ram_addr_t oldsize = block->used_length;
const ram_addr_t unaligned_size = newsize;
assert(block);
@@ -1838,6 +1845,11 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
return -EINVAL;
}
+ /* Notify before modifying the ram block and touching the bitmaps. */
+ if (block->host) {
+ ram_block_notify_resize(block->host, oldsize, newsize);
+ }
+
cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
block->used_length = newsize;
cpu_physical_memory_set_dirty_range(block->offset, block->used_length,
@@ -2005,7 +2017,8 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared)
qemu_madvise(new_block->host, new_block->max_length,
QEMU_MADV_DONTFORK);
}
- ram_block_notify_add(new_block->host, new_block->max_length);
+ ram_block_notify_add(new_block->host, new_block->used_length,
+ new_block->max_length);
}
}
@@ -2184,7 +2197,8 @@ void qemu_ram_free(RAMBlock *block)
}
if (block->host) {
- ram_block_notify_remove(block->host, block->max_length);
+ ram_block_notify_remove(block->host, block->used_length,
+ block->max_length);
}
qemu_mutex_lock_ramlist();
@@ -3486,7 +3500,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
goto err;
}
- if ((start + length) <= rb->used_length) {
+ if ((start + length) <= rb->max_length) {
bool need_madvise, need_fallocate;
if (!QEMU_IS_ALIGNED(length, rb->page_size)) {
error_report("ram_block_discard_range: Unaligned length: %zx",
@@ -3553,7 +3567,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
} else {
error_report("ram_block_discard_range: Overrun block '%s' (%" PRIu64
"/%zx/" RAM_ADDR_FMT")",
- rb->idstr, start, length, rb->used_length);
+ rb->idstr, start, length, rb->max_length);
}
err:
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 307944aef3..93e78469bc 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -3595,7 +3595,6 @@ void qemu_init(int argc, char **argv, char **envp)
current_machine->cpu_type = parse_cpu_option(cpu_option);
}
/* NB: for machine none cpu_type could STILL be NULL here! */
- accel_init_interfaces(ACCEL_GET_CLASS(current_machine->accelerator));
qemu_resolve_machine_memdev();
parse_numa_opts(current_machine);
diff --git a/target/avr/helper.c b/target/avr/helper.c
index 35e1019594..981c29da45 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -188,11 +188,7 @@ void helper_break(CPUAVRState *env)
void helper_wdr(CPUAVRState *env)
{
- CPUState *cs = env_cpu(env);
-
- /* WD is not implemented yet, placeholder */
- cs->exception_index = EXCP_DEBUG;
- cpu_loop_exit(cs);
+ qemu_log_mask(LOG_UNIMP, "WDG reset (not implemented)\n");
}
/*
diff --git a/target/i386/cpu-internal.h b/target/i386/cpu-internal.h
new file mode 100644
index 0000000000..9baac5c0b4
--- /dev/null
+++ b/target/i386/cpu-internal.h
@@ -0,0 +1,70 @@
+/*
+ * i386 CPU internal definitions to be shared between cpu.c and cpu-sysemu.c
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef I386_CPU_INTERNAL_H
+#define I386_CPU_INTERNAL_H
+
+typedef enum FeatureWordType {
+ CPUID_FEATURE_WORD,
+ MSR_FEATURE_WORD,
+} FeatureWordType;
+
+typedef struct FeatureWordInfo {
+ FeatureWordType type;
+ /* feature flags names are taken from "Intel Processor Identification and
+ * the CPUID Instruction" and AMD's "CPUID Specification".
+ * In cases of disagreement between feature naming conventions,
+ * aliases may be added.
+ */
+ const char *feat_names[64];
+ union {
+ /* If type==CPUID_FEATURE_WORD */
+ struct {
+ uint32_t eax; /* Input EAX for CPUID */
+ bool needs_ecx; /* CPUID instruction uses ECX as input */
+ uint32_t ecx; /* Input ECX value for CPUID */
+ int reg; /* output register (R_* constant) */
+ } cpuid;
+ /* If type==MSR_FEATURE_WORD */
+ struct {
+ uint32_t index;
+ } msr;
+ };
+ uint64_t tcg_features; /* Feature flags supported by TCG */
+ uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */
+ uint64_t migratable_flags; /* Feature flags known to be migratable */
+ /* Features that shouldn't be auto-enabled by "-cpu host" */
+ uint64_t no_autoenable_flags;
+} FeatureWordInfo;
+
+extern FeatureWordInfo feature_word_info[];
+
+void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
+
+#ifndef CONFIG_USER_ONLY
+GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs);
+void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
+ const char *name, void *opaque, Error **errp);
+
+void x86_cpu_apic_create(X86CPU *cpu, Error **errp);
+void x86_cpu_apic_realize(X86CPU *cpu, Error **errp);
+void x86_cpu_machine_reset_cb(void *opaque);
+#endif /* !CONFIG_USER_ONLY */
+
+#endif /* I386_CPU_INTERNAL_H */
diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c
new file mode 100644
index 0000000000..6477584313
--- /dev/null
+++ b/target/i386/cpu-sysemu.c
@@ -0,0 +1,352 @@
+/*
+ * i386 CPUID, CPU class, definitions, models: sysemu-only code
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "sysemu/xen.h"
+#include "sysemu/whpx.h"
+#include "kvm/kvm_i386.h"
+#include "qapi/error.h"
+#include "qapi/qapi-visit-run-state.h"
+#include "qapi/qmp/qdict.h"
+#include "qom/qom-qobject.h"
+#include "qapi/qapi-commands-machine-target.h"
+#include "hw/qdev-properties.h"
+
+#include "exec/address-spaces.h"
+#include "hw/i386/apic_internal.h"
+
+#include "cpu-internal.h"
+
+/* Return a QDict containing keys for all properties that can be included
+ * in static expansion of CPU models. All properties set by x86_cpu_load_model()
+ * must be included in the dictionary.
+ */
+static QDict *x86_cpu_static_props(void)
+{
+ FeatureWord w;
+ int i;
+ static const char *props[] = {
+ "min-level",
+ "min-xlevel",
+ "family",
+ "model",
+ "stepping",
+ "model-id",
+ "vendor",
+ "lmce",
+ NULL,
+ };
+ static QDict *d;
+
+ if (d) {
+ return d;
+ }
+
+ d = qdict_new();
+ for (i = 0; props[i]; i++) {
+ qdict_put_null(d, props[i]);
+ }
+
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ FeatureWordInfo *fi = &feature_word_info[w];
+ int bit;
+ for (bit = 0; bit < 64; bit++) {
+ if (!fi->feat_names[bit]) {
+ continue;
+ }
+ qdict_put_null(d, fi->feat_names[bit]);
+ }
+ }
+
+ return d;
+}
+
+/* Add an entry to @props dict, with the value for property. */
+static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop)
+{
+ QObject *value = object_property_get_qobject(OBJECT(cpu), prop,
+ &error_abort);
+
+ qdict_put_obj(props, prop, value);
+}
+
+/* Convert CPU model data from X86CPU object to a property dictionary
+ * that can recreate exactly the same CPU model.
+ */
+static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
+{
+ QDict *sprops = x86_cpu_static_props();
+ const QDictEntry *e;
+
+ for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) {
+ const char *prop = qdict_entry_key(e);
+ x86_cpu_expand_prop(cpu, props, prop);
+ }
+}
+
+/* Convert CPU model data from X86CPU object to a property dictionary
+ * that can recreate exactly the same CPU model, including every
+ * writeable QOM property.
+ */
+static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
+{
+ ObjectPropertyIterator iter;
+ ObjectProperty *prop;
+
+ object_property_iter_init(&iter, OBJECT(cpu));
+ while ((prop = object_property_iter_next(&iter))) {
+ /* skip read-only or write-only properties */
+ if (!prop->get || !prop->set) {
+ continue;
+ }
+
+ /* "hotplugged" is the only property that is configurable
+ * on the command-line but will be set differently on CPUs
+ * created using "-cpu ... -smp ..." and by CPUs created
+ * on the fly by x86_cpu_from_model() for querying. Skip it.
+ */
+ if (!strcmp(prop->name, "hotplugged")) {
+ continue;
+ }
+ x86_cpu_expand_prop(cpu, props, prop->name);
+ }
+}
+
+static void object_apply_props(Object *obj, QDict *props, Error **errp)
+{
+ const QDictEntry *prop;
+
+ for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) {
+ if (!object_property_set_qobject(obj, qdict_entry_key(prop),
+ qdict_entry_value(prop), errp)) {
+ break;
+ }
+ }
+}
+
+/* Create X86CPU object according to model+props specification */
+static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp)
+{
+ X86CPU *xc = NULL;
+ X86CPUClass *xcc;
+ Error *err = NULL;
+
+ xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model));
+ if (xcc == NULL) {
+ error_setg(&err, "CPU model '%s' not found", model);
+ goto out;
+ }
+
+ xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc)));
+ if (props) {
+ object_apply_props(OBJECT(xc), props, &err);
+ if (err) {
+ goto out;
+ }
+ }
+
+ x86_cpu_expand_features(xc, &err);
+ if (err) {
+ goto out;
+ }
+
+out:
+ if (err) {
+ error_propagate(errp, err);
+ object_unref(OBJECT(xc));
+ xc = NULL;
+ }
+ return xc;
+}
+
+CpuModelExpansionInfo *
+qmp_query_cpu_model_expansion(CpuModelExpansionType type,
+ CpuModelInfo *model,
+ Error **errp)
+{
+ X86CPU *xc = NULL;
+ Error *err = NULL;
+ CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1);
+ QDict *props = NULL;
+ const char *base_name;
+
+ xc = x86_cpu_from_model(model->name,
+ model->has_props ?
+ qobject_to(QDict, model->props) :
+ NULL, &err);
+ if (err) {
+ goto out;
+ }
+
+ props = qdict_new();
+ ret->model = g_new0(CpuModelInfo, 1);
+ ret->model->props = QOBJECT(props);
+ ret->model->has_props = true;
+
+ switch (type) {
+ case CPU_MODEL_EXPANSION_TYPE_STATIC:
+ /* Static expansion will be based on "base" only */
+ base_name = "base";
+ x86_cpu_to_dict(xc, props);
+ break;
+ case CPU_MODEL_EXPANSION_TYPE_FULL:
+ /* As we don't return every single property, full expansion needs
+ * to keep the original model name+props, and add extra
+ * properties on top of that.
+ */
+ base_name = model->name;
+ x86_cpu_to_dict_full(xc, props);
+ break;
+ default:
+ error_setg(&err, "Unsupported expansion type");
+ goto out;
+ }
+
+ x86_cpu_to_dict(xc, props);
+
+ ret->model->name = g_strdup(base_name);
+
+out:
+ object_unref(OBJECT(xc));
+ if (err) {
+ error_propagate(errp, err);
+ qapi_free_CpuModelExpansionInfo(ret);
+ ret = NULL;
+ }
+ return ret;
+}
+
+void cpu_clear_apic_feature(CPUX86State *env)
+{
+ env->features[FEAT_1_EDX] &= ~CPUID_APIC;
+}
+
+bool cpu_is_bsp(X86CPU *cpu)
+{
+ return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
+}
+
+/* TODO: remove me, when reset over QOM tree is implemented */
+void x86_cpu_machine_reset_cb(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ cpu_reset(CPU(cpu));
+}
+
+APICCommonClass *apic_get_class(void)
+{
+ const char *apic_type = "apic";
+
+ /* TODO: in-kernel irqchip for hvf */
+ if (kvm_apic_in_kernel()) {
+ apic_type = "kvm-apic";
+ } else if (xen_enabled()) {
+ apic_type = "xen-apic";
+ } else if (whpx_apic_in_platform()) {
+ apic_type = "whpx-apic";
+ }
+
+ return APIC_COMMON_CLASS(object_class_by_name(apic_type));
+}
+
+void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
+{
+ APICCommonState *apic;
+ ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
+
+ cpu->apic_state = DEVICE(object_new_with_class(apic_class));
+
+ object_property_add_child(OBJECT(cpu), "lapic",
+ OBJECT(cpu->apic_state));
+ object_unref(OBJECT(cpu->apic_state));
+
+ qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
+ /* TODO: convert to link<> */
+ apic = APIC_COMMON(cpu->apic_state);
+ apic->cpu = cpu;
+ apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
+}
+
+void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
+{
+ APICCommonState *apic;
+ static bool apic_mmio_map_once;
+
+ if (cpu->apic_state == NULL) {
+ return;
+ }
+ qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
+
+ /* Map APIC MMIO area */
+ apic = APIC_COMMON(cpu->apic_state);
+ if (!apic_mmio_map_once) {
+ memory_region_add_subregion_overlap(get_system_memory(),
+ apic->apicbase &
+ MSR_IA32_APICBASE_BASE,
+ &apic->io_memory,
+ 0x1000);
+ apic_mmio_map_once = true;
+ }
+}
+
+GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ GuestPanicInformation *panic_info = NULL;
+
+ if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) {
+ panic_info = g_malloc0(sizeof(GuestPanicInformation));
+
+ panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
+
+ assert(HV_CRASH_PARAMS >= 5);
+ panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0];
+ panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1];
+ panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2];
+ panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3];
+ panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4];
+ }
+
+ return panic_info;
+}
+void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CPUState *cs = CPU(obj);
+ GuestPanicInformation *panic_info;
+
+ if (!cs->crash_occurred) {
+ error_setg(errp, "No crash occured");
+ return;
+ }
+
+ panic_info = x86_cpu_get_crash_info(cs);
+ if (panic_info == NULL) {
+ error_setg(errp, "No crash information");
+ return;
+ }
+
+ visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
+ errp);
+ qapi_free_GuestPanicInformation(panic_info);
+}
+
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ad99cad0e7..c496bfa1c2 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1,5 +1,5 @@
/*
- * i386 CPUID helper functions
+ * i386 CPUID, CPU class, definitions, models
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -20,49 +20,26 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
-#include "qemu/bitops.h"
#include "qemu/qemu-print.h"
-
#include "cpu.h"
-#include "tcg/tcg-cpu.h"
#include "tcg/helper-tcg.h"
-#include "exec/exec-all.h"
-#include "sysemu/kvm.h"
#include "sysemu/reset.h"
#include "sysemu/hvf.h"
-#include "sysemu/cpus.h"
-#include "sysemu/xen.h"
-#include "sysemu/whpx.h"
#include "kvm/kvm_i386.h"
#include "sev_i386.h"
-
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qapi/error.h"
#include "qapi/qapi-visit-machine.h"
-#include "qapi/qapi-visit-run-state.h"
-#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h"
-#include "qapi/visitor.h"
-#include "qom/qom-qobject.h"
-#include "sysemu/arch_init.h"
#include "qapi/qapi-commands-machine-target.h"
-
#include "standard-headers/asm-x86/kvm_para.h"
-
-#include "sysemu/sysemu.h"
-#include "sysemu/tcg.h"
#include "hw/qdev-properties.h"
#include "hw/i386/topology.h"
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
-#include "hw/i386/apic_internal.h"
#include "hw/boards.h"
#endif
#include "disas/capstone.h"
+#include "cpu-internal.h"
/* Helpers for building CPUID[2] descriptors: */
@@ -595,8 +572,8 @@ static CPUCacheInfo legacy_l3_cache = {
#define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */
#define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */
-static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
- uint32_t vendor2, uint32_t vendor3)
+void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
+ uint32_t vendor2, uint32_t vendor3)
{
int i;
for (i = 0; i < 4; i++) {
@@ -677,40 +654,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */
#define TCG_14_0_ECX_FEATURES 0
-typedef enum FeatureWordType {
- CPUID_FEATURE_WORD,
- MSR_FEATURE_WORD,
-} FeatureWordType;
-
-typedef struct FeatureWordInfo {
- FeatureWordType type;
- /* feature flags names are taken from "Intel Processor Identification and
- * the CPUID Instruction" and AMD's "CPUID Specification".
- * In cases of disagreement between feature naming conventions,
- * aliases may be added.
- */
- const char *feat_names[64];
- union {
- /* If type==CPUID_FEATURE_WORD */
- struct {
- uint32_t eax; /* Input EAX for CPUID */
- bool needs_ecx; /* CPUID instruction uses ECX as input */
- uint32_t ecx; /* Input ECX value for CPUID */
- int reg; /* output register (R_* constant) */
- } cpuid;
- /* If type==MSR_FEATURE_WORD */
- struct {
- uint32_t index;
- } msr;
- };
- uint64_t tcg_features; /* Feature flags supported by TCG */
- uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */
- uint64_t migratable_flags; /* Feature flags known to be migratable */
- /* Features that shouldn't be auto-enabled by "-cpu host" */
- uint64_t no_autoenable_flags;
-} FeatureWordInfo;
-
-static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
+FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_1_EDX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
@@ -1589,25 +1533,6 @@ void host_cpuid(uint32_t function, uint32_t count,
*edx = vec[3];
}
-void host_vendor_fms(char *vendor, int *family, int *model, int *stepping)
-{
- uint32_t eax, ebx, ecx, edx;
-
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
-
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
- if (family) {
- *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
- }
- if (model) {
- *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
- }
- if (stepping) {
- *stepping = eax & 0x0F;
- }
-}
-
/* CPU class name definitions: */
/* Return type name for a given CPU model name
@@ -1632,10 +1557,6 @@ static char *x86_cpu_class_get_model_name(X86CPUClass *cc)
strlen(class_name) - strlen(X86_CPU_TYPE_SUFFIX));
}
-typedef struct PropValue {
- const char *prop, *value;
-} PropValue;
-
typedef struct X86CPUVersionDefinition {
X86CPUVersion version;
const char *alias;
@@ -4249,32 +4170,6 @@ static X86CPUDefinition builtin_x86_defs[] = {
},
};
-/* KVM-specific features that are automatically added/removed
- * from all CPU models when KVM is enabled.
- */
-static PropValue kvm_default_props[] = {
- { "kvmclock", "on" },
- { "kvm-nopiodelay", "on" },
- { "kvm-asyncpf", "on" },
- { "kvm-steal-time", "on" },
- { "kvm-pv-eoi", "on" },
- { "kvmclock-stable-bit", "on" },
- { "x2apic", "on" },
- { "kvm-msi-ext-dest-id", "off" },
- { "acpi", "off" },
- { "monitor", "off" },
- { "svm", "off" },
- { NULL, NULL },
-};
-
-/* TCG-specific defaults that override all CPU models when using TCG
- */
-static PropValue tcg_default_props[] = {
- { "vme", "off" },
- { NULL, NULL },
-};
-
-
/*
* We resolve CPU model aliases using -v1 when using "-machine
* none", but this is just for compatibility while libvirt isn't
@@ -4316,61 +4211,6 @@ static X86CPUVersion x86_cpu_model_resolve_version(const X86CPUModel *model)
return v;
}
-void x86_cpu_change_kvm_default(const char *prop, const char *value)
-{
- PropValue *pv;
- for (pv = kvm_default_props; pv->prop; pv++) {
- if (!strcmp(pv->prop, prop)) {
- pv->value = value;
- break;
- }
- }
-
- /* It is valid to call this function only for properties that
- * are already present in the kvm_default_props table.
- */
- assert(pv->prop);
-}
-
-static bool lmce_supported(void)
-{
- uint64_t mce_cap = 0;
-
-#ifdef CONFIG_KVM
- if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) {
- return false;
- }
-#endif
-
- return !!(mce_cap & MCG_LMCE_P);
-}
-
-#define CPUID_MODEL_ID_SZ 48
-
-/**
- * cpu_x86_fill_model_id:
- * Get CPUID model ID string from host CPU.
- *
- * @str should have at least CPUID_MODEL_ID_SZ bytes
- *
- * The function does NOT add a null terminator to the string
- * automatically.
- */
-static int cpu_x86_fill_model_id(char *str)
-{
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
- int i;
-
- for (i = 0; i < 3; i++) {
- host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
- memcpy(str + i * 16 + 0, &eax, 4);
- memcpy(str + i * 16 + 4, &ebx, 4);
- memcpy(str + i * 16 + 8, &ecx, 4);
- memcpy(str + i * 16 + 12, &edx, 4);
- }
- return 0;
-}
-
static Property max_x86_cpu_properties[] = {
DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true),
DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false),
@@ -4393,62 +4233,25 @@ static void max_x86_cpu_class_init(ObjectClass *oc, void *data)
static void max_x86_cpu_initfn(Object *obj)
{
X86CPU *cpu = X86_CPU(obj);
- CPUX86State *env = &cpu->env;
- KVMState *s = kvm_state;
/* We can't fill the features array here because we don't know yet if
* "migratable" is true or false.
*/
cpu->max_features = true;
-
- if (accel_uses_host_cpuid()) {
- char vendor[CPUID_VENDOR_SZ + 1] = { 0 };
- char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 };
- int family, model, stepping;
-
- host_vendor_fms(vendor, &family, &model, &stepping);
- cpu_x86_fill_model_id(model_id);
-
- object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
- object_property_set_int(OBJECT(cpu), "family", family, &error_abort);
- object_property_set_int(OBJECT(cpu), "model", model, &error_abort);
- object_property_set_int(OBJECT(cpu), "stepping", stepping,
- &error_abort);
- object_property_set_str(OBJECT(cpu), "model-id", model_id,
- &error_abort);
-
- if (kvm_enabled()) {
- env->cpuid_min_level =
- kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
- env->cpuid_min_xlevel =
- kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
- env->cpuid_min_xlevel2 =
- kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
- } else {
- env->cpuid_min_level =
- hvf_get_supported_cpuid(0x0, 0, R_EAX);
- env->cpuid_min_xlevel =
- hvf_get_supported_cpuid(0x80000000, 0, R_EAX);
- env->cpuid_min_xlevel2 =
- hvf_get_supported_cpuid(0xC0000000, 0, R_EAX);
- }
-
- if (lmce_supported()) {
- object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort);
- }
- object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort);
- } else {
- object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
- &error_abort);
- object_property_set_int(OBJECT(cpu), "family", 6, &error_abort);
- object_property_set_int(OBJECT(cpu), "model", 6, &error_abort);
- object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort);
- object_property_set_str(OBJECT(cpu), "model-id",
- "QEMU TCG CPU version " QEMU_HW_VERSION,
- &error_abort);
- }
-
object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort);
+
+ /*
+ * these defaults are used for TCG and all other accelerators
+ * besides KVM and HVF, which overwrite these values
+ */
+ object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD,
+ &error_abort);
+ object_property_set_int(OBJECT(cpu), "family", 6, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", 6, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort);
+ object_property_set_str(OBJECT(cpu), "model-id",
+ "QEMU TCG CPU version " QEMU_HW_VERSION,
+ &error_abort);
}
static const TypeInfo max_x86_cpu_type_info = {
@@ -4458,31 +4261,6 @@ static const TypeInfo max_x86_cpu_type_info = {
.class_init = max_x86_cpu_class_init,
};
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
-static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
-{
- X86CPUClass *xcc = X86_CPU_CLASS(oc);
-
- xcc->host_cpuid_required = true;
- xcc->ordering = 8;
-
-#if defined(CONFIG_KVM)
- xcc->model_description =
- "KVM processor with all supported host features ";
-#elif defined(CONFIG_HVF)
- xcc->model_description =
- "HVF processor with all supported host features ";
-#endif
-}
-
-static const TypeInfo host_x86_cpu_type_info = {
- .name = X86_CPU_TYPE_NAME("host"),
- .parent = X86_CPU_TYPE_NAME("max"),
- .class_init = host_x86_cpu_class_init,
-};
-
-#endif
-
static char *feature_word_description(FeatureWordInfo *f, uint32_t bit)
{
assert(f->type == CPUID_FEATURE_WORD || f->type == MSR_FEATURE_WORD);
@@ -4930,7 +4708,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
}
}
-static void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
static void x86_cpu_filter_features(X86CPU *cpu, bool verbose);
/* Build a list with the name of all features on a feature word array */
@@ -5201,7 +4978,7 @@ static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
return r;
}
-static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
+void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
{
PropValue *pv;
for (pv = props; pv->prop; pv++) {
@@ -5248,8 +5025,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
{
X86CPUDefinition *def = model->cpudef;
CPUX86State *env = &cpu->env;
- const char *vendor;
- char host_vendor[CPUID_VENDOR_SZ + 1];
FeatureWord w;
/*NOTE: any property set by this function should be returned by
@@ -5276,20 +5051,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
/* legacy-cache defaults to 'off' if CPU model provides cache info */
cpu->legacy_cache = !def->cache_info;
- /* Special cases not set in the X86CPUDefinition structs: */
- /* TODO: in-kernel irqchip for hvf */
- if (kvm_enabled()) {
- if (!kvm_irqchip_in_kernel()) {
- x86_cpu_change_kvm_default("x2apic", "off");
- } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) {
- x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on");
- }
-
- x86_cpu_apply_props(cpu, kvm_default_props);
- } else if (tcg_enabled()) {
- x86_cpu_apply_props(cpu, tcg_default_props);
- }
-
env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
/* sysenter isn't supported in compatibility mode on AMD,
@@ -5299,15 +5060,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
* KVM's sysenter/syscall emulation in compatibility mode and
* when doing cross vendor migration
*/
- vendor = def->vendor;
- if (accel_uses_host_cpuid()) {
- uint32_t ebx = 0, ecx = 0, edx = 0;
- host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx);
- vendor = host_vendor;
- }
- object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
+ /*
+ * vendor property is set here but then overloaded with the
+ * host cpu vendor for KVM and HVF.
+ */
+ object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort);
x86_cpu_apply_version_props(cpu, model);
@@ -5319,207 +5077,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
memset(&env->user_features, 0, sizeof(env->user_features));
}
-#ifndef CONFIG_USER_ONLY
-/* Return a QDict containing keys for all properties that can be included
- * in static expansion of CPU models. All properties set by x86_cpu_load_model()
- * must be included in the dictionary.
- */
-static QDict *x86_cpu_static_props(void)
-{
- FeatureWord w;
- int i;
- static const char *props[] = {
- "min-level",
- "min-xlevel",
- "family",
- "model",
- "stepping",
- "model-id",
- "vendor",
- "lmce",
- NULL,
- };
- static QDict *d;
-
- if (d) {
- return d;
- }
-
- d = qdict_new();
- for (i = 0; props[i]; i++) {
- qdict_put_null(d, props[i]);
- }
-
- for (w = 0; w < FEATURE_WORDS; w++) {
- FeatureWordInfo *fi = &feature_word_info[w];
- int bit;
- for (bit = 0; bit < 64; bit++) {
- if (!fi->feat_names[bit]) {
- continue;
- }
- qdict_put_null(d, fi->feat_names[bit]);
- }
- }
-
- return d;
-}
-
-/* Add an entry to @props dict, with the value for property. */
-static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop)
-{
- QObject *value = object_property_get_qobject(OBJECT(cpu), prop,
- &error_abort);
-
- qdict_put_obj(props, prop, value);
-}
-
-/* Convert CPU model data from X86CPU object to a property dictionary
- * that can recreate exactly the same CPU model.
- */
-static void x86_cpu_to_dict(X86CPU *cpu, QDict *props)
-{
- QDict *sprops = x86_cpu_static_props();
- const QDictEntry *e;
-
- for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) {
- const char *prop = qdict_entry_key(e);
- x86_cpu_expand_prop(cpu, props, prop);
- }
-}
-
-/* Convert CPU model data from X86CPU object to a property dictionary
- * that can recreate exactly the same CPU model, including every
- * writeable QOM property.
- */
-static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props)
-{
- ObjectPropertyIterator iter;
- ObjectProperty *prop;
-
- object_property_iter_init(&iter, OBJECT(cpu));
- while ((prop = object_property_iter_next(&iter))) {
- /* skip read-only or write-only properties */
- if (!prop->get || !prop->set) {
- continue;
- }
-
- /* "hotplugged" is the only property that is configurable
- * on the command-line but will be set differently on CPUs
- * created using "-cpu ... -smp ..." and by CPUs created
- * on the fly by x86_cpu_from_model() for querying. Skip it.
- */
- if (!strcmp(prop->name, "hotplugged")) {
- continue;
- }
- x86_cpu_expand_prop(cpu, props, prop->name);
- }
-}
-
-static void object_apply_props(Object *obj, QDict *props, Error **errp)
-{
- const QDictEntry *prop;
-
- for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) {
- if (!object_property_set_qobject(obj, qdict_entry_key(prop),
- qdict_entry_value(prop), errp)) {
- break;
- }
- }
-}
-
-/* Create X86CPU object according to model+props specification */
-static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp)
-{
- X86CPU *xc = NULL;
- X86CPUClass *xcc;
- Error *err = NULL;
-
- xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model));
- if (xcc == NULL) {
- error_setg(&err, "CPU model '%s' not found", model);
- goto out;
- }
-
- xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc)));
- if (props) {
- object_apply_props(OBJECT(xc), props, &err);
- if (err) {
- goto out;
- }
- }
-
- x86_cpu_expand_features(xc, &err);
- if (err) {
- goto out;
- }
-
-out:
- if (err) {
- error_propagate(errp, err);
- object_unref(OBJECT(xc));
- xc = NULL;
- }
- return xc;
-}
-
-CpuModelExpansionInfo *
-qmp_query_cpu_model_expansion(CpuModelExpansionType type,
- CpuModelInfo *model,
- Error **errp)
-{
- X86CPU *xc = NULL;
- Error *err = NULL;
- CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1);
- QDict *props = NULL;
- const char *base_name;
-
- xc = x86_cpu_from_model(model->name,
- model->has_props ?
- qobject_to(QDict, model->props) :
- NULL, &err);
- if (err) {
- goto out;
- }
-
- props = qdict_new();
- ret->model = g_new0(CpuModelInfo, 1);
- ret->model->props = QOBJECT(props);
- ret->model->has_props = true;
-
- switch (type) {
- case CPU_MODEL_EXPANSION_TYPE_STATIC:
- /* Static expansion will be based on "base" only */
- base_name = "base";
- x86_cpu_to_dict(xc, props);
- break;
- case CPU_MODEL_EXPANSION_TYPE_FULL:
- /* As we don't return every single property, full expansion needs
- * to keep the original model name+props, and add extra
- * properties on top of that.
- */
- base_name = model->name;
- x86_cpu_to_dict_full(xc, props);
- break;
- default:
- error_setg(&err, "Unsupported expansion type");
- goto out;
- }
-
- x86_cpu_to_dict(xc, props);
-
- ret->model->name = g_strdup(base_name);
-
-out:
- object_unref(OBJECT(xc));
- if (err) {
- error_propagate(errp, err);
- qapi_free_CpuModelExpansionInfo(ret);
- ret = NULL;
- }
- return ret;
-}
-#endif /* !CONFIG_USER_ONLY */
-
static gchar *x86_gdb_arch_name(CPUState *cs)
{
#ifdef TARGET_X86_64
@@ -5594,15 +5151,6 @@ static void x86_register_cpudef_types(X86CPUDefinition *def)
}
-#if !defined(CONFIG_USER_ONLY)
-
-void cpu_clear_apic_feature(CPUX86State *env)
-{
- env->features[FEAT_1_EDX] &= ~CPUID_APIC;
-}
-
-#endif /* !CONFIG_USER_ONLY */
-
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
@@ -6251,20 +5799,6 @@ static void x86_cpu_reset(DeviceState *dev)
#endif
}
-#ifndef CONFIG_USER_ONLY
-bool cpu_is_bsp(X86CPU *cpu)
-{
- return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
-}
-
-/* TODO: remove me, when reset over QOM tree is implemented */
-static void x86_cpu_machine_reset_cb(void *opaque)
-{
- X86CPU *cpu = opaque;
- cpu_reset(CPU(cpu));
-}
-#endif
-
static void mce_init(X86CPU *cpu)
{
CPUX86State *cenv = &cpu->env;
@@ -6282,109 +5816,6 @@ static void mce_init(X86CPU *cpu)
}
}
-#ifndef CONFIG_USER_ONLY
-APICCommonClass *apic_get_class(void)
-{
- const char *apic_type = "apic";
-
- /* TODO: in-kernel irqchip for hvf */
- if (kvm_apic_in_kernel()) {
- apic_type = "kvm-apic";
- } else if (xen_enabled()) {
- apic_type = "xen-apic";
- } else if (whpx_apic_in_platform()) {
- apic_type = "whpx-apic";
- }
-
- return APIC_COMMON_CLASS(object_class_by_name(apic_type));
-}
-
-static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
-{
- APICCommonState *apic;
- ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
-
- cpu->apic_state = DEVICE(object_new_with_class(apic_class));
-
- object_property_add_child(OBJECT(cpu), "lapic",
- OBJECT(cpu->apic_state));
- object_unref(OBJECT(cpu->apic_state));
-
- qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
- /* TODO: convert to link<> */
- apic = APIC_COMMON(cpu->apic_state);
- apic->cpu = cpu;
- apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
-}
-
-static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
-{
- APICCommonState *apic;
- static bool apic_mmio_map_once;
-
- if (cpu->apic_state == NULL) {
- return;
- }
- qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
-
- /* Map APIC MMIO area */
- apic = APIC_COMMON(cpu->apic_state);
- if (!apic_mmio_map_once) {
- memory_region_add_subregion_overlap(get_system_memory(),
- apic->apicbase &
- MSR_IA32_APICBASE_BASE,
- &apic->io_memory,
- 0x1000);
- apic_mmio_map_once = true;
- }
-}
-
-static void x86_cpu_machine_done(Notifier *n, void *unused)
-{
- X86CPU *cpu = container_of(n, X86CPU, machine_done);
- MemoryRegion *smram =
- (MemoryRegion *) object_resolve_path("/machine/smram", NULL);
-
- if (smram) {
- cpu->smram = g_new(MemoryRegion, 1);
- memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram",
- smram, 0, 4 * GiB);
- memory_region_set_enabled(cpu->smram, true);
- memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1);
- }
-}
-#else
-static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
-{
-}
-#endif
-
-/* Note: Only safe for use on x86(-64) hosts */
-static uint32_t x86_host_phys_bits(void)
-{
- uint32_t eax;
- uint32_t host_phys_bits;
-
- host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL);
- if (eax >= 0x80000008) {
- host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL);
- /* Note: According to AMD doc 25481 rev 2.34 they have a field
- * at 23:16 that can specify a maximum physical address bits for
- * the guest that can override this value; but I've not seen
- * anything with that set.
- */
- host_phys_bits = eax & 0xff;
- } else {
- /* It's an odd 64 bit machine that doesn't have the leaf for
- * physical address bits; fall back to 36 that's most older
- * Intel.
- */
- host_phys_bits = 36;
- }
-
- return host_phys_bits;
-}
-
static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value)
{
if (*min < value) {
@@ -6488,7 +5919,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu)
/* Expand CPU configuration data, based on configured features
* and host/accelerator capabilities when appropriate.
*/
-static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
+void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
{
CPUX86State *env = &cpu->env;
FeatureWord w;
@@ -6702,27 +6133,19 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
Error *local_err = NULL;
static bool ht_warned;
- if (xcc->host_cpuid_required) {
- if (!accel_uses_host_cpuid()) {
- g_autofree char *name = x86_cpu_class_get_model_name(xcc);
- error_setg(&local_err, "CPU model '%s' requires KVM", name);
- goto out;
- }
+ /* Process Hyper-V enlightenments */
+ x86_cpu_hyperv_realize(cpu);
+
+ cpu_exec_realizefn(cs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
}
- if (cpu->max_features && accel_uses_host_cpuid()) {
- if (enable_cpu_pm) {
- host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx,
- &cpu->mwait.ecx, &cpu->mwait.edx);
- env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR;
- if (kvm_enabled() && kvm_has_waitpkg()) {
- env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG;
- }
- }
- if (kvm_enabled() && cpu->ucode_rev == 0) {
- cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state,
- MSR_IA32_UCODE_REV);
- }
+ if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) {
+ g_autofree char *name = x86_cpu_class_get_model_name(xcc);
+ error_setg(&local_err, "CPU model '%s' requires KVM or HVF", name);
+ goto out;
}
if (cpu->ucode_rev == 0) {
@@ -6774,30 +6197,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
* consumer AMD devices but nothing else.
*/
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
- if (accel_uses_host_cpuid()) {
- uint32_t host_phys_bits = x86_host_phys_bits();
- static bool warned;
-
- /* Print a warning if the user set it to a value that's not the
- * host value.
- */
- if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 &&
- !warned) {
- warn_report("Host physical bits (%u)"
- " does not match phys-bits property (%u)",
- host_phys_bits, cpu->phys_bits);
- warned = true;
- }
-
- 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;
- }
- }
- }
if (cpu->phys_bits &&
(cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
cpu->phys_bits < 32)) {
@@ -6806,9 +6205,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits);
return;
}
- /* 0 means it was not explicitly set by the user (or by machine
- * compat_props or by the host code above). In this case, the default
- * is the value used by TCG (40).
+ /*
+ * 0 means it was not explicitly set by the user (or by machine
+ * compat_props or by the host code in host-cpu.c).
+ * In this case, the default is the value used by TCG (40).
*/
if (cpu->phys_bits == 0) {
cpu->phys_bits = TCG_PHYS_ADDR_BITS;
@@ -6857,15 +6257,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
env->cache_info_amd.l3_cache = &legacy_l3_cache;
}
- /* Process Hyper-V enlightenments */
- x86_cpu_hyperv_realize(cpu);
-
- cpu_exec_realizefn(cs, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
#ifndef CONFIG_USER_ONLY
MachineState *ms = MACHINE(qdev_get_machine());
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
@@ -6880,33 +6271,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
mce_init(cpu);
-#ifndef CONFIG_USER_ONLY
- if (tcg_enabled()) {
- cpu->cpu_as_mem = g_new(MemoryRegion, 1);
- cpu->cpu_as_root = g_new(MemoryRegion, 1);
-
- /* Outer container... */
- memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull);
- memory_region_set_enabled(cpu->cpu_as_root, true);
-
- /* ... with two regions inside: normal system memory with low
- * priority, and...
- */
- memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory",
- get_system_memory(), 0, ~0ull);
- memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0);
- memory_region_set_enabled(cpu->cpu_as_mem, true);
-
- cs->num_ases = 2;
- cpu_address_space_init(cs, 0, "cpu-memory", cs->memory);
- cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root);
-
- /* ... SMRAM with higher priority, linked from /machine/smram. */
- cpu->machine_done.notify = x86_cpu_machine_done;
- qemu_add_machine_init_done_notifier(&cpu->machine_done);
- }
-#endif
-
qemu_init_vcpu(cs);
/*
@@ -6929,10 +6293,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
ht_warned = true;
}
+#ifndef CONFIG_USER_ONLY
x86_cpu_apic_realize(cpu, &local_err);
if (local_err != NULL) {
goto out;
}
+#endif /* !CONFIG_USER_ONLY */
cpu_reset(cs);
xcc->parent_realize(dev, &local_err);
@@ -7056,52 +6422,6 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc,
x86_cpu_register_bit_prop(xcc, name, w, bitnr);
}
-#if !defined(CONFIG_USER_ONLY)
-static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- GuestPanicInformation *panic_info = NULL;
-
- if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) {
- panic_info = g_malloc0(sizeof(GuestPanicInformation));
-
- panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V;
-
- assert(HV_CRASH_PARAMS >= 5);
- panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0];
- panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1];
- panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2];
- panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3];
- panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4];
- }
-
- return panic_info;
-}
-static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- CPUState *cs = CPU(obj);
- GuestPanicInformation *panic_info;
-
- if (!cs->crash_occurred) {
- error_setg(errp, "No crash occurred");
- return;
- }
-
- panic_info = x86_cpu_get_crash_info(cs);
- if (panic_info == NULL) {
- error_setg(errp, "No crash information");
- return;
- }
-
- visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
- errp);
- qapi_free_GuestPanicInformation(panic_info);
-}
-#endif /* !CONFIG_USER_ONLY */
-
static void x86_cpu_initfn(Object *obj)
{
X86CPU *cpu = X86_CPU(obj);
@@ -7153,6 +6473,9 @@ static void x86_cpu_initfn(Object *obj)
if (xcc->model) {
x86_cpu_load_model(cpu, xcc->model);
}
+
+ /* if required, do accelerator-specific cpu initializations */
+ accel_cpu_instance_init(CPU(obj));
}
static int64_t x86_cpu_get_arch_id(CPUState *cs)
@@ -7410,11 +6733,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
cc->class_by_name = x86_cpu_class_by_name;
cc->parse_features = x86_cpu_parse_featurestr;
cc->has_work = x86_cpu_has_work;
-
-#ifdef CONFIG_TCG
- tcg_cpu_common_class_init(cc);
-#endif /* CONFIG_TCG */
-
cc->dump_state = x86_cpu_dump_state;
cc->set_pc = x86_cpu_set_pc;
cc->gdb_read_register = x86_cpu_gdb_read_register;
@@ -7525,9 +6843,6 @@ static void x86_cpu_register_types(void)
}
type_register_static(&max_x86_cpu_type_info);
type_register_static(&x86_base_cpu_type_info);
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
- type_register_static(&host_x86_cpu_type_info);
-#endif
}
type_init(x86_cpu_register_types)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 1bc300ce85..e6836393f7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -303,6 +303,19 @@ typedef enum X86Seg {
#define PG_ERROR_I_D_MASK 0x10
#define PG_ERROR_PK_MASK 0x20
+#define PG_MODE_PAE (1 << 0)
+#define PG_MODE_LMA (1 << 1)
+#define PG_MODE_NXE (1 << 2)
+#define PG_MODE_PSE (1 << 3)
+#define PG_MODE_LA57 (1 << 4)
+#define PG_MODE_SVM_MASK MAKE_64BIT_MASK(0, 15)
+
+/* Bits of CR4 that do not affect the NPT page format. */
+#define PG_MODE_WP (1 << 16)
+#define PG_MODE_PKE (1 << 17)
+#define PG_MODE_PKS (1 << 18)
+#define PG_MODE_SMEP (1 << 19)
+
#define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */
#define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */
#define MCG_LMCE_P (1ULL<<27) /* Local Machine Check Supported */
@@ -1817,7 +1830,10 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env);
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void x86_register_ferr_irq(qemu_irq irq);
+void fpu_check_raise_ferr_irq(CPUX86State *s);
void cpu_set_ignne(void);
+void cpu_clear_ignne(void);
+
/* mpx_helper.c */
void cpu_sync_bndcs_hflags(CPUX86State *env);
@@ -1926,13 +1942,20 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo,
void *puc);
/* cpu.c */
+void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
+ uint32_t vendor2, uint32_t vendor3);
+typedef struct PropValue {
+ const char *prop, *value;
+} PropValue;
+void x86_cpu_apply_props(X86CPU *cpu, PropValue *props);
+
+/* cpu.c other functions (cpuid) */
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
void cpu_clear_apic_feature(CPUX86State *env);
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
-void host_vendor_fms(char *vendor, int *family, int *model, int *stepping);
/* helper.c */
void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
@@ -1948,6 +1971,11 @@ static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs)
return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs));
}
+/*
+ * load efer and update the corresponding hflags. XXX: do consistency
+ * checks with cpuid bits?
+ */
+void cpu_load_efer(CPUX86State *env, uint64_t val);
uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr);
uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr);
uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr);
@@ -2044,21 +2072,6 @@ static inline uint32_t cpu_compute_eflags(CPUX86State *env)
return eflags;
}
-
-/* load efer and update the corresponding hflags. XXX: do consistency
- checks with cpuid bits? */
-static inline void cpu_load_efer(CPUX86State *env, uint64_t val)
-{
- env->efer = val;
- env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
- if (env->efer & MSR_EFER_LMA) {
- env->hflags |= HF_LMA_MASK;
- }
- if (env->efer & MSR_EFER_SVME) {
- env->hflags |= HF_SVME_MASK;
- }
-}
-
static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env)
{
return ((MemTxAttrs) { .secure = (env->hflags & HF_SMM_MASK) != 0 });
@@ -2105,6 +2118,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env)
((env->cr[4] & CR4_VMXE_MASK) || (env->hflags & HF_SMM_MASK));
}
+/* excp_helper.c */
+int get_pg_mode(CPUX86State *env);
+
/* fpu_helper.c */
void update_fp_status(CPUX86State *env);
void update_mxcsr_status(CPUX86State *env);
@@ -2130,24 +2146,21 @@ static inline void cpu_set_fpuc(CPUX86State *env, uint16_t fpuc)
void helper_lock_init(void);
/* svm_helper.c */
+#ifdef CONFIG_USER_ONLY
+static inline void
+cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
+ uint64_t param, uintptr_t retaddr)
+{ /* no-op */ }
+#else
void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
uint64_t param, uintptr_t retaddr);
+#endif
+
/* apic.c */
void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
TPRAccess access);
-
-/* Change the value of a KVM-specific default
- *
- * If value is NULL, no default will be set and the original
- * value from the CPU model table will be kept.
- *
- * It is valid to call this function only for properties that
- * are already present in the kvm_default_props table.
- */
-void x86_cpu_change_kvm_default(const char *prop, const char *value);
-
/* Special values for X86CPUVersion: */
/* Resolve to latest CPU version */
diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c
index 41e265fc67..098a2ad15a 100644
--- a/target/i386/gdbstub.c
+++ b/target/i386/gdbstub.c
@@ -78,6 +78,23 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
#define GDB_FORCE_64 0
#endif
+static int gdb_read_reg_cs64(uint32_t hflags, GByteArray *buf, target_ulong val)
+{
+ if ((hflags & HF_CS64_MASK) || GDB_FORCE_64) {
+ return gdb_get_reg64(buf, val);
+ }
+ return gdb_get_reg32(buf, val);
+}
+
+static int gdb_write_reg_cs64(uint32_t hflags, uint8_t *buf, target_ulong *val)
+{
+ if (hflags & HF_CS64_MASK) {
+ *val = ldq_p(buf);
+ return 8;
+ }
+ *val = ldl_p(buf);
+ return 4;
+}
int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
@@ -142,25 +159,14 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
case IDX_SEG_REGS + 5:
return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
-
case IDX_SEG_REGS + 6:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->segs[R_FS].base);
- }
- return gdb_get_reg32(mem_buf, env->segs[R_FS].base);
-
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_FS].base);
case IDX_SEG_REGS + 7:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->segs[R_GS].base);
- }
- return gdb_get_reg32(mem_buf, env->segs[R_GS].base);
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_GS].base);
case IDX_SEG_REGS + 8:
#ifdef TARGET_X86_64
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->kernelgsbase);
- }
- return gdb_get_reg32(mem_buf, env->kernelgsbase);
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->kernelgsbase);
#else
return gdb_get_reg32(mem_buf, 0);
#endif
@@ -188,45 +194,23 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
return gdb_get_reg32(mem_buf, env->mxcsr);
case IDX_CTL_CR0_REG:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->cr[0]);
- }
- return gdb_get_reg32(mem_buf, env->cr[0]);
-
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[0]);
case IDX_CTL_CR2_REG:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->cr[2]);
- }
- return gdb_get_reg32(mem_buf, env->cr[2]);
-
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[2]);
case IDX_CTL_CR3_REG:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->cr[3]);
- }
- return gdb_get_reg32(mem_buf, env->cr[3]);
-
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[3]);
case IDX_CTL_CR4_REG:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->cr[4]);
- }
- return gdb_get_reg32(mem_buf, env->cr[4]);
-
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[4]);
case IDX_CTL_CR8_REG:
-#ifdef CONFIG_SOFTMMU
+#ifndef CONFIG_USER_ONLY
tpr = cpu_get_apic_tpr(cpu->apic_state);
#else
tpr = 0;
#endif
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, tpr);
- }
- return gdb_get_reg32(mem_buf, tpr);
+ return gdb_read_reg_cs64(env->hflags, mem_buf, tpr);
case IDX_CTL_EFER_REG:
- if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) {
- return gdb_get_reg64(mem_buf, env->efer);
- }
- return gdb_get_reg32(mem_buf, env->efer);
+ return gdb_read_reg_cs64(env->hflags, mem_buf, env->efer);
}
}
return 0;
@@ -266,7 +250,8 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
- uint32_t tmp;
+ target_ulong tmp;
+ int len;
/* N.B. GDB can't deal with changes in registers or sizes in the middle
of a session. So if we're in 32-bit mode on a 64-bit cpu, still act
@@ -329,30 +314,13 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
case IDX_SEG_REGS + 5:
return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf);
-
case IDX_SEG_REGS + 6:
- if (env->hflags & HF_CS64_MASK) {
- env->segs[R_FS].base = ldq_p(mem_buf);
- return 8;
- }
- env->segs[R_FS].base = ldl_p(mem_buf);
- return 4;
-
+ return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_FS].base);
case IDX_SEG_REGS + 7:
- if (env->hflags & HF_CS64_MASK) {
- env->segs[R_GS].base = ldq_p(mem_buf);
- return 8;
- }
- env->segs[R_GS].base = ldl_p(mem_buf);
- return 4;
-
+ return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_GS].base);
case IDX_SEG_REGS + 8:
#ifdef TARGET_X86_64
- if (env->hflags & HF_CS64_MASK) {
- env->kernelgsbase = ldq_p(mem_buf);
- return 8;
- }
- env->kernelgsbase = ldl_p(mem_buf);
+ return gdb_write_reg_cs64(env->hflags, mem_buf, &env->kernelgsbase);
#endif
return 4;
@@ -382,57 +350,46 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 4;
case IDX_CTL_CR0_REG:
- if (env->hflags & HF_CS64_MASK) {
- cpu_x86_update_cr0(env, ldq_p(mem_buf));
- return 8;
- }
- cpu_x86_update_cr0(env, ldl_p(mem_buf));
- return 4;
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ cpu_x86_update_cr0(env, tmp);
+#endif
+ return len;
case IDX_CTL_CR2_REG:
- if (env->hflags & HF_CS64_MASK) {
- env->cr[2] = ldq_p(mem_buf);
- return 8;
- }
- env->cr[2] = ldl_p(mem_buf);
- return 4;
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ env->cr[2] = tmp;
+#endif
+ return len;
case IDX_CTL_CR3_REG:
- if (env->hflags & HF_CS64_MASK) {
- cpu_x86_update_cr3(env, ldq_p(mem_buf));
- return 8;
- }
- cpu_x86_update_cr3(env, ldl_p(mem_buf));
- return 4;
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ cpu_x86_update_cr3(env, tmp);
+#endif
+ return len;
case IDX_CTL_CR4_REG:
- if (env->hflags & HF_CS64_MASK) {
- cpu_x86_update_cr4(env, ldq_p(mem_buf));
- return 8;
- }
- cpu_x86_update_cr4(env, ldl_p(mem_buf));
- return 4;
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ cpu_x86_update_cr4(env, tmp);
+#endif
+ return len;
case IDX_CTL_CR8_REG:
- if (env->hflags & HF_CS64_MASK) {
-#ifdef CONFIG_SOFTMMU
- cpu_set_apic_tpr(cpu->apic_state, ldq_p(mem_buf));
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ cpu_set_apic_tpr(cpu->apic_state, tmp);
#endif
- return 8;
- }
-#ifdef CONFIG_SOFTMMU
- cpu_set_apic_tpr(cpu->apic_state, ldl_p(mem_buf));
-#endif
- return 4;
+ return len;
case IDX_CTL_EFER_REG:
- if (env->hflags & HF_CS64_MASK) {
- cpu_load_efer(env, ldq_p(mem_buf));
- return 8;
- }
- cpu_load_efer(env, ldl_p(mem_buf));
- return 4;
-
+ len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp);
+#ifndef CONFIG_USER_ONLY
+ cpu_load_efer(env, tmp);
+#endif
+ return len;
}
}
/* Unrecognised register. */
diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c
index 35495f5e82..8d44edbffd 100644
--- a/target/i386/hax/hax-mem.c
+++ b/target/i386/hax/hax-mem.c
@@ -293,7 +293,8 @@ static MemoryListener hax_memory_listener = {
.priority = 10,
};
-static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
+static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size,
+ size_t max_size)
{
/*
* We must register each RAM block with the HAXM kernel module, or
@@ -304,7 +305,7 @@ static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
* host physical pages for the RAM block as part of this registration
* process, hence the name hax_populate_ram().
*/
- if (hax_populate_ram((uint64_t)(uintptr_t)host, size) < 0) {
+ if (hax_populate_ram((uint64_t)(uintptr_t)host, max_size) < 0) {
fprintf(stderr, "HAX failed to populate RAM\n");
abort();
}
diff --git a/target/i386/helper.c b/target/i386/helper.c
index 8c180b5b2b..533b29cb91 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -574,6 +574,19 @@ void do_cpu_sipi(X86CPU *cpu)
#endif
#ifndef CONFIG_USER_ONLY
+
+void cpu_load_efer(CPUX86State *env, uint64_t val)
+{
+ env->efer = val;
+ env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
+ if (env->efer & MSR_EFER_LMA) {
+ env->hflags |= HF_LMA_MASK;
+ }
+ if (env->efer & MSR_EFER_SVME) {
+ env->hflags |= HF_SVME_MASK;
+ }
+}
+
uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr)
{
X86CPU *cpu = X86_CPU(cs);
diff --git a/target/i386/helper.h b/target/i386/helper.h
index c2ae2f7e61..f3d8c3f949 100644
--- a/target/i386/helper.h
+++ b/target/i386/helper.h
@@ -42,13 +42,13 @@ DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
DEF_HELPER_2(iret_real, void, env, int)
DEF_HELPER_3(iret_protected, void, env, int, int)
DEF_HELPER_3(lret_protected, void, env, int, int)
-DEF_HELPER_2(read_crN, tl, env, int)
-DEF_HELPER_3(write_crN, void, env, int, tl)
-DEF_HELPER_2(lmsw, void, env, tl)
DEF_HELPER_1(clts, void, env)
+
+#ifndef CONFIG_USER_ONLY
DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl)
+#endif /* !CONFIG_USER_ONLY */
+
DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
-DEF_HELPER_2(invlpg, void, env, tl)
DEF_HELPER_1(sysenter, void, env)
DEF_HELPER_2(sysexit, void, env, int)
@@ -56,21 +56,22 @@ DEF_HELPER_2(sysexit, void, env, int)
DEF_HELPER_2(syscall, void, env, int)
DEF_HELPER_2(sysret, void, env, int)
#endif
-DEF_HELPER_2(hlt, void, env, int)
-DEF_HELPER_2(monitor, void, env, tl)
-DEF_HELPER_2(mwait, void, env, int)
-DEF_HELPER_2(pause, void, env, int)
-DEF_HELPER_1(debug, void, env)
+DEF_HELPER_FLAGS_2(pause, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_1(debug, TCG_CALL_NO_WG, noreturn, env)
DEF_HELPER_1(reset_rf, void, env)
-DEF_HELPER_3(raise_interrupt, void, env, int, int)
-DEF_HELPER_2(raise_exception, void, env, int)
+DEF_HELPER_FLAGS_3(raise_interrupt, TCG_CALL_NO_WG, noreturn, env, int, int)
+DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, int)
DEF_HELPER_1(cli, void, env)
DEF_HELPER_1(sti, void, env)
DEF_HELPER_1(clac, void, env)
DEF_HELPER_1(stac, void, env)
DEF_HELPER_3(boundw, void, env, tl, int)
DEF_HELPER_3(boundl, void, env, tl, int)
+
+#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(rsm, void, env)
+#endif /* !CONFIG_USER_ONLY */
+
DEF_HELPER_2(into, void, env, int)
DEF_HELPER_2(cmpxchg8b_unlocked, void, env, tl)
DEF_HELPER_2(cmpxchg8b, void, env, tl)
@@ -78,27 +79,23 @@ DEF_HELPER_2(cmpxchg8b, void, env, tl)
DEF_HELPER_2(cmpxchg16b_unlocked, void, env, tl)
DEF_HELPER_2(cmpxchg16b, void, env, tl)
#endif
-DEF_HELPER_1(single_step, void, env)
+DEF_HELPER_FLAGS_1(single_step, TCG_CALL_NO_WG, noreturn, env)
DEF_HELPER_1(rechecking_single_step, void, env)
DEF_HELPER_1(cpuid, void, env)
DEF_HELPER_1(rdtsc, void, env)
DEF_HELPER_1(rdtscp, void, env)
-DEF_HELPER_1(rdpmc, void, env)
-DEF_HELPER_1(rdmsr, void, env)
-DEF_HELPER_1(wrmsr, void, env)
+DEF_HELPER_FLAGS_1(rdpmc, TCG_CALL_NO_WG, noreturn, env)
-DEF_HELPER_2(check_iob, void, env, i32)
-DEF_HELPER_2(check_iow, void, env, i32)
-DEF_HELPER_2(check_iol, void, env, i32)
+#ifndef CONFIG_USER_ONLY
DEF_HELPER_3(outb, void, env, i32, i32)
DEF_HELPER_2(inb, tl, env, i32)
DEF_HELPER_3(outw, void, env, i32, i32)
DEF_HELPER_2(inw, tl, env, i32)
DEF_HELPER_3(outl, void, env, i32, i32)
DEF_HELPER_2(inl, tl, env, i32)
+DEF_HELPER_FLAGS_3(check_io, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
-
-DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
+DEF_HELPER_2(svm_check_intercept, void, env, i32)
DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
DEF_HELPER_3(vmrun, void, env, int, int)
DEF_HELPER_1(vmmcall, void, env)
@@ -106,8 +103,15 @@ DEF_HELPER_2(vmload, void, env, int)
DEF_HELPER_2(vmsave, void, env, int)
DEF_HELPER_1(stgi, void, env)
DEF_HELPER_1(clgi, void, env)
-DEF_HELPER_1(skinit, void, env)
-DEF_HELPER_2(invlpga, void, env, int)
+DEF_HELPER_FLAGS_2(flush_page, TCG_CALL_NO_RWG, void, env, tl)
+DEF_HELPER_FLAGS_2(hlt, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_FLAGS_2(monitor, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(mwait, TCG_CALL_NO_WG, noreturn, env, int)
+DEF_HELPER_1(rdmsr, void, env)
+DEF_HELPER_1(wrmsr, void, env)
+DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
+DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl)
+#endif /* !CONFIG_USER_ONLY */
/* x86 FPU */
diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c
new file mode 100644
index 0000000000..4ea9e354ea
--- /dev/null
+++ b/target/i386/host-cpu.c
@@ -0,0 +1,204 @@
+/*
+ * x86 host CPU functions, and "host" cpu type initialization
+ *
+ * Copyright 2021 SUSE 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.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "host-cpu.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+
+/* Note: Only safe for use on x86(-64) hosts */
+static uint32_t host_cpu_phys_bits(void)
+{
+ uint32_t eax;
+ uint32_t host_phys_bits;
+
+ host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL);
+ if (eax >= 0x80000008) {
+ host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL);
+ /*
+ * Note: According to AMD doc 25481 rev 2.34 they have a field
+ * at 23:16 that can specify a maximum physical address bits for
+ * the guest that can override this value; but I've not seen
+ * anything with that set.
+ */
+ host_phys_bits = eax & 0xff;
+ } else {
+ /*
+ * It's an odd 64 bit machine that doesn't have the leaf for
+ * physical address bits; fall back to 36 that's most older
+ * Intel.
+ */
+ host_phys_bits = 36;
+ }
+
+ return host_phys_bits;
+}
+
+static void host_cpu_enable_cpu_pm(X86CPU *cpu)
+{
+ CPUX86State *env = &cpu->env;
+
+ host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx,
+ &cpu->mwait.ecx, &cpu->mwait.edx);
+ env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR;
+}
+
+static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu)
+{
+ uint32_t host_phys_bits = host_cpu_phys_bits();
+ uint32_t phys_bits = cpu->phys_bits;
+ static bool warned;
+
+ /*
+ * Print a warning if the user set it to a value that's not the
+ * host value.
+ */
+ if (phys_bits != host_phys_bits && phys_bits != 0 &&
+ !warned) {
+ warn_report("Host physical bits (%u)"
+ " does not match phys-bits property (%u)",
+ host_phys_bits, phys_bits);
+ warned = true;
+ }
+
+ if (cpu->host_phys_bits) {
+ /* The user asked for us to use the host physical bits */
+ phys_bits = host_phys_bits;
+ if (cpu->host_phys_bits_limit &&
+ phys_bits > cpu->host_phys_bits_limit) {
+ phys_bits = cpu->host_phys_bits_limit;
+ }
+ }
+
+ return phys_bits;
+}
+
+bool host_cpu_realizefn(CPUState *cs, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ if (cpu->max_features && enable_cpu_pm) {
+ host_cpu_enable_cpu_pm(cpu);
+ }
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
+ uint32_t phys_bits = host_cpu_adjust_phys_bits(cpu);
+
+ if (phys_bits &&
+ (phys_bits > TARGET_PHYS_ADDR_SPACE_BITS ||
+ phys_bits < 32)) {
+ error_setg(errp, "phys-bits should be between 32 and %u "
+ " (but is %u)",
+ TARGET_PHYS_ADDR_SPACE_BITS, phys_bits);
+ return false;
+ }
+ cpu->phys_bits = phys_bits;
+ }
+ return true;
+}
+
+#define CPUID_MODEL_ID_SZ 48
+/**
+ * cpu_x86_fill_model_id:
+ * Get CPUID model ID string from host CPU.
+ *
+ * @str should have at least CPUID_MODEL_ID_SZ bytes
+ *
+ * The function does NOT add a null terminator to the string
+ * automatically.
+ */
+static int host_cpu_fill_model_id(char *str)
+{
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
+ memcpy(str + i * 16 + 0, &eax, 4);
+ memcpy(str + i * 16 + 4, &ebx, 4);
+ memcpy(str + i * 16 + 8, &ecx, 4);
+ memcpy(str + i * 16 + 12, &edx, 4);
+ }
+ return 0;
+}
+
+void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
+
+ host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+ if (family) {
+ *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+ }
+ if (model) {
+ *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+ }
+ if (stepping) {
+ *stepping = eax & 0x0F;
+ }
+}
+
+void host_cpu_instance_init(X86CPU *cpu)
+{
+ uint32_t ebx = 0, ecx = 0, edx = 0;
+ char vendor[CPUID_VENDOR_SZ + 1];
+
+ host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(vendor, ebx, edx, ecx);
+
+ object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
+}
+
+void host_cpu_max_instance_init(X86CPU *cpu)
+{
+ char vendor[CPUID_VENDOR_SZ + 1] = { 0 };
+ char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 };
+ int family, model, stepping;
+
+ /* Use max host physical address bits if -cpu max option is applied */
+ object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort);
+
+ host_cpu_vendor_fms(vendor, &family, &model, &stepping);
+ host_cpu_fill_model_id(model_id);
+
+ object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort);
+ object_property_set_int(OBJECT(cpu), "family", family, &error_abort);
+ object_property_set_int(OBJECT(cpu), "model", model, &error_abort);
+ object_property_set_int(OBJECT(cpu), "stepping", stepping,
+ &error_abort);
+ object_property_set_str(OBJECT(cpu), "model-id", model_id,
+ &error_abort);
+}
+
+static void host_cpu_class_init(ObjectClass *oc, void *data)
+{
+ X86CPUClass *xcc = X86_CPU_CLASS(oc);
+
+ xcc->host_cpuid_required = true;
+ xcc->ordering = 8;
+ xcc->model_description =
+ g_strdup_printf("processor with all supported host features ");
+}
+
+static const TypeInfo host_cpu_type_info = {
+ .name = X86_CPU_TYPE_NAME("host"),
+ .parent = X86_CPU_TYPE_NAME("max"),
+ .class_init = host_cpu_class_init,
+};
+
+static void host_cpu_type_init(void)
+{
+ type_register_static(&host_cpu_type_info);
+}
+
+type_init(host_cpu_type_init);
diff --git a/target/i386/host-cpu.h b/target/i386/host-cpu.h
new file mode 100644
index 0000000000..6a9bc918ba
--- /dev/null
+++ b/target/i386/host-cpu.h
@@ -0,0 +1,19 @@
+/*
+ * x86 host CPU type initialization and host CPU functions
+ *
+ * Copyright 2021 SUSE 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 HOST_CPU_H
+#define HOST_CPU_H
+
+void host_cpu_instance_init(X86CPU *cpu);
+void host_cpu_max_instance_init(X86CPU *cpu);
+bool host_cpu_realizefn(CPUState *cs, Error **errp);
+
+void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping);
+
+#endif /* HOST_CPU_H */
diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c
new file mode 100644
index 0000000000..8fbc423888
--- /dev/null
+++ b/target/i386/hvf/hvf-cpu.c
@@ -0,0 +1,68 @@
+/*
+ * x86 HVF CPU type initialization
+ *
+ * Copyright 2021 SUSE 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.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "host-cpu.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "sysemu/hvf.h"
+#include "hw/core/accel-cpu.h"
+
+static void hvf_cpu_max_instance_init(X86CPU *cpu)
+{
+ CPUX86State *env = &cpu->env;
+
+ host_cpu_max_instance_init(cpu);
+
+ env->cpuid_min_level =
+ hvf_get_supported_cpuid(0x0, 0, R_EAX);
+ env->cpuid_min_xlevel =
+ hvf_get_supported_cpuid(0x80000000, 0, R_EAX);
+ env->cpuid_min_xlevel2 =
+ hvf_get_supported_cpuid(0xC0000000, 0, R_EAX);
+}
+
+static void hvf_cpu_instance_init(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ host_cpu_instance_init(cpu);
+
+ /* Special cases not set in the X86CPUDefinition structs: */
+ /* TODO: in-kernel irqchip for hvf */
+
+ if (cpu->max_features) {
+ hvf_cpu_max_instance_init(cpu);
+ }
+}
+
+static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+ acc->cpu_realizefn = host_cpu_realizefn;
+ acc->cpu_instance_init = hvf_cpu_instance_init;
+}
+
+static const TypeInfo hvf_cpu_accel_type_info = {
+ .name = ACCEL_CPU_NAME("hvf"),
+
+ .parent = TYPE_ACCEL_CPU,
+ .class_init = hvf_cpu_accel_class_init,
+ .abstract = true,
+};
+
+static void hvf_cpu_accel_register_types(void)
+{
+ type_register_static(&hvf_cpu_accel_type_info);
+}
+
+type_init(hvf_cpu_accel_register_types);
diff --git a/target/i386/hvf/meson.build b/target/i386/hvf/meson.build
index e9eb5a5da8..d253d5fd10 100644
--- a/target/i386/hvf/meson.build
+++ b/target/i386/hvf/meson.build
@@ -10,4 +10,5 @@ i386_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
'x86_mmu.c',
'x86_task.c',
'x86hvf.c',
+ 'hvf-cpu.c',
))
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
new file mode 100644
index 0000000000..c660ad4293
--- /dev/null
+++ b/target/i386/kvm/kvm-cpu.c
@@ -0,0 +1,151 @@
+/*
+ * x86 KVM CPU type initialization
+ *
+ * Copyright 2021 SUSE 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.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "host-cpu.h"
+#include "kvm-cpu.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+
+#include "kvm_i386.h"
+#include "hw/core/accel-cpu.h"
+
+static bool kvm_cpu_realizefn(CPUState *cs, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ /*
+ * The realize order is important, since x86_cpu_realize() checks if
+ * nothing else has been set by the user (or by accelerators) in
+ * cpu->ucode_rev and cpu->phys_bits.
+ *
+ * realize order:
+ * kvm_cpu -> host_cpu -> x86_cpu
+ */
+ if (cpu->max_features) {
+ if (enable_cpu_pm && kvm_has_waitpkg()) {
+ env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG;
+ }
+ if (cpu->ucode_rev == 0) {
+ cpu->ucode_rev =
+ kvm_arch_get_supported_msr_feature(kvm_state,
+ MSR_IA32_UCODE_REV);
+ }
+ }
+ return host_cpu_realizefn(cs, errp);
+}
+
+/*
+ * KVM-specific features that are automatically added/removed
+ * from all CPU models when KVM is enabled.
+ */
+static PropValue kvm_default_props[] = {
+ { "kvmclock", "on" },
+ { "kvm-nopiodelay", "on" },
+ { "kvm-asyncpf", "on" },
+ { "kvm-steal-time", "on" },
+ { "kvm-pv-eoi", "on" },
+ { "kvmclock-stable-bit", "on" },
+ { "x2apic", "on" },
+ { "kvm-msi-ext-dest-id", "off" },
+ { "acpi", "off" },
+ { "monitor", "off" },
+ { "svm", "off" },
+ { NULL, NULL },
+};
+
+void x86_cpu_change_kvm_default(const char *prop, const char *value)
+{
+ PropValue *pv;
+ for (pv = kvm_default_props; pv->prop; pv++) {
+ if (!strcmp(pv->prop, prop)) {
+ pv->value = value;
+ break;
+ }
+ }
+
+ /*
+ * It is valid to call this function only for properties that
+ * are already present in the kvm_default_props table.
+ */
+ assert(pv->prop);
+}
+
+static bool lmce_supported(void)
+{
+ uint64_t mce_cap = 0;
+
+ if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) {
+ return false;
+ }
+ return !!(mce_cap & MCG_LMCE_P);
+}
+
+static void kvm_cpu_max_instance_init(X86CPU *cpu)
+{
+ CPUX86State *env = &cpu->env;
+ KVMState *s = kvm_state;
+
+ host_cpu_max_instance_init(cpu);
+
+ if (lmce_supported()) {
+ object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort);
+ }
+
+ env->cpuid_min_level =
+ kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+ env->cpuid_min_xlevel =
+ kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX);
+ env->cpuid_min_xlevel2 =
+ kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+}
+
+static void kvm_cpu_instance_init(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ host_cpu_instance_init(cpu);
+
+ if (!kvm_irqchip_in_kernel()) {
+ x86_cpu_change_kvm_default("x2apic", "off");
+ } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) {
+ x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on");
+ }
+
+ /* Special cases not set in the X86CPUDefinition structs: */
+
+ x86_cpu_apply_props(cpu, kvm_default_props);
+
+ if (cpu->max_features) {
+ kvm_cpu_max_instance_init(cpu);
+ }
+}
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+ acc->cpu_realizefn = kvm_cpu_realizefn;
+ acc->cpu_instance_init = kvm_cpu_instance_init;
+}
+static const TypeInfo kvm_cpu_accel_type_info = {
+ .name = ACCEL_CPU_NAME("kvm"),
+
+ .parent = TYPE_ACCEL_CPU,
+ .class_init = kvm_cpu_accel_class_init,
+ .abstract = true,
+};
+static void kvm_cpu_accel_register_types(void)
+{
+ type_register_static(&kvm_cpu_accel_type_info);
+}
+type_init(kvm_cpu_accel_register_types);
diff --git a/target/i386/kvm/kvm-cpu.h b/target/i386/kvm/kvm-cpu.h
new file mode 100644
index 0000000000..e858ca21e5
--- /dev/null
+++ b/target/i386/kvm/kvm-cpu.h
@@ -0,0 +1,41 @@
+/*
+ * i386 KVM CPU type and functions
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KVM_CPU_H
+#define KVM_CPU_H
+
+#ifdef CONFIG_KVM
+/*
+ * Change the value of a KVM-specific default
+ *
+ * If value is NULL, no default will be set and the original
+ * value from the CPU model table will be kept.
+ *
+ * It is valid to call this function only for properties that
+ * are already present in the kvm_default_props table.
+ */
+void x86_cpu_change_kvm_default(const char *prop, const char *value);
+
+#else /* !CONFIG_KVM */
+
+#define x86_cpu_change_kvm_default(a, b)
+
+#endif /* CONFIG_KVM */
+
+#endif /* KVM_CPU_H */
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 7fe9f52710..d972eb4705 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -22,6 +22,7 @@
#include "standard-headers/asm-x86/kvm_para.h"
#include "cpu.h"
+#include "host-cpu.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm_int.h"
@@ -288,7 +289,7 @@ static bool host_tsx_broken(void)
int family, model, stepping;\
char vendor[CPUID_VENDOR_SZ + 1];
- host_vendor_fms(vendor, &family, &model, &stepping);
+ host_cpu_vendor_fms(vendor, &family, &model, &stepping);
/* Check if we are running on a Haswell host known to have broken TSX */
return !strcmp(vendor, CPUID_VENDOR_INTEL) &&
diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build
index 1d66559187..0a533411ca 100644
--- a/target/i386/kvm/meson.build
+++ b/target/i386/kvm/meson.build
@@ -1,3 +1,8 @@
i386_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
-i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))
+
+i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files(
+ 'kvm.c',
+ 'kvm-cpu.c',
+))
+
i386_softmmu_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c'))
diff --git a/target/i386/meson.build b/target/i386/meson.build
index b0c04f3d89..dac19ec00d 100644
--- a/target/i386/meson.build
+++ b/target/i386/meson.build
@@ -6,7 +6,11 @@ i386_ss.add(files(
'xsave_helper.c',
'cpu-dump.c',
))
-i386_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-stub.c'))
+i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c', 'sev.c'), if_false: files('sev-stub.c'))
+
+# x86 cpu type
+i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c'))
+i386_ss.add(when: 'CONFIG_HVF', if_true: files('host-cpu.c'))
i386_softmmu_ss = ss.source_set()
i386_softmmu_ss.add(files(
@@ -14,7 +18,9 @@ i386_softmmu_ss.add(files(
'arch_memory_mapping.c',
'machine.c',
'monitor.c',
+ 'cpu-sysemu.c',
))
+i386_user_ss = ss.source_set()
subdir('kvm')
subdir('hax')
@@ -25,3 +31,4 @@ subdir('tcg')
target_arch += {'i386': i386_ss}
target_softmmu_arch += {'i386': i386_softmmu_ss}
+target_user_arch += {'i386': i386_user_ss}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 9a43be11cb..41f7800b5f 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -180,7 +180,8 @@ sev_set_guest_state(SevGuestState *sev, SevState new_state)
}
static void
-sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
+sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size,
+ size_t max_size)
{
int r;
struct kvm_enc_region range;
@@ -197,19 +198,20 @@ sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
}
range.addr = (__u64)(unsigned long)host;
- range.size = size;
+ range.size = max_size;
- trace_kvm_memcrypt_register_region(host, size);
+ trace_kvm_memcrypt_register_region(host, max_size);
r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
if (r) {
error_report("%s: failed to register region (%p+%#zx) error '%s'",
- __func__, host, size, strerror(errno));
+ __func__, host, max_size, strerror(errno));
exit(1);
}
}
static void
-sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
+sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size,
+ size_t max_size)
{
int r;
struct kvm_enc_region range;
@@ -226,13 +228,13 @@ sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
}
range.addr = (__u64)(unsigned long)host;
- range.size = size;
+ range.size = max_size;
- trace_kvm_memcrypt_unregister_region(host, size);
+ trace_kvm_memcrypt_unregister_region(host, max_size);
r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
if (r) {
error_report("%s: failed to unregister region (%p+%#zx)",
- __func__, host, size);
+ __func__, host, max_size);
}
}
diff --git a/target/i386/svm.h b/target/i386/svm.h
index ae30fc6f79..87965e5bc2 100644
--- a/target/i386/svm.h
+++ b/target/i386/svm.h
@@ -132,16 +132,6 @@
#define SVM_NPT_ENABLED (1 << 0)
-#define SVM_NPT_PAE (1 << 0)
-#define SVM_NPT_LMA (1 << 1)
-#define SVM_NPT_NXE (1 << 2)
-#define SVM_NPT_PSE (1 << 3)
-
-#define SVM_NPTEXIT_P (1ULL << 0)
-#define SVM_NPTEXIT_RW (1ULL << 1)
-#define SVM_NPTEXIT_US (1ULL << 2)
-#define SVM_NPTEXIT_RSVD (1ULL << 3)
-#define SVM_NPTEXIT_ID (1ULL << 4)
#define SVM_NPTEXIT_GPA (1ULL << 32)
#define SVM_NPTEXIT_GPT (1ULL << 33)
diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c
index 979230ac12..83cd89581e 100644
--- a/target/i386/tcg/bpt_helper.c
+++ b/target/i386/tcg/bpt_helper.c
@@ -19,224 +19,10 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "helper-tcg.h"
-
-#ifndef CONFIG_USER_ONLY
-static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index)
-{
- return (dr7 >> (index * 2)) & 1;
-}
-
-static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index)
-{
- return (dr7 >> (index * 2)) & 2;
-
-}
-static inline bool hw_breakpoint_enabled(unsigned long dr7, int index)
-{
- return hw_global_breakpoint_enabled(dr7, index) ||
- hw_local_breakpoint_enabled(dr7, index);
-}
-
-static inline int hw_breakpoint_type(unsigned long dr7, int index)
-{
- return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3;
-}
-
-static inline int hw_breakpoint_len(unsigned long dr7, int index)
-{
- int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3);
- return (len == 2) ? 8 : len + 1;
-}
-
-static int hw_breakpoint_insert(CPUX86State *env, int index)
-{
- CPUState *cs = env_cpu(env);
- target_ulong dr7 = env->dr[7];
- target_ulong drN = env->dr[index];
- int err = 0;
-
- switch (hw_breakpoint_type(dr7, index)) {
- case DR7_TYPE_BP_INST:
- if (hw_breakpoint_enabled(dr7, index)) {
- err = cpu_breakpoint_insert(cs, drN, BP_CPU,
- &env->cpu_breakpoint[index]);
- }
- break;
-
- case DR7_TYPE_IO_RW:
- /* Notice when we should enable calls to bpt_io. */
- return hw_breakpoint_enabled(env->dr[7], index)
- ? HF_IOBPT_MASK : 0;
-
- case DR7_TYPE_DATA_WR:
- if (hw_breakpoint_enabled(dr7, index)) {
- err = cpu_watchpoint_insert(cs, drN,
- hw_breakpoint_len(dr7, index),
- BP_CPU | BP_MEM_WRITE,
- &env->cpu_watchpoint[index]);
- }
- break;
-
- case DR7_TYPE_DATA_RW:
- if (hw_breakpoint_enabled(dr7, index)) {
- err = cpu_watchpoint_insert(cs, drN,
- hw_breakpoint_len(dr7, index),
- BP_CPU | BP_MEM_ACCESS,
- &env->cpu_watchpoint[index]);
- }
- break;
- }
- if (err) {
- env->cpu_breakpoint[index] = NULL;
- }
- return 0;
-}
-
-static void hw_breakpoint_remove(CPUX86State *env, int index)
-{
- CPUState *cs = env_cpu(env);
-
- switch (hw_breakpoint_type(env->dr[7], index)) {
- case DR7_TYPE_BP_INST:
- if (env->cpu_breakpoint[index]) {
- cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
- env->cpu_breakpoint[index] = NULL;
- }
- break;
-
- case DR7_TYPE_DATA_WR:
- case DR7_TYPE_DATA_RW:
- if (env->cpu_breakpoint[index]) {
- cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
- env->cpu_breakpoint[index] = NULL;
- }
- break;
-
- case DR7_TYPE_IO_RW:
- /* HF_IOBPT_MASK cleared elsewhere. */
- break;
- }
-}
-
-void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
-{
- target_ulong old_dr7 = env->dr[7];
- int iobpt = 0;
- int i;
-
- new_dr7 |= DR7_FIXED_1;
-
- /* If nothing is changing except the global/local enable bits,
- then we can make the change more efficient. */
- if (((old_dr7 ^ new_dr7) & ~0xff) == 0) {
- /* Fold the global and local enable bits together into the
- global fields, then xor to show which registers have
- changed collective enable state. */
- int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff;
-
- for (i = 0; i < DR7_MAX_BP; i++) {
- if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) {
- hw_breakpoint_remove(env, i);
- }
- }
- env->dr[7] = new_dr7;
- for (i = 0; i < DR7_MAX_BP; i++) {
- if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) {
- iobpt |= hw_breakpoint_insert(env, i);
- } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW
- && hw_breakpoint_enabled(new_dr7, i)) {
- iobpt |= HF_IOBPT_MASK;
- }
- }
- } else {
- for (i = 0; i < DR7_MAX_BP; i++) {
- hw_breakpoint_remove(env, i);
- }
- env->dr[7] = new_dr7;
- for (i = 0; i < DR7_MAX_BP; i++) {
- iobpt |= hw_breakpoint_insert(env, i);
- }
- }
-
- env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt;
-}
-
-static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
-{
- target_ulong dr6;
- int reg;
- bool hit_enabled = false;
-
- dr6 = env->dr[6] & ~0xf;
- for (reg = 0; reg < DR7_MAX_BP; reg++) {
- bool bp_match = false;
- bool wp_match = false;
-
- switch (hw_breakpoint_type(env->dr[7], reg)) {
- case DR7_TYPE_BP_INST:
- if (env->dr[reg] == env->eip) {
- bp_match = true;
- }
- break;
- case DR7_TYPE_DATA_WR:
- case DR7_TYPE_DATA_RW:
- if (env->cpu_watchpoint[reg] &&
- env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
- wp_match = true;
- }
- break;
- case DR7_TYPE_IO_RW:
- break;
- }
- if (bp_match || wp_match) {
- dr6 |= 1 << reg;
- if (hw_breakpoint_enabled(env->dr[7], reg)) {
- hit_enabled = true;
- }
- }
- }
-
- if (hit_enabled || force_dr6_update) {
- env->dr[6] = dr6;
- }
-
- return hit_enabled;
-}
-
-void breakpoint_handler(CPUState *cs)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- CPUBreakpoint *bp;
-
- if (cs->watchpoint_hit) {
- if (cs->watchpoint_hit->flags & BP_CPU) {
- cs->watchpoint_hit = NULL;
- if (check_hw_breakpoints(env, false)) {
- raise_exception(env, EXCP01_DB);
- } else {
- cpu_loop_exit_noexc(cs);
- }
- }
- } else {
- QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
- if (bp->pc == env->eip) {
- if (bp->flags & BP_CPU) {
- check_hw_breakpoints(env, true);
- raise_exception(env, EXCP01_DB);
- }
- break;
- }
- }
- }
-}
-#endif
-
-void helper_single_step(CPUX86State *env)
+void QEMU_NORETURN helper_single_step(CPUX86State *env)
{
#ifndef CONFIG_USER_ONLY
check_hw_breakpoints(env, true);
@@ -252,41 +38,6 @@ void helper_rechecking_single_step(CPUX86State *env)
}
}
-void helper_set_dr(CPUX86State *env, int reg, target_ulong t0)
-{
-#ifndef CONFIG_USER_ONLY
- switch (reg) {
- case 0: case 1: case 2: case 3:
- if (hw_breakpoint_enabled(env->dr[7], reg)
- && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) {
- hw_breakpoint_remove(env, reg);
- env->dr[reg] = t0;
- hw_breakpoint_insert(env, reg);
- } else {
- env->dr[reg] = t0;
- }
- return;
- case 4:
- if (env->cr[4] & CR4_DE_MASK) {
- break;
- }
- /* fallthru */
- case 6:
- env->dr[6] = t0 | DR6_FIXED_1;
- return;
- case 5:
- if (env->cr[4] & CR4_DE_MASK) {
- break;
- }
- /* fallthru */
- case 7:
- cpu_x86_update_dr7(env, t0);
- return;
- }
- raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
-#endif
-}
-
target_ulong helper_get_dr(CPUX86State *env, int reg)
{
switch (reg) {
@@ -307,30 +58,3 @@ target_ulong helper_get_dr(CPUX86State *env, int reg)
}
raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
}
-
-/* Check if Port I/O is trapped by a breakpoint. */
-void helper_bpt_io(CPUX86State *env, uint32_t port,
- uint32_t size, target_ulong next_eip)
-{
-#ifndef CONFIG_USER_ONLY
- target_ulong dr7 = env->dr[7];
- int i, hit = 0;
-
- for (i = 0; i < DR7_MAX_BP; ++i) {
- if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW
- && hw_breakpoint_enabled(dr7, i)) {
- int bpt_len = hw_breakpoint_len(dr7, i);
- if (port + size - 1 >= env->dr[i]
- && port <= env->dr[i] + bpt_len - 1) {
- hit |= 1 << i;
- }
- }
- }
-
- if (hit) {
- env->dr[6] = (env->dr[6] & ~0xf) | hit;
- env->eip = next_eip;
- raise_exception(env, EXCP01_DB);
- }
-#endif
-}
diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c
index 1e71e44510..bdae887d0a 100644
--- a/target/i386/tcg/excp_helper.c
+++ b/target/i386/tcg/excp_helper.c
@@ -25,12 +25,13 @@
#include "exec/helper-proto.h"
#include "helper-tcg.h"
-void helper_raise_interrupt(CPUX86State *env, int intno, int next_eip_addend)
+void QEMU_NORETURN helper_raise_interrupt(CPUX86State *env, int intno,
+ int next_eip_addend)
{
raise_interrupt(env, intno, 1, 0, next_eip_addend);
}
-void helper_raise_exception(CPUX86State *env, int exception_index)
+void QEMU_NORETURN helper_raise_exception(CPUX86State *env, int exception_index)
{
raise_exception(env, exception_index);
}
@@ -116,597 +117,25 @@ void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int,
raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0);
}
-void raise_exception_err(CPUX86State *env, int exception_index,
- int error_code)
+void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index,
+ int error_code)
{
raise_interrupt2(env, exception_index, 0, error_code, 0, 0);
}
-void raise_exception_err_ra(CPUX86State *env, int exception_index,
- int error_code, uintptr_t retaddr)
+void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index,
+ int error_code, uintptr_t retaddr)
{
raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr);
}
-void raise_exception(CPUX86State *env, int exception_index)
+void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index)
{
raise_interrupt2(env, exception_index, 0, 0, 0, 0);
}
-void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t retaddr)
+void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index,
+ uintptr_t retaddr)
{
raise_interrupt2(env, exception_index, 0, 0, 0, retaddr);
}
-
-#if !defined(CONFIG_USER_ONLY)
-static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
- int *prot)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
- uint64_t ptep, pte;
- uint64_t exit_info_1 = 0;
- target_ulong pde_addr, pte_addr;
- uint32_t page_offset;
- int page_size;
-
- if (likely(!(env->hflags2 & HF2_NPT_MASK))) {
- return gphys;
- }
-
- if (!(env->nested_pg_mode & SVM_NPT_NXE)) {
- rsvd_mask |= PG_NX_MASK;
- }
-
- if (env->nested_pg_mode & SVM_NPT_PAE) {
- uint64_t pde, pdpe;
- target_ulong pdpe_addr;
-
-#ifdef TARGET_X86_64
- if (env->nested_pg_mode & SVM_NPT_LMA) {
- uint64_t pml5e;
- uint64_t pml4e_addr, pml4e;
-
- pml5e = env->nested_cr3;
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
-
- pml4e_addr = (pml5e & PG_ADDRESS_MASK) +
- (((gphys >> 39) & 0x1ff) << 3);
- pml4e = x86_ldq_phys(cs, pml4e_addr);
- if (!(pml4e & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pml4e & (rsvd_mask | PG_PSE_MASK)) {
- goto do_fault_rsvd;
- }
- if (!(pml4e & PG_ACCESSED_MASK)) {
- pml4e |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pml4e_addr, pml4e);
- }
- ptep &= pml4e ^ PG_NX_MASK;
- pdpe_addr = (pml4e & PG_ADDRESS_MASK) +
- (((gphys >> 30) & 0x1ff) << 3);
- pdpe = x86_ldq_phys(cs, pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pdpe & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep &= pdpe ^ PG_NX_MASK;
- if (!(pdpe & PG_ACCESSED_MASK)) {
- pdpe |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pdpe_addr, pdpe);
- }
- if (pdpe & PG_PSE_MASK) {
- /* 1 GB page */
- page_size = 1024 * 1024 * 1024;
- pte_addr = pdpe_addr;
- pte = pdpe;
- goto do_check_protect;
- }
- } else
-#endif
- {
- pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18);
- pdpe = x86_ldq_phys(cs, pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- rsvd_mask |= PG_HI_USER_MASK;
- if (pdpe & (rsvd_mask | PG_NX_MASK)) {
- goto do_fault_rsvd;
- }
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
- }
-
- pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3);
- pde = x86_ldq_phys(cs, pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pde & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep &= pde ^ PG_NX_MASK;
- if (pde & PG_PSE_MASK) {
- /* 2 MB page */
- page_size = 2048 * 1024;
- pte_addr = pde_addr;
- pte = pde;
- goto do_check_protect;
- }
- /* 4 KB page */
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pde_addr, pde);
- }
- pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3);
- pte = x86_ldq_phys(cs, pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pte & rsvd_mask) {
- goto do_fault_rsvd;
- }
- /* combine pde and pte nx, user and rw protections */
- ptep &= pte ^ PG_NX_MASK;
- page_size = 4096;
- } else {
- uint32_t pde;
-
- /* page directory entry */
- pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc);
- pde = x86_ldl_phys(cs, pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- ptep = pde | PG_NX_MASK;
-
- /* if host cr4 PSE bit is set, then we use a 4MB page */
- if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) {
- page_size = 4096 * 1024;
- pte_addr = pde_addr;
-
- /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
- * Leave bits 20-13 in place for setting accessed/dirty bits below.
- */
- pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
- rsvd_mask = 0x200000;
- goto do_check_protect_pse36;
- }
-
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pde_addr, pde);
- }
-
- /* page directory entry */
- pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc);
- pte = x86_ldl_phys(cs, pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- /* combine pde and pte user and rw protections */
- ptep &= pte | PG_NX_MASK;
- page_size = 4096;
- rsvd_mask = 0;
- }
-
- do_check_protect:
- rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK;
- do_check_protect_pse36:
- if (pte & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep ^= PG_NX_MASK;
-
- if (!(ptep & PG_USER_MASK)) {
- goto do_fault_protect;
- }
- if (ptep & PG_NX_MASK) {
- if (access_type == MMU_INST_FETCH) {
- goto do_fault_protect;
- }
- *prot &= ~PAGE_EXEC;
- }
- if (!(ptep & PG_RW_MASK)) {
- if (access_type == MMU_DATA_STORE) {
- goto do_fault_protect;
- }
- *prot &= ~PAGE_WRITE;
- }
-
- pte &= PG_ADDRESS_MASK & ~(page_size - 1);
- page_offset = gphys & (page_size - 1);
- return pte + page_offset;
-
- do_fault_rsvd:
- exit_info_1 |= SVM_NPTEXIT_RSVD;
- do_fault_protect:
- exit_info_1 |= SVM_NPTEXIT_P;
- do_fault:
- x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
- gphys);
- exit_info_1 |= SVM_NPTEXIT_US;
- if (access_type == MMU_DATA_STORE) {
- exit_info_1 |= SVM_NPTEXIT_RW;
- } else if (access_type == MMU_INST_FETCH) {
- exit_info_1 |= SVM_NPTEXIT_ID;
- }
- if (prot) {
- exit_info_1 |= SVM_NPTEXIT_GPA;
- } else { /* page table access */
- exit_info_1 |= SVM_NPTEXIT_GPT;
- }
- cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr);
-}
-
-/* return value:
- * -1 = cannot handle fault
- * 0 = nothing more to do
- * 1 = generate PF fault
- */
-static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
- int is_write1, int mmu_idx)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- uint64_t ptep, pte;
- int32_t a20_mask;
- target_ulong pde_addr, pte_addr;
- int error_code = 0;
- int is_dirty, prot, page_size, is_write, is_user;
- hwaddr paddr;
- uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
- uint32_t page_offset;
- target_ulong vaddr;
- uint32_t pkr;
-
- is_user = mmu_idx == MMU_USER_IDX;
-#if defined(DEBUG_MMU)
- printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
- addr, is_write1, is_user, env->eip);
-#endif
- is_write = is_write1 & 1;
-
- a20_mask = x86_get_a20_mask(env);
- if (!(env->cr[0] & CR0_PG_MASK)) {
- pte = addr;
-#ifdef TARGET_X86_64
- if (!(env->hflags & HF_LMA_MASK)) {
- /* Without long mode we can only address 32bits in real mode */
- pte = (uint32_t)pte;
- }
-#endif
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- page_size = 4096;
- goto do_mapping;
- }
-
- if (!(env->efer & MSR_EFER_NXE)) {
- rsvd_mask |= PG_NX_MASK;
- }
-
- if (env->cr[4] & CR4_PAE_MASK) {
- uint64_t pde, pdpe;
- target_ulong pdpe_addr;
-
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- bool la57 = env->cr[4] & CR4_LA57_MASK;
- uint64_t pml5e_addr, pml5e;
- uint64_t pml4e_addr, pml4e;
- int32_t sext;
-
- /* test virtual address sign extension */
- sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47;
- if (sext != 0 && sext != -1) {
- env->error_code = 0;
- cs->exception_index = EXCP0D_GPF;
- return 1;
- }
-
- if (la57) {
- pml5e_addr = ((env->cr[3] & ~0xfff) +
- (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
- pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL);
- pml5e = x86_ldq_phys(cs, pml5e_addr);
- if (!(pml5e & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pml5e & (rsvd_mask | PG_PSE_MASK)) {
- goto do_fault_rsvd;
- }
- if (!(pml5e & PG_ACCESSED_MASK)) {
- pml5e |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pml5e_addr, pml5e);
- }
- ptep = pml5e ^ PG_NX_MASK;
- } else {
- pml5e = env->cr[3];
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
- }
-
- pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
- (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
- pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false);
- pml4e = x86_ldq_phys(cs, pml4e_addr);
- if (!(pml4e & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pml4e & (rsvd_mask | PG_PSE_MASK)) {
- goto do_fault_rsvd;
- }
- if (!(pml4e & PG_ACCESSED_MASK)) {
- pml4e |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pml4e_addr, pml4e);
- }
- ptep &= pml4e ^ PG_NX_MASK;
- pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
- a20_mask;
- pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL);
- pdpe = x86_ldq_phys(cs, pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pdpe & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep &= pdpe ^ PG_NX_MASK;
- if (!(pdpe & PG_ACCESSED_MASK)) {
- pdpe |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pdpe_addr, pdpe);
- }
- if (pdpe & PG_PSE_MASK) {
- /* 1 GB page */
- page_size = 1024 * 1024 * 1024;
- pte_addr = pdpe_addr;
- pte = pdpe;
- goto do_check_protect;
- }
- } else
-#endif
- {
- /* XXX: load them when cr3 is loaded ? */
- pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
- a20_mask;
- pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false);
- pdpe = x86_ldq_phys(cs, pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- rsvd_mask |= PG_HI_USER_MASK;
- if (pdpe & (rsvd_mask | PG_NX_MASK)) {
- goto do_fault_rsvd;
- }
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
- }
-
- pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
- a20_mask;
- pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL);
- pde = x86_ldq_phys(cs, pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pde & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep &= pde ^ PG_NX_MASK;
- if (pde & PG_PSE_MASK) {
- /* 2 MB page */
- page_size = 2048 * 1024;
- pte_addr = pde_addr;
- pte = pde;
- goto do_check_protect;
- }
- /* 4 KB page */
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pde_addr, pde);
- }
- pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
- a20_mask;
- pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL);
- pte = x86_ldq_phys(cs, pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- if (pte & rsvd_mask) {
- goto do_fault_rsvd;
- }
- /* combine pde and pte nx, user and rw protections */
- ptep &= pte ^ PG_NX_MASK;
- page_size = 4096;
- } else {
- uint32_t pde;
-
- /* page directory entry */
- pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
- a20_mask;
- pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL);
- pde = x86_ldl_phys(cs, pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- ptep = pde | PG_NX_MASK;
-
- /* if PSE bit is set, then we use a 4MB page */
- if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
- page_size = 4096 * 1024;
- pte_addr = pde_addr;
-
- /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
- * Leave bits 20-13 in place for setting accessed/dirty bits below.
- */
- pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
- rsvd_mask = 0x200000;
- goto do_check_protect_pse36;
- }
-
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- x86_stl_phys_notdirty(cs, pde_addr, pde);
- }
-
- /* page directory entry */
- pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
- a20_mask;
- pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL);
- pte = x86_ldl_phys(cs, pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- goto do_fault;
- }
- /* combine pde and pte user and rw protections */
- ptep &= pte | PG_NX_MASK;
- page_size = 4096;
- rsvd_mask = 0;
- }
-
-do_check_protect:
- rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK;
-do_check_protect_pse36:
- if (pte & rsvd_mask) {
- goto do_fault_rsvd;
- }
- ptep ^= PG_NX_MASK;
-
- /* can the page can be put in the TLB? prot will tell us */
- if (is_user && !(ptep & PG_USER_MASK)) {
- goto do_fault_protect;
- }
-
- prot = 0;
- if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
- prot |= PAGE_READ;
- if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) {
- prot |= PAGE_WRITE;
- }
- }
- if (!(ptep & PG_NX_MASK) &&
- (mmu_idx == MMU_USER_IDX ||
- !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) {
- prot |= PAGE_EXEC;
- }
-
- if (!(env->hflags & HF_LMA_MASK)) {
- pkr = 0;
- } else if (ptep & PG_USER_MASK) {
- pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0;
- } else {
- pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0;
- }
- if (pkr) {
- uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT;
- uint32_t pkr_ad = (pkr >> pk * 2) & 1;
- uint32_t pkr_wd = (pkr >> pk * 2) & 2;
- uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-
- if (pkr_ad) {
- pkr_prot &= ~(PAGE_READ | PAGE_WRITE);
- } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) {
- pkr_prot &= ~PAGE_WRITE;
- }
-
- prot &= pkr_prot;
- if ((pkr_prot & (1 << is_write1)) == 0) {
- assert(is_write1 != 2);
- error_code |= PG_ERROR_PK_MASK;
- goto do_fault_protect;
- }
- }
-
- if ((prot & (1 << is_write1)) == 0) {
- goto do_fault_protect;
- }
-
- /* yes, it can! */
- is_dirty = is_write && !(pte & PG_DIRTY_MASK);
- if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
- pte |= PG_ACCESSED_MASK;
- if (is_dirty) {
- pte |= PG_DIRTY_MASK;
- }
- x86_stl_phys_notdirty(cs, pte_addr, pte);
- }
-
- if (!(pte & PG_DIRTY_MASK)) {
- /* only set write access if already dirty... otherwise wait
- for dirty access */
- assert(!is_write);
- prot &= ~PAGE_WRITE;
- }
-
- do_mapping:
- pte = pte & a20_mask;
-
- /* align to page_size */
- pte &= PG_ADDRESS_MASK & ~(page_size - 1);
- page_offset = addr & (page_size - 1);
- paddr = get_hphys(cs, pte + page_offset, is_write1, &prot);
-
- /* Even if 4MB pages, we map only one 4KB page in the cache to
- avoid filling it too fast */
- vaddr = addr & TARGET_PAGE_MASK;
- paddr &= TARGET_PAGE_MASK;
-
- assert(prot & (1 << is_write1));
- tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
- prot, mmu_idx, page_size);
- return 0;
- do_fault_rsvd:
- error_code |= PG_ERROR_RSVD_MASK;
- do_fault_protect:
- error_code |= PG_ERROR_P_MASK;
- do_fault:
- error_code |= (is_write << PG_ERROR_W_BIT);
- if (is_user)
- error_code |= PG_ERROR_U_MASK;
- if (is_write1 == 2 &&
- (((env->efer & MSR_EFER_NXE) &&
- (env->cr[4] & CR4_PAE_MASK)) ||
- (env->cr[4] & CR4_SMEP_MASK)))
- error_code |= PG_ERROR_I_D_MASK;
- if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
- /* cr2 is not modified in case of exceptions */
- x86_stq_phys(cs,
- env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
- addr);
- } else {
- env->cr[2] = addr;
- }
- env->error_code = error_code;
- cs->exception_index = EXCP0E_PAGE;
- return 1;
-}
-#endif
-
-bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
-
-#ifdef CONFIG_USER_ONLY
- /* user mode only emulation */
- env->cr[2] = addr;
- env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT;
- env->error_code |= PG_ERROR_U_MASK;
- cs->exception_index = EXCP0E_PAGE;
- env->exception_is_int = 0;
- env->exception_next_eip = -1;
- cpu_loop_exit_restore(cs, retaddr);
-#else
- env->retaddr = retaddr;
- if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) {
- /* FIXME: On error in get_hphys we have already jumped out. */
- g_assert(!probe);
- raise_exception_err_ra(env, cs->exception_index,
- env->error_code, retaddr);
- }
- return true;
-#endif
-}
diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c
index 60ed93520a..1b30f1bb73 100644
--- a/target/i386/tcg/fpu_helper.c
+++ b/target/i386/tcg/fpu_helper.c
@@ -21,17 +21,10 @@
#include <math.h>
#include "cpu.h"
#include "exec/helper-proto.h"
-#include "qemu/host-utils.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
#include "fpu/softfloat.h"
#include "fpu/softfloat-macros.h"
#include "helper-tcg.h"
-#ifdef CONFIG_SOFTMMU
-#include "hw/irq.h"
-#endif
-
/* float macros */
#define FT0 (env->ft0)
#define ST0 (env->fpregs[env->fpstt].d)
@@ -75,36 +68,6 @@
#define floatx80_ln2_d make_floatx80(0x3ffe, 0xb17217f7d1cf79abLL)
#define floatx80_pi_d make_floatx80(0x4000, 0xc90fdaa22168c234LL)
-#if !defined(CONFIG_USER_ONLY)
-static qemu_irq ferr_irq;
-
-void x86_register_ferr_irq(qemu_irq irq)
-{
- ferr_irq = irq;
-}
-
-static void cpu_clear_ignne(void)
-{
- CPUX86State *env = &X86_CPU(first_cpu)->env;
- env->hflags2 &= ~HF2_IGNNE_MASK;
-}
-
-void cpu_set_ignne(void)
-{
- CPUX86State *env = &X86_CPU(first_cpu)->env;
- env->hflags2 |= HF2_IGNNE_MASK;
- /*
- * We get here in response to a write to port F0h. The chipset should
- * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is
- * cleared, because FERR# and FP_IRQ are two separate pins on real
- * hardware. However, we don't model FERR# as a qemu_irq, so we just
- * do directly what the chipset would do, i.e. deassert FP_IRQ.
- */
- qemu_irq_lower(ferr_irq);
-}
-#endif
-
-
static inline void fpush(CPUX86State *env)
{
env->fpstt = (env->fpstt - 1) & 7;
@@ -117,8 +80,7 @@ static inline void fpop(CPUX86State *env)
env->fpstt = (env->fpstt + 1) & 7;
}
-static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr,
- uintptr_t retaddr)
+static floatx80 do_fldt(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
{
CPU_LDoubleU temp;
@@ -127,8 +89,8 @@ static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr,
return temp.d;
}
-static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr,
- uintptr_t retaddr)
+static void do_fstt(CPUX86State *env, floatx80 f, target_ulong ptr,
+ uintptr_t retaddr)
{
CPU_LDoubleU temp;
@@ -203,8 +165,8 @@ static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr)
raise_exception_ra(env, EXCP10_COPR, retaddr);
}
#if !defined(CONFIG_USER_ONLY)
- else if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) {
- qemu_irq_raise(ferr_irq);
+ else {
+ fpu_check_raise_ferr_irq(env);
}
#endif
}
@@ -405,14 +367,14 @@ void helper_fldt_ST0(CPUX86State *env, target_ulong ptr)
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = helper_fldt(env, ptr, GETPC());
+ env->fpregs[new_fpstt].d = do_fldt(env, ptr, GETPC());
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
void helper_fstt_ST0(CPUX86State *env, target_ulong ptr)
{
- helper_fstt(env, ST0, ptr, GETPC());
+ do_fstt(env, ST0, ptr, GETPC());
}
void helper_fpush(CPUX86State *env)
@@ -2458,17 +2420,18 @@ void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)
do_fldenv(env, ptr, data32, GETPC());
}
-void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
+static void do_fsave(CPUX86State *env, target_ulong ptr, int data32,
+ uintptr_t retaddr)
{
floatx80 tmp;
int i;
- do_fstenv(env, ptr, data32, GETPC());
+ do_fstenv(env, ptr, data32, retaddr);
ptr += (14 << data32);
for (i = 0; i < 8; i++) {
tmp = ST(i);
- helper_fstt(env, tmp, ptr, GETPC());
+ do_fstt(env, tmp, ptr, retaddr);
ptr += 10;
}
@@ -2486,30 +2449,41 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
env->fptags[7] = 1;
}
-void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
+void helper_fsave(CPUX86State *env, target_ulong ptr, int data32)
+{
+ do_fsave(env, ptr, data32, GETPC());
+}
+
+static void do_frstor(CPUX86State *env, target_ulong ptr, int data32,
+ uintptr_t retaddr)
{
floatx80 tmp;
int i;
- do_fldenv(env, ptr, data32, GETPC());
+ do_fldenv(env, ptr, data32, retaddr);
ptr += (14 << data32);
for (i = 0; i < 8; i++) {
- tmp = helper_fldt(env, ptr, GETPC());
+ tmp = do_fldt(env, ptr, retaddr);
ST(i) = tmp;
ptr += 10;
}
}
+void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
+{
+ do_frstor(env, ptr, data32, GETPC());
+}
+
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
- helper_fsave(env, ptr, data32);
+ do_fsave(env, ptr, data32, 0);
}
void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
- helper_frstor(env, ptr, data32);
+ do_frstor(env, ptr, data32, 0);
}
#endif
@@ -2539,7 +2513,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
addr = ptr + XO(legacy.fpregs);
for (i = 0; i < 8; i++) {
floatx80 tmp = ST(i);
- helper_fstt(env, tmp, addr, ra);
+ do_fstt(env, tmp, addr, ra);
addr += 16;
}
}
@@ -2594,10 +2568,8 @@ static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
cpu_stq_data_ra(env, ptr, env->pkru, ra);
}
-void helper_fxsave(CPUX86State *env, target_ulong ptr)
+static void do_fxsave(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
- uintptr_t ra = GETPC();
-
/* The operand must be 16 byte aligned */
if (ptr & 0xf) {
raise_exception_ra(env, EXCP0D_GPF, ra);
@@ -2616,6 +2588,11 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr)
}
}
+void helper_fxsave(CPUX86State *env, target_ulong ptr)
+{
+ do_fxsave(env, ptr, GETPC());
+}
+
static uint64_t get_xinuse(CPUX86State *env)
{
uint64_t inuse = -1;
@@ -2703,7 +2680,7 @@ static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
addr = ptr + XO(legacy.fpregs);
for (i = 0; i < 8; i++) {
- floatx80 tmp = helper_fldt(env, addr, ra);
+ floatx80 tmp = do_fldt(env, addr, ra);
ST(i) = tmp;
addr += 16;
}
@@ -2758,10 +2735,8 @@ static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra)
env->pkru = cpu_ldq_data_ra(env, ptr, ra);
}
-void helper_fxrstor(CPUX86State *env, target_ulong ptr)
+static void do_fxrstor(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
- uintptr_t ra = GETPC();
-
/* The operand must be 16 byte aligned */
if (ptr & 0xf) {
raise_exception_ra(env, EXCP0D_GPF, ra);
@@ -2780,15 +2755,20 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr)
}
}
+void helper_fxrstor(CPUX86State *env, target_ulong ptr)
+{
+ do_fxrstor(env, ptr, GETPC());
+}
+
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
{
- helper_fxsave(env, ptr);
+ do_fxsave(env, ptr, 0);
}
void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
{
- helper_fxrstor(env, ptr);
+ do_fxrstor(env, ptr, 0);
}
#endif
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index bcdfca06f6..2510cc244e 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -76,16 +76,27 @@ extern const uint8_t parity_table[256];
/* misc_helper.c */
void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask);
+void do_pause(CPUX86State *env) QEMU_NORETURN;
-/* svm_helper.c */
+/* sysemu/svm_helper.c */
+#ifndef CONFIG_USER_ONLY
void QEMU_NORETURN cpu_vmexit(CPUX86State *nenv, uint32_t exit_code,
uint64_t exit_info_1, uintptr_t retaddr);
void do_vmexit(CPUX86State *env);
+#endif
/* seg_helper.c */
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
+void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
+ int error_code, target_ulong next_eip, int is_hw);
+void handle_even_inj(CPUX86State *env, int intno, int is_int,
+ int error_code, int is_hw, int rm);
+int exception_has_error_code(int intno);
/* smm_helper.c */
void do_smm_enter(X86CPU *cpu);
+/* bpt_helper.c */
+bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update);
+
#endif /* I386_HELPER_TCG_H */
diff --git a/target/i386/tcg/meson.build b/target/i386/tcg/meson.build
index 6a1a73cdbf..f9110e890c 100644
--- a/target/i386/tcg/meson.build
+++ b/target/i386/tcg/meson.build
@@ -8,7 +8,8 @@ i386_ss.add(when: 'CONFIG_TCG', if_true: files(
'misc_helper.c',
'mpx_helper.c',
'seg_helper.c',
- 'smm_helper.c',
- 'svm_helper.c',
'tcg-cpu.c',
'translate.c'), if_false: files('tcg-stub.c'))
+
+subdir('sysemu')
+subdir('user')
diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c
index a25428c36e..baffa5d7ba 100644
--- a/target/i386/tcg/misc_helper.c
+++ b/target/i386/tcg/misc_helper.c
@@ -18,12 +18,9 @@
*/
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "exec/address-spaces.h"
#include "helper-tcg.h"
/*
@@ -39,69 +36,6 @@ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask)
(eflags & update_mask) | 0x2;
}
-void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data);
-#else
- address_space_stb(&address_space_io, port, data,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
-target_ulong helper_inb(CPUX86State *env, uint32_t port)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "inb: port=0x%04x\n", port);
- return 0;
-#else
- return address_space_ldub(&address_space_io, port,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
-void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data);
-#else
- address_space_stw(&address_space_io, port, data,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
-target_ulong helper_inw(CPUX86State *env, uint32_t port)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "inw: port=0x%04x\n", port);
- return 0;
-#else
- return address_space_lduw(&address_space_io, port,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
-void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data);
-#else
- address_space_stl(&address_space_io, port, data,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
-target_ulong helper_inl(CPUX86State *env, uint32_t port)
-{
-#ifdef CONFIG_USER_ONLY
- fprintf(stderr, "inl: port=0x%04x\n", port);
- return 0;
-#else
- return address_space_ldl(&address_space_io, port,
- cpu_get_mem_attrs(env), NULL);
-#endif
-}
-
void helper_into(CPUX86State *env, int next_eip_addend)
{
int eflags;
@@ -126,84 +60,6 @@ void helper_cpuid(CPUX86State *env)
env->regs[R_EDX] = edx;
}
-#if defined(CONFIG_USER_ONLY)
-target_ulong helper_read_crN(CPUX86State *env, int reg)
-{
- return 0;
-}
-
-void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
-{
-}
-#else
-target_ulong helper_read_crN(CPUX86State *env, int reg)
-{
- target_ulong val;
-
- cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
- switch (reg) {
- default:
- val = env->cr[reg];
- break;
- case 8:
- if (!(env->hflags2 & HF2_VINTR_MASK)) {
- val = cpu_get_apic_tpr(env_archcpu(env)->apic_state);
- } else {
- val = env->v_tpr;
- }
- break;
- }
- return val;
-}
-
-void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
-{
- cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
- switch (reg) {
- case 0:
- cpu_x86_update_cr0(env, t0);
- break;
- case 3:
- cpu_x86_update_cr3(env, t0);
- break;
- case 4:
- if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) &&
- (env->hflags & HF_CS64_MASK)) {
- raise_exception_ra(env, EXCP0D_GPF, GETPC());
- }
- cpu_x86_update_cr4(env, t0);
- break;
- case 8:
- if (!(env->hflags2 & HF2_VINTR_MASK)) {
- qemu_mutex_lock_iothread();
- cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0);
- qemu_mutex_unlock_iothread();
- }
- env->v_tpr = t0 & 0x0f;
- break;
- default:
- env->cr[reg] = t0;
- break;
- }
-}
-#endif
-
-void helper_lmsw(CPUX86State *env, target_ulong t0)
-{
- /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
- if already set to one. */
- t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
- helper_write_crN(env, 0, t0);
-}
-
-void helper_invlpg(CPUX86State *env, target_ulong addr)
-{
- X86CPU *cpu = env_archcpu(env);
-
- cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
- tlb_flush_page(CPU(cpu), addr);
-}
-
void helper_rdtsc(CPUX86State *env)
{
uint64_t val;
@@ -224,7 +80,7 @@ void helper_rdtscp(CPUX86State *env)
env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
}
-void helper_rdpmc(CPUX86State *env)
+void QEMU_NORETURN helper_rdpmc(CPUX86State *env)
{
if (((env->cr[4] & CR4_PCE_MASK) == 0 ) &&
((env->hflags & HF_CPL_MASK) != 0)) {
@@ -237,414 +93,24 @@ void helper_rdpmc(CPUX86State *env)
raise_exception_err(env, EXCP06_ILLOP, 0);
}
-#if defined(CONFIG_USER_ONLY)
-void helper_wrmsr(CPUX86State *env)
+void QEMU_NORETURN do_pause(CPUX86State *env)
{
-}
-
-void helper_rdmsr(CPUX86State *env)
-{
-}
-#else
-void helper_wrmsr(CPUX86State *env)
-{
- uint64_t val;
CPUState *cs = env_cpu(env);
- cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
-
- val = ((uint32_t)env->regs[R_EAX]) |
- ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
-
- switch ((uint32_t)env->regs[R_ECX]) {
- case MSR_IA32_SYSENTER_CS:
- env->sysenter_cs = val & 0xffff;
- break;
- case MSR_IA32_SYSENTER_ESP:
- env->sysenter_esp = val;
- break;
- case MSR_IA32_SYSENTER_EIP:
- env->sysenter_eip = val;
- break;
- case MSR_IA32_APICBASE:
- cpu_set_apic_base(env_archcpu(env)->apic_state, val);
- break;
- case MSR_EFER:
- {
- uint64_t update_mask;
-
- update_mask = 0;
- if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
- update_mask |= MSR_EFER_SCE;
- }
- if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
- update_mask |= MSR_EFER_LME;
- }
- if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
- update_mask |= MSR_EFER_FFXSR;
- }
- if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
- update_mask |= MSR_EFER_NXE;
- }
- if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
- update_mask |= MSR_EFER_SVME;
- }
- if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
- update_mask |= MSR_EFER_FFXSR;
- }
- cpu_load_efer(env, (env->efer & ~update_mask) |
- (val & update_mask));
- }
- break;
- case MSR_STAR:
- env->star = val;
- break;
- case MSR_PAT:
- env->pat = val;
- break;
- case MSR_IA32_PKRS:
- if (val & 0xFFFFFFFF00000000ull) {
- goto error;
- }
- env->pkrs = val;
- tlb_flush(cs);
- break;
- case MSR_VM_HSAVE_PA:
- env->vm_hsave = val;
- break;
-#ifdef TARGET_X86_64
- case MSR_LSTAR:
- env->lstar = val;
- break;
- case MSR_CSTAR:
- env->cstar = val;
- break;
- case MSR_FMASK:
- env->fmask = val;
- break;
- case MSR_FSBASE:
- env->segs[R_FS].base = val;
- break;
- case MSR_GSBASE:
- env->segs[R_GS].base = val;
- break;
- case MSR_KERNELGSBASE:
- env->kernelgsbase = val;
- break;
-#endif
- case MSR_MTRRphysBase(0):
- case MSR_MTRRphysBase(1):
- case MSR_MTRRphysBase(2):
- case MSR_MTRRphysBase(3):
- case MSR_MTRRphysBase(4):
- case MSR_MTRRphysBase(5):
- case MSR_MTRRphysBase(6):
- case MSR_MTRRphysBase(7):
- env->mtrr_var[((uint32_t)env->regs[R_ECX] -
- MSR_MTRRphysBase(0)) / 2].base = val;
- break;
- case MSR_MTRRphysMask(0):
- case MSR_MTRRphysMask(1):
- case MSR_MTRRphysMask(2):
- case MSR_MTRRphysMask(3):
- case MSR_MTRRphysMask(4):
- case MSR_MTRRphysMask(5):
- case MSR_MTRRphysMask(6):
- case MSR_MTRRphysMask(7):
- env->mtrr_var[((uint32_t)env->regs[R_ECX] -
- MSR_MTRRphysMask(0)) / 2].mask = val;
- break;
- case MSR_MTRRfix64K_00000:
- env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
- MSR_MTRRfix64K_00000] = val;
- break;
- case MSR_MTRRfix16K_80000:
- case MSR_MTRRfix16K_A0000:
- env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
- MSR_MTRRfix16K_80000 + 1] = val;
- break;
- case MSR_MTRRfix4K_C0000:
- case MSR_MTRRfix4K_C8000:
- case MSR_MTRRfix4K_D0000:
- case MSR_MTRRfix4K_D8000:
- case MSR_MTRRfix4K_E0000:
- case MSR_MTRRfix4K_E8000:
- case MSR_MTRRfix4K_F0000:
- case MSR_MTRRfix4K_F8000:
- env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
- MSR_MTRRfix4K_C0000 + 3] = val;
- break;
- case MSR_MTRRdefType:
- env->mtrr_deftype = val;
- break;
- case MSR_MCG_STATUS:
- env->mcg_status = val;
- break;
- case MSR_MCG_CTL:
- if ((env->mcg_cap & MCG_CTL_P)
- && (val == 0 || val == ~(uint64_t)0)) {
- env->mcg_ctl = val;
- }
- break;
- case MSR_TSC_AUX:
- env->tsc_aux = val;
- break;
- case MSR_IA32_MISC_ENABLE:
- env->msr_ia32_misc_enable = val;
- break;
- case MSR_IA32_BNDCFGS:
- /* FIXME: #GP if reserved bits are set. */
- /* FIXME: Extend highest implemented bit of linear address. */
- env->msr_bndcfgs = val;
- cpu_sync_bndcs_hflags(env);
- break;
- default:
- if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
- && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
- (4 * env->mcg_cap & 0xff)) {
- uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
- if ((offset & 0x3) != 0
- || (val == 0 || val == ~(uint64_t)0)) {
- env->mce_banks[offset] = val;
- }
- break;
- }
- /* XXX: exception? */
- break;
- }
- return;
-error:
- raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
-}
-
-void helper_rdmsr(CPUX86State *env)
-{
- X86CPU *x86_cpu = env_archcpu(env);
- uint64_t val;
-
- cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
-
- switch ((uint32_t)env->regs[R_ECX]) {
- case MSR_IA32_SYSENTER_CS:
- val = env->sysenter_cs;
- break;
- case MSR_IA32_SYSENTER_ESP:
- val = env->sysenter_esp;
- break;
- case MSR_IA32_SYSENTER_EIP:
- val = env->sysenter_eip;
- break;
- case MSR_IA32_APICBASE:
- val = cpu_get_apic_base(env_archcpu(env)->apic_state);
- break;
- case MSR_EFER:
- val = env->efer;
- break;
- case MSR_STAR:
- val = env->star;
- break;
- case MSR_PAT:
- val = env->pat;
- break;
- case MSR_IA32_PKRS:
- val = env->pkrs;
- break;
- case MSR_VM_HSAVE_PA:
- val = env->vm_hsave;
- break;
- case MSR_IA32_PERF_STATUS:
- /* tsc_increment_by_tick */
- val = 1000ULL;
- /* CPU multiplier */
- val |= (((uint64_t)4ULL) << 40);
- break;
-#ifdef TARGET_X86_64
- case MSR_LSTAR:
- val = env->lstar;
- break;
- case MSR_CSTAR:
- val = env->cstar;
- break;
- case MSR_FMASK:
- val = env->fmask;
- break;
- case MSR_FSBASE:
- val = env->segs[R_FS].base;
- break;
- case MSR_GSBASE:
- val = env->segs[R_GS].base;
- break;
- case MSR_KERNELGSBASE:
- val = env->kernelgsbase;
- break;
- case MSR_TSC_AUX:
- val = env->tsc_aux;
- break;
-#endif
- case MSR_SMI_COUNT:
- val = env->msr_smi_count;
- break;
- case MSR_MTRRphysBase(0):
- case MSR_MTRRphysBase(1):
- case MSR_MTRRphysBase(2):
- case MSR_MTRRphysBase(3):
- case MSR_MTRRphysBase(4):
- case MSR_MTRRphysBase(5):
- case MSR_MTRRphysBase(6):
- case MSR_MTRRphysBase(7):
- val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
- MSR_MTRRphysBase(0)) / 2].base;
- break;
- case MSR_MTRRphysMask(0):
- case MSR_MTRRphysMask(1):
- case MSR_MTRRphysMask(2):
- case MSR_MTRRphysMask(3):
- case MSR_MTRRphysMask(4):
- case MSR_MTRRphysMask(5):
- case MSR_MTRRphysMask(6):
- case MSR_MTRRphysMask(7):
- val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
- MSR_MTRRphysMask(0)) / 2].mask;
- break;
- case MSR_MTRRfix64K_00000:
- val = env->mtrr_fixed[0];
- break;
- case MSR_MTRRfix16K_80000:
- case MSR_MTRRfix16K_A0000:
- val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
- MSR_MTRRfix16K_80000 + 1];
- break;
- case MSR_MTRRfix4K_C0000:
- case MSR_MTRRfix4K_C8000:
- case MSR_MTRRfix4K_D0000:
- case MSR_MTRRfix4K_D8000:
- case MSR_MTRRfix4K_E0000:
- case MSR_MTRRfix4K_E8000:
- case MSR_MTRRfix4K_F0000:
- case MSR_MTRRfix4K_F8000:
- val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
- MSR_MTRRfix4K_C0000 + 3];
- break;
- case MSR_MTRRdefType:
- val = env->mtrr_deftype;
- break;
- case MSR_MTRRcap:
- if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
- val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
- MSR_MTRRcap_WC_SUPPORTED;
- } else {
- /* XXX: exception? */
- val = 0;
- }
- break;
- case MSR_MCG_CAP:
- val = env->mcg_cap;
- break;
- case MSR_MCG_CTL:
- if (env->mcg_cap & MCG_CTL_P) {
- val = env->mcg_ctl;
- } else {
- val = 0;
- }
- break;
- case MSR_MCG_STATUS:
- val = env->mcg_status;
- break;
- case MSR_IA32_MISC_ENABLE:
- val = env->msr_ia32_misc_enable;
- break;
- case MSR_IA32_BNDCFGS:
- val = env->msr_bndcfgs;
- break;
- case MSR_IA32_UCODE_REV:
- val = x86_cpu->ucode_rev;
- break;
- default:
- if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
- && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
- (4 * env->mcg_cap & 0xff)) {
- uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
- val = env->mce_banks[offset];
- break;
- }
- /* XXX: exception? */
- val = 0;
- break;
- }
- env->regs[R_EAX] = (uint32_t)(val);
- env->regs[R_EDX] = (uint32_t)(val >> 32);
-}
-#endif
-
-static void do_pause(X86CPU *cpu)
-{
- CPUState *cs = CPU(cpu);
-
/* Just let another CPU run. */
cs->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(cs);
}
-static void do_hlt(X86CPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- CPUX86State *env = &cpu->env;
-
- env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
- cpu_loop_exit(cs);
-}
-
-void helper_hlt(CPUX86State *env, int next_eip_addend)
+void QEMU_NORETURN helper_pause(CPUX86State *env, int next_eip_addend)
{
- X86CPU *cpu = env_archcpu(env);
-
- cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
- env->eip += next_eip_addend;
-
- do_hlt(cpu);
-}
-
-void helper_monitor(CPUX86State *env, target_ulong ptr)
-{
- if ((uint32_t)env->regs[R_ECX] != 0) {
- raise_exception_ra(env, EXCP0D_GPF, GETPC());
- }
- /* XXX: store address? */
- cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
-}
-
-void helper_mwait(CPUX86State *env, int next_eip_addend)
-{
- CPUState *cs = env_cpu(env);
- X86CPU *cpu = env_archcpu(env);
-
- if ((uint32_t)env->regs[R_ECX] != 0) {
- raise_exception_ra(env, EXCP0D_GPF, GETPC());
- }
- cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
- env->eip += next_eip_addend;
-
- /* XXX: not complete but not completely erroneous */
- if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
- do_pause(cpu);
- } else {
- do_hlt(cpu);
- }
-}
-
-void helper_pause(CPUX86State *env, int next_eip_addend)
-{
- X86CPU *cpu = env_archcpu(env);
-
cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
env->eip += next_eip_addend;
- do_pause(cpu);
+ do_pause(env);
}
-void helper_debug(CPUX86State *env)
+void QEMU_NORETURN helper_debug(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index d180a381d1..2f6cdc8239 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -26,49 +26,7 @@
#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "helper-tcg.h"
-
-//#define DEBUG_PCALL
-
-#ifdef DEBUG_PCALL
-# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
-# define LOG_PCALL_STATE(cpu) \
- log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP)
-#else
-# define LOG_PCALL(...) do { } while (0)
-# define LOG_PCALL_STATE(cpu) do { } while (0)
-#endif
-
-/*
- * TODO: Convert callers to compute cpu_mmu_index_kernel once
- * and use *_mmuidx_ra directly.
- */
-#define cpu_ldub_kernel_ra(e, p, r) \
- cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
-#define cpu_lduw_kernel_ra(e, p, r) \
- cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
-#define cpu_ldl_kernel_ra(e, p, r) \
- cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
-#define cpu_ldq_kernel_ra(e, p, r) \
- cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
-
-#define cpu_stb_kernel_ra(e, p, v, r) \
- cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
-#define cpu_stw_kernel_ra(e, p, v, r) \
- cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
-#define cpu_stl_kernel_ra(e, p, v, r) \
- cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
-#define cpu_stq_kernel_ra(e, p, v, r) \
- cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
-
-#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0)
-#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0)
-#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0)
-#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0)
-
-#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0)
-#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0)
-#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0)
-#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0)
+#include "seg_helper.h"
/* return non zero if error */
static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr,
@@ -531,7 +489,7 @@ static inline unsigned int get_sp_mask(unsigned int e2)
}
}
-static int exception_has_error_code(int intno)
+int exception_has_error_code(int intno)
{
switch (intno) {
case 8:
@@ -977,72 +935,6 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
#endif
#ifdef TARGET_X86_64
-#if defined(CONFIG_USER_ONLY)
-void helper_syscall(CPUX86State *env, int next_eip_addend)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = EXCP_SYSCALL;
- env->exception_is_int = 0;
- env->exception_next_eip = env->eip + next_eip_addend;
- cpu_loop_exit(cs);
-}
-#else
-void helper_syscall(CPUX86State *env, int next_eip_addend)
-{
- int selector;
-
- if (!(env->efer & MSR_EFER_SCE)) {
- raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
- }
- selector = (env->star >> 32) & 0xffff;
- if (env->hflags & HF_LMA_MASK) {
- int code64;
-
- env->regs[R_ECX] = env->eip + next_eip_addend;
- env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK;
-
- code64 = env->hflags & HF_CS64_MASK;
-
- env->eflags &= ~(env->fmask | RF_MASK);
- cpu_load_eflags(env, env->eflags, 0);
- cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
- DESC_L_MASK);
- cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- if (code64) {
- env->eip = env->lstar;
- } else {
- env->eip = env->cstar;
- }
- } else {
- env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend);
-
- env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
- cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- env->eip = (uint32_t)env->star;
- }
-}
-#endif
-#endif
-
-#ifdef TARGET_X86_64
void helper_sysret(CPUX86State *env, int dflag)
{
int cpl, selector;
@@ -1136,84 +1028,13 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int,
env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
}
-#if defined(CONFIG_USER_ONLY)
-/* fake user mode interrupt. is_int is TRUE if coming from the int
- * instruction. next_eip is the env->eip value AFTER the interrupt
- * instruction. It is only relevant if is_int is TRUE or if intno
- * is EXCP_SYSCALL.
- */
-static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
- int error_code, target_ulong next_eip)
-{
- if (is_int) {
- SegmentCache *dt;
- target_ulong ptr;
- int dpl, cpl, shift;
- uint32_t e2;
-
- dt = &env->idt;
- if (env->hflags & HF_LMA_MASK) {
- shift = 4;
- } else {
- shift = 3;
- }
- ptr = dt->base + (intno << shift);
- e2 = cpu_ldl_kernel(env, ptr + 4);
-
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- /* check privilege if software int */
- if (dpl < cpl) {
- raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2);
- }
- }
-
- /* Since we emulate only user space, we cannot do more than
- exiting the emulation with the suitable exception and error
- code. So update EIP for INT 0x80 and EXCP_SYSCALL. */
- if (is_int || intno == EXCP_SYSCALL) {
- env->eip = next_eip;
- }
-}
-
-#else
-
-static void handle_even_inj(CPUX86State *env, int intno, int is_int,
- int error_code, int is_hw, int rm)
-{
- CPUState *cs = env_cpu(env);
- uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
- control.event_inj));
-
- if (!(event_inj & SVM_EVTINJ_VALID)) {
- int type;
-
- if (is_int) {
- type = SVM_EVTINJ_TYPE_SOFT;
- } else {
- type = SVM_EVTINJ_TYPE_EXEPT;
- }
- event_inj = intno | type | SVM_EVTINJ_VALID;
- if (!rm && exception_has_error_code(intno)) {
- event_inj |= SVM_EVTINJ_VALID_ERR;
- x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
- control.event_inj_err),
- error_code);
- }
- x86_stl_phys(cs,
- env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
- event_inj);
- }
-}
-#endif
-
/*
* Begin execution of an interruption. is_int is TRUE if coming from
* the int instruction. next_eip is the env->eip value AFTER the interrupt
* instruction. It is only relevant if is_int is TRUE.
*/
-static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
- int error_code, target_ulong next_eip, int is_hw)
+void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
+ int error_code, target_ulong next_eip, int is_hw)
{
CPUX86State *env = &cpu->env;
@@ -1289,36 +1110,6 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int,
#endif
}
-void x86_cpu_do_interrupt(CPUState *cs)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
-
-#if defined(CONFIG_USER_ONLY)
- /* if user mode only, we simulate a fake exception
- which will be handled outside the cpu execution
- loop */
- do_interrupt_user(env, cs->exception_index,
- env->exception_is_int,
- env->error_code,
- env->exception_next_eip);
- /* successfully delivered */
- env->old_exception = -1;
-#else
- if (cs->exception_index == EXCP_VMEXIT) {
- assert(env->old_exception == -1);
- do_vmexit(env);
- } else {
- do_interrupt_all(cpu, cs->exception_index,
- env->exception_is_int,
- env->error_code,
- env->exception_next_eip, 0);
- /* successfully delivered */
- env->old_exception = -1;
- }
-#endif
-}
-
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw)
{
do_interrupt_all(env_archcpu(env), intno, 0, 0, 0, is_hw);
@@ -1351,7 +1142,11 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
case CPU_INTERRUPT_SMI:
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0);
cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
+#ifdef CONFIG_USER_ONLY
+ cpu_abort(CPU(cpu), "SMI interrupt: cannot enter SMM in user-mode");
+#else
do_smm_enter(cpu);
+#endif /* CONFIG_USER_ONLY */
break;
case CPU_INTERRUPT_NMI:
cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0);
@@ -2621,62 +2416,3 @@ void helper_verw(CPUX86State *env, target_ulong selector1)
}
CC_SRC = eflags | CC_Z;
}
-
-#if defined(CONFIG_USER_ONLY)
-void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector)
-{
- if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
- int dpl = (env->eflags & VM_MASK) ? 3 : 0;
- selector &= 0xffff;
- cpu_x86_load_seg_cache(env, seg_reg, selector,
- (selector << 4), 0xffff,
- DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
- DESC_A_MASK | (dpl << DESC_DPL_SHIFT));
- } else {
- helper_load_seg(env, seg_reg, selector);
- }
-}
-#endif
-
-/* check if Port I/O is allowed in TSS */
-static inline void check_io(CPUX86State *env, int addr, int size,
- uintptr_t retaddr)
-{
- int io_offset, val, mask;
-
- /* TSS must be a valid 32 bit one */
- if (!(env->tr.flags & DESC_P_MASK) ||
- ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
- env->tr.limit < 103) {
- goto fail;
- }
- io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
- io_offset += (addr >> 3);
- /* Note: the check needs two bytes */
- if ((io_offset + 1) > env->tr.limit) {
- goto fail;
- }
- val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
- val >>= (addr & 7);
- mask = (1 << size) - 1;
- /* all bits must be zero to allow the I/O */
- if ((val & mask) != 0) {
- fail:
- raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
- }
-}
-
-void helper_check_iob(CPUX86State *env, uint32_t t0)
-{
- check_io(env, t0, 1, GETPC());
-}
-
-void helper_check_iow(CPUX86State *env, uint32_t t0)
-{
- check_io(env, t0, 2, GETPC());
-}
-
-void helper_check_iol(CPUX86State *env, uint32_t t0)
-{
- check_io(env, t0, 4, GETPC());
-}
diff --git a/target/i386/tcg/seg_helper.h b/target/i386/tcg/seg_helper.h
new file mode 100644
index 0000000000..ebf1035277
--- /dev/null
+++ b/target/i386/tcg/seg_helper.h
@@ -0,0 +1,66 @@
+/*
+ * x86 segmentation related helpers macros
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SEG_HELPER_H
+#define SEG_HELPER_H
+
+//#define DEBUG_PCALL
+
+#ifdef DEBUG_PCALL
+# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
+# define LOG_PCALL_STATE(cpu) \
+ log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP)
+#else
+# define LOG_PCALL(...) do { } while (0)
+# define LOG_PCALL_STATE(cpu) do { } while (0)
+#endif
+
+/*
+ * TODO: Convert callers to compute cpu_mmu_index_kernel once
+ * and use *_mmuidx_ra directly.
+ */
+#define cpu_ldub_kernel_ra(e, p, r) \
+ cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
+#define cpu_lduw_kernel_ra(e, p, r) \
+ cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
+#define cpu_ldl_kernel_ra(e, p, r) \
+ cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
+#define cpu_ldq_kernel_ra(e, p, r) \
+ cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r)
+
+#define cpu_stb_kernel_ra(e, p, v, r) \
+ cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
+#define cpu_stw_kernel_ra(e, p, v, r) \
+ cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
+#define cpu_stl_kernel_ra(e, p, v, r) \
+ cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
+#define cpu_stq_kernel_ra(e, p, v, r) \
+ cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r)
+
+#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0)
+#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0)
+#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0)
+#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0)
+
+#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0)
+#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0)
+#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0)
+#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0)
+
+#endif /* SEG_HELPER_H */
diff --git a/target/i386/tcg/sysemu/bpt_helper.c b/target/i386/tcg/sysemu/bpt_helper.c
new file mode 100644
index 0000000000..9bdf7e170b
--- /dev/null
+++ b/target/i386/tcg/sysemu/bpt_helper.c
@@ -0,0 +1,293 @@
+/*
+ * i386 breakpoint helpers - sysemu code
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "exec/exec-all.h"
+#include "exec/helper-proto.h"
+#include "tcg/helper-tcg.h"
+
+
+static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index)
+{
+ return (dr7 >> (index * 2)) & 1;
+}
+
+static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index)
+{
+ return (dr7 >> (index * 2)) & 2;
+
+}
+static inline bool hw_breakpoint_enabled(unsigned long dr7, int index)
+{
+ return hw_global_breakpoint_enabled(dr7, index) ||
+ hw_local_breakpoint_enabled(dr7, index);
+}
+
+static inline int hw_breakpoint_type(unsigned long dr7, int index)
+{
+ return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3;
+}
+
+static inline int hw_breakpoint_len(unsigned long dr7, int index)
+{
+ int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3);
+ return (len == 2) ? 8 : len + 1;
+}
+
+static int hw_breakpoint_insert(CPUX86State *env, int index)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong dr7 = env->dr[7];
+ target_ulong drN = env->dr[index];
+ int err = 0;
+
+ switch (hw_breakpoint_type(dr7, index)) {
+ case DR7_TYPE_BP_INST:
+ if (hw_breakpoint_enabled(dr7, index)) {
+ err = cpu_breakpoint_insert(cs, drN, BP_CPU,
+ &env->cpu_breakpoint[index]);
+ }
+ break;
+
+ case DR7_TYPE_IO_RW:
+ /* Notice when we should enable calls to bpt_io. */
+ return hw_breakpoint_enabled(env->dr[7], index)
+ ? HF_IOBPT_MASK : 0;
+
+ case DR7_TYPE_DATA_WR:
+ if (hw_breakpoint_enabled(dr7, index)) {
+ err = cpu_watchpoint_insert(cs, drN,
+ hw_breakpoint_len(dr7, index),
+ BP_CPU | BP_MEM_WRITE,
+ &env->cpu_watchpoint[index]);
+ }
+ break;
+
+ case DR7_TYPE_DATA_RW:
+ if (hw_breakpoint_enabled(dr7, index)) {
+ err = cpu_watchpoint_insert(cs, drN,
+ hw_breakpoint_len(dr7, index),
+ BP_CPU | BP_MEM_ACCESS,
+ &env->cpu_watchpoint[index]);
+ }
+ break;
+ }
+ if (err) {
+ env->cpu_breakpoint[index] = NULL;
+ }
+ return 0;
+}
+
+static void hw_breakpoint_remove(CPUX86State *env, int index)
+{
+ CPUState *cs = env_cpu(env);
+
+ switch (hw_breakpoint_type(env->dr[7], index)) {
+ case DR7_TYPE_BP_INST:
+ if (env->cpu_breakpoint[index]) {
+ cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
+ env->cpu_breakpoint[index] = NULL;
+ }
+ break;
+
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
+ if (env->cpu_breakpoint[index]) {
+ cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
+ env->cpu_breakpoint[index] = NULL;
+ }
+ break;
+
+ case DR7_TYPE_IO_RW:
+ /* HF_IOBPT_MASK cleared elsewhere. */
+ break;
+ }
+}
+
+void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7)
+{
+ target_ulong old_dr7 = env->dr[7];
+ int iobpt = 0;
+ int i;
+
+ new_dr7 |= DR7_FIXED_1;
+
+ /* If nothing is changing except the global/local enable bits,
+ then we can make the change more efficient. */
+ if (((old_dr7 ^ new_dr7) & ~0xff) == 0) {
+ /* Fold the global and local enable bits together into the
+ global fields, then xor to show which registers have
+ changed collective enable state. */
+ int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff;
+
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) {
+ hw_breakpoint_remove(env, i);
+ }
+ }
+ env->dr[7] = new_dr7;
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) {
+ iobpt |= hw_breakpoint_insert(env, i);
+ } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW
+ && hw_breakpoint_enabled(new_dr7, i)) {
+ iobpt |= HF_IOBPT_MASK;
+ }
+ }
+ } else {
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ hw_breakpoint_remove(env, i);
+ }
+ env->dr[7] = new_dr7;
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ iobpt |= hw_breakpoint_insert(env, i);
+ }
+ }
+
+ env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt;
+}
+
+bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
+{
+ target_ulong dr6;
+ int reg;
+ bool hit_enabled = false;
+
+ dr6 = env->dr[6] & ~0xf;
+ for (reg = 0; reg < DR7_MAX_BP; reg++) {
+ bool bp_match = false;
+ bool wp_match = false;
+
+ switch (hw_breakpoint_type(env->dr[7], reg)) {
+ case DR7_TYPE_BP_INST:
+ if (env->dr[reg] == env->eip) {
+ bp_match = true;
+ }
+ break;
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
+ if (env->cpu_watchpoint[reg] &&
+ env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
+ wp_match = true;
+ }
+ break;
+ case DR7_TYPE_IO_RW:
+ break;
+ }
+ if (bp_match || wp_match) {
+ dr6 |= 1 << reg;
+ if (hw_breakpoint_enabled(env->dr[7], reg)) {
+ hit_enabled = true;
+ }
+ }
+ }
+
+ if (hit_enabled || force_dr6_update) {
+ env->dr[6] = dr6;
+ }
+
+ return hit_enabled;
+}
+
+void breakpoint_handler(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ CPUBreakpoint *bp;
+
+ if (cs->watchpoint_hit) {
+ if (cs->watchpoint_hit->flags & BP_CPU) {
+ cs->watchpoint_hit = NULL;
+ if (check_hw_breakpoints(env, false)) {
+ raise_exception(env, EXCP01_DB);
+ } else {
+ cpu_loop_exit_noexc(cs);
+ }
+ }
+ } else {
+ QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+ if (bp->pc == env->eip) {
+ if (bp->flags & BP_CPU) {
+ check_hw_breakpoints(env, true);
+ raise_exception(env, EXCP01_DB);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void helper_set_dr(CPUX86State *env, int reg, target_ulong t0)
+{
+ switch (reg) {
+ case 0: case 1: case 2: case 3:
+ if (hw_breakpoint_enabled(env->dr[7], reg)
+ && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) {
+ hw_breakpoint_remove(env, reg);
+ env->dr[reg] = t0;
+ hw_breakpoint_insert(env, reg);
+ } else {
+ env->dr[reg] = t0;
+ }
+ return;
+ case 4:
+ if (env->cr[4] & CR4_DE_MASK) {
+ break;
+ }
+ /* fallthru */
+ case 6:
+ env->dr[6] = t0 | DR6_FIXED_1;
+ return;
+ case 5:
+ if (env->cr[4] & CR4_DE_MASK) {
+ break;
+ }
+ /* fallthru */
+ case 7:
+ cpu_x86_update_dr7(env, t0);
+ return;
+ }
+ raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
+}
+
+/* Check if Port I/O is trapped by a breakpoint. */
+void helper_bpt_io(CPUX86State *env, uint32_t port,
+ uint32_t size, target_ulong next_eip)
+{
+ target_ulong dr7 = env->dr[7];
+ int i, hit = 0;
+
+ for (i = 0; i < DR7_MAX_BP; ++i) {
+ if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW
+ && hw_breakpoint_enabled(dr7, i)) {
+ int bpt_len = hw_breakpoint_len(dr7, i);
+ if (port + size - 1 >= env->dr[i]
+ && port <= env->dr[i] + bpt_len - 1) {
+ hit |= 1 << i;
+ }
+ }
+ }
+
+ if (hit) {
+ env->dr[6] = (env->dr[6] & ~0xf) | hit;
+ env->eip = next_eip;
+ raise_exception(env, EXCP01_DB);
+ }
+}
diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
new file mode 100644
index 0000000000..b6d940e04e
--- /dev/null
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -0,0 +1,471 @@
+/*
+ * x86 exception helpers - sysemu code
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "tcg/helper-tcg.h"
+
+int get_pg_mode(CPUX86State *env)
+{
+ int pg_mode = 0;
+ if (env->cr[0] & CR0_WP_MASK) {
+ pg_mode |= PG_MODE_WP;
+ }
+ if (env->cr[4] & CR4_PAE_MASK) {
+ pg_mode |= PG_MODE_PAE;
+ }
+ if (env->cr[4] & CR4_PSE_MASK) {
+ pg_mode |= PG_MODE_PSE;
+ }
+ if (env->cr[4] & CR4_PKE_MASK) {
+ pg_mode |= PG_MODE_PKE;
+ }
+ if (env->cr[4] & CR4_PKS_MASK) {
+ pg_mode |= PG_MODE_PKS;
+ }
+ if (env->cr[4] & CR4_SMEP_MASK) {
+ pg_mode |= PG_MODE_SMEP;
+ }
+ if (env->cr[4] & CR4_LA57_MASK) {
+ pg_mode |= PG_MODE_LA57;
+ }
+ if (env->hflags & HF_LMA_MASK) {
+ pg_mode |= PG_MODE_LMA;
+ }
+ if (env->efer & MSR_EFER_NXE) {
+ pg_mode |= PG_MODE_NXE;
+ }
+ return pg_mode;
+}
+
+#define PG_ERROR_OK (-1)
+
+typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
+ int *prot);
+
+#define GET_HPHYS(cs, gpa, access_type, prot) \
+ (get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa)
+
+static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func,
+ uint64_t cr3, int is_write1, int mmu_idx, int pg_mode,
+ hwaddr *xlat, int *page_size, int *prot)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ uint64_t ptep, pte;
+ int32_t a20_mask;
+ target_ulong pde_addr, pte_addr;
+ int error_code = 0;
+ int is_dirty, is_write, is_user;
+ uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
+ uint32_t page_offset;
+ uint32_t pkr;
+
+ is_user = (mmu_idx == MMU_USER_IDX);
+ is_write = is_write1 & 1;
+ a20_mask = x86_get_a20_mask(env);
+
+ if (!(pg_mode & PG_MODE_NXE)) {
+ rsvd_mask |= PG_NX_MASK;
+ }
+
+ if (pg_mode & PG_MODE_PAE) {
+ uint64_t pde, pdpe;
+ target_ulong pdpe_addr;
+
+#ifdef TARGET_X86_64
+ if (env->hflags & HF_LMA_MASK) {
+ bool la57 = pg_mode & PG_MODE_LA57;
+ uint64_t pml5e_addr, pml5e;
+ uint64_t pml4e_addr, pml4e;
+ int32_t sext;
+
+ /* test virtual address sign extension */
+ sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47;
+ if (get_hphys_func && sext != 0 && sext != -1) {
+ env->error_code = 0;
+ cs->exception_index = EXCP0D_GPF;
+ return 1;
+ }
+
+ if (la57) {
+ pml5e_addr = ((cr3 & ~0xfff) +
+ (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
+ pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL);
+ pml5e = x86_ldq_phys(cs, pml5e_addr);
+ if (!(pml5e & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ if (pml5e & (rsvd_mask | PG_PSE_MASK)) {
+ goto do_fault_rsvd;
+ }
+ if (!(pml5e & PG_ACCESSED_MASK)) {
+ pml5e |= PG_ACCESSED_MASK;
+ x86_stl_phys_notdirty(cs, pml5e_addr, pml5e);
+ }
+ ptep = pml5e ^ PG_NX_MASK;
+ } else {
+ pml5e = cr3;
+ ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
+ }
+
+ pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
+ (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
+ pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL);
+ pml4e = x86_ldq_phys(cs, pml4e_addr);
+ if (!(pml4e & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ if (pml4e & (rsvd_mask | PG_PSE_MASK)) {
+ goto do_fault_rsvd;
+ }
+ if (!(pml4e & PG_ACCESSED_MASK)) {
+ pml4e |= PG_ACCESSED_MASK;
+ x86_stl_phys_notdirty(cs, pml4e_addr, pml4e);
+ }
+ ptep &= pml4e ^ PG_NX_MASK;
+ pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
+ a20_mask;
+ pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL);
+ pdpe = x86_ldq_phys(cs, pdpe_addr);
+ if (!(pdpe & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ if (pdpe & rsvd_mask) {
+ goto do_fault_rsvd;
+ }
+ ptep &= pdpe ^ PG_NX_MASK;
+ if (!(pdpe & PG_ACCESSED_MASK)) {
+ pdpe |= PG_ACCESSED_MASK;
+ x86_stl_phys_notdirty(cs, pdpe_addr, pdpe);
+ }
+ if (pdpe & PG_PSE_MASK) {
+ /* 1 GB page */
+ *page_size = 1024 * 1024 * 1024;
+ pte_addr = pdpe_addr;
+ pte = pdpe;
+ goto do_check_protect;
+ }
+ } else
+#endif
+ {
+ /* XXX: load them when cr3 is loaded ? */
+ pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) &
+ a20_mask;
+ pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL);
+ pdpe = x86_ldq_phys(cs, pdpe_addr);
+ if (!(pdpe & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ rsvd_mask |= PG_HI_USER_MASK;
+ if (pdpe & (rsvd_mask | PG_NX_MASK)) {
+ goto do_fault_rsvd;
+ }
+ ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
+ }
+
+ pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
+ a20_mask;
+ pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL);
+ pde = x86_ldq_phys(cs, pde_addr);
+ if (!(pde & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ if (pde & rsvd_mask) {
+ goto do_fault_rsvd;
+ }
+ ptep &= pde ^ PG_NX_MASK;
+ if (pde & PG_PSE_MASK) {
+ /* 2 MB page */
+ *page_size = 2048 * 1024;
+ pte_addr = pde_addr;
+ pte = pde;
+ goto do_check_protect;
+ }
+ /* 4 KB page */
+ if (!(pde & PG_ACCESSED_MASK)) {
+ pde |= PG_ACCESSED_MASK;
+ x86_stl_phys_notdirty(cs, pde_addr, pde);
+ }
+ pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
+ a20_mask;
+ pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL);
+ pte = x86_ldq_phys(cs, pte_addr);
+ if (!(pte & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ if (pte & rsvd_mask) {
+ goto do_fault_rsvd;
+ }
+ /* combine pde and pte nx, user and rw protections */
+ ptep &= pte ^ PG_NX_MASK;
+ *page_size = 4096;
+ } else {
+ uint32_t pde;
+
+ /* page directory entry */
+ pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) &
+ a20_mask;
+ pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL);
+ pde = x86_ldl_phys(cs, pde_addr);
+ if (!(pde & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ ptep = pde | PG_NX_MASK;
+
+ /* if PSE bit is set, then we use a 4MB page */
+ if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) {
+ *page_size = 4096 * 1024;
+ pte_addr = pde_addr;
+
+ /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
+ * Leave bits 20-13 in place for setting accessed/dirty bits below.
+ */
+ pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
+ rsvd_mask = 0x200000;
+ goto do_check_protect_pse36;
+ }
+
+ if (!(pde & PG_ACCESSED_MASK)) {
+ pde |= PG_ACCESSED_MASK;
+ x86_stl_phys_notdirty(cs, pde_addr, pde);
+ }
+
+ /* page directory entry */
+ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
+ a20_mask;
+ pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL);
+ pte = x86_ldl_phys(cs, pte_addr);
+ if (!(pte & PG_PRESENT_MASK)) {
+ goto do_fault;
+ }
+ /* combine pde and pte user and rw protections */
+ ptep &= pte | PG_NX_MASK;
+ *page_size = 4096;
+ rsvd_mask = 0;
+ }
+
+do_check_protect:
+ rsvd_mask |= (*page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK;
+do_check_protect_pse36:
+ if (pte & rsvd_mask) {
+ goto do_fault_rsvd;
+ }
+ ptep ^= PG_NX_MASK;
+
+ /* can the page can be put in the TLB? prot will tell us */
+ if (is_user && !(ptep & PG_USER_MASK)) {
+ goto do_fault_protect;
+ }
+
+ *prot = 0;
+ if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
+ *prot |= PAGE_READ;
+ if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
+ *prot |= PAGE_WRITE;
+ }
+ }
+ if (!(ptep & PG_NX_MASK) &&
+ (mmu_idx == MMU_USER_IDX ||
+ !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) {
+ *prot |= PAGE_EXEC;
+ }
+
+ if (!(env->hflags & HF_LMA_MASK)) {
+ pkr = 0;
+ } else if (ptep & PG_USER_MASK) {
+ pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0;
+ } else {
+ pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0;
+ }
+ if (pkr) {
+ uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT;
+ uint32_t pkr_ad = (pkr >> pk * 2) & 1;
+ uint32_t pkr_wd = (pkr >> pk * 2) & 2;
+ uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+
+ if (pkr_ad) {
+ pkr_prot &= ~(PAGE_READ | PAGE_WRITE);
+ } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) {
+ pkr_prot &= ~PAGE_WRITE;
+ }
+
+ *prot &= pkr_prot;
+ if ((pkr_prot & (1 << is_write1)) == 0) {
+ assert(is_write1 != 2);
+ error_code |= PG_ERROR_PK_MASK;
+ goto do_fault_protect;
+ }
+ }
+
+ if ((*prot & (1 << is_write1)) == 0) {
+ goto do_fault_protect;
+ }
+
+ /* yes, it can! */
+ is_dirty = is_write && !(pte & PG_DIRTY_MASK);
+ if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
+ pte |= PG_ACCESSED_MASK;
+ if (is_dirty) {
+ pte |= PG_DIRTY_MASK;
+ }
+ x86_stl_phys_notdirty(cs, pte_addr, pte);
+ }
+
+ if (!(pte & PG_DIRTY_MASK)) {
+ /* only set write access if already dirty... otherwise wait
+ for dirty access */
+ assert(!is_write);
+ *prot &= ~PAGE_WRITE;
+ }
+
+ pte = pte & a20_mask;
+
+ /* align to page_size */
+ pte &= PG_ADDRESS_MASK & ~(*page_size - 1);
+ page_offset = addr & (*page_size - 1);
+ *xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot);
+ return PG_ERROR_OK;
+
+ do_fault_rsvd:
+ error_code |= PG_ERROR_RSVD_MASK;
+ do_fault_protect:
+ error_code |= PG_ERROR_P_MASK;
+ do_fault:
+ error_code |= (is_write << PG_ERROR_W_BIT);
+ if (is_user)
+ error_code |= PG_ERROR_U_MASK;
+ if (is_write1 == 2 &&
+ (((pg_mode & PG_MODE_NXE) && (pg_mode & PG_MODE_PAE)) ||
+ (pg_mode & PG_MODE_SMEP)))
+ error_code |= PG_ERROR_I_D_MASK;
+ return error_code;
+}
+
+static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
+ int *prot)
+{
+ CPUX86State *env = &X86_CPU(cs)->env;
+ uint64_t exit_info_1;
+ int page_size;
+ int next_prot;
+ hwaddr hphys;
+
+ if (likely(!(env->hflags2 & HF2_NPT_MASK))) {
+ return gphys;
+ }
+
+ exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3,
+ access_type, MMU_USER_IDX, env->nested_pg_mode,
+ &hphys, &page_size, &next_prot);
+ if (exit_info_1 == PG_ERROR_OK) {
+ if (prot) {
+ *prot &= next_prot;
+ }
+ return hphys;
+ }
+
+ x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
+ gphys);
+ if (prot) {
+ exit_info_1 |= SVM_NPTEXIT_GPA;
+ } else { /* page table access */
+ exit_info_1 |= SVM_NPTEXIT_GPT;
+ }
+ cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr);
+}
+
+/* return value:
+ * -1 = cannot handle fault
+ * 0 = nothing more to do
+ * 1 = generate PF fault
+ */
+static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
+ int is_write1, int mmu_idx)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ int error_code = PG_ERROR_OK;
+ int pg_mode, prot, page_size;
+ hwaddr paddr;
+ hwaddr vaddr;
+
+#if defined(DEBUG_MMU)
+ printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n",
+ addr, is_write1, mmu_idx, env->eip);
+#endif
+
+ if (!(env->cr[0] & CR0_PG_MASK)) {
+ paddr = addr;
+#ifdef TARGET_X86_64
+ if (!(env->hflags & HF_LMA_MASK)) {
+ /* Without long mode we can only address 32bits in real mode */
+ paddr = (uint32_t)paddr;
+ }
+#endif
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ page_size = 4096;
+ } else {
+ pg_mode = get_pg_mode(env);
+ error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1,
+ mmu_idx, pg_mode,
+ &paddr, &page_size, &prot);
+ }
+
+ if (error_code == PG_ERROR_OK) {
+ /* Even if 4MB pages, we map only one 4KB page in the cache to
+ avoid filling it too fast */
+ vaddr = addr & TARGET_PAGE_MASK;
+ paddr &= TARGET_PAGE_MASK;
+
+ assert(prot & (1 << is_write1));
+ tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
+ prot, mmu_idx, page_size);
+ return 0;
+ } else {
+ if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
+ /* cr2 is not modified in case of exceptions */
+ x86_stq_phys(cs,
+ env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
+ addr);
+ } else {
+ env->cr[2] = addr;
+ }
+ env->error_code = error_code;
+ cs->exception_index = EXCP0E_PAGE;
+ return 1;
+ }
+}
+
+bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ env->retaddr = retaddr;
+ if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) {
+ /* FIXME: On error in get_hphys we have already jumped out. */
+ g_assert(!probe);
+ raise_exception_err_ra(env, cs->exception_index,
+ env->error_code, retaddr);
+ }
+ return true;
+}
diff --git a/target/i386/tcg/sysemu/fpu_helper.c b/target/i386/tcg/sysemu/fpu_helper.c
new file mode 100644
index 0000000000..1c3610da3b
--- /dev/null
+++ b/target/i386/tcg/sysemu/fpu_helper.c
@@ -0,0 +1,57 @@
+/*
+ * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers (sysemu code)
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "hw/irq.h"
+
+static qemu_irq ferr_irq;
+
+void x86_register_ferr_irq(qemu_irq irq)
+{
+ ferr_irq = irq;
+}
+
+void fpu_check_raise_ferr_irq(CPUX86State *env)
+{
+ if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) {
+ qemu_irq_raise(ferr_irq);
+ return;
+ }
+}
+
+void cpu_clear_ignne(void)
+{
+ CPUX86State *env = &X86_CPU(first_cpu)->env;
+ env->hflags2 &= ~HF2_IGNNE_MASK;
+}
+
+void cpu_set_ignne(void)
+{
+ CPUX86State *env = &X86_CPU(first_cpu)->env;
+ env->hflags2 |= HF2_IGNNE_MASK;
+ /*
+ * We get here in response to a write to port F0h. The chipset should
+ * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is
+ * cleared, because FERR# and FP_IRQ are two separate pins on real
+ * hardware. However, we don't model FERR# as a qemu_irq, so we just
+ * do directly what the chipset would do, i.e. deassert FP_IRQ.
+ */
+ qemu_irq_lower(ferr_irq);
+}
diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build
new file mode 100644
index 0000000000..2e444e766a
--- /dev/null
+++ b/target/i386/tcg/sysemu/meson.build
@@ -0,0 +1,10 @@
+i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files(
+ 'tcg-cpu.c',
+ 'smm_helper.c',
+ 'excp_helper.c',
+ 'bpt_helper.c',
+ 'misc_helper.c',
+ 'fpu_helper.c',
+ 'svm_helper.c',
+ 'seg_helper.c',
+))
diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c
new file mode 100644
index 0000000000..0cef2f1a4c
--- /dev/null
+++ b/target/i386/tcg/sysemu/misc_helper.c
@@ -0,0 +1,490 @@
+/*
+ * x86 misc helpers - sysemu code
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "qemu/main-loop.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+#include "exec/address-spaces.h"
+#include "tcg/helper-tcg.h"
+
+void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
+{
+ address_space_stb(&address_space_io, port, data,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+target_ulong helper_inb(CPUX86State *env, uint32_t port)
+{
+ return address_space_ldub(&address_space_io, port,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
+{
+ address_space_stw(&address_space_io, port, data,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+target_ulong helper_inw(CPUX86State *env, uint32_t port)
+{
+ return address_space_lduw(&address_space_io, port,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
+{
+ address_space_stl(&address_space_io, port, data,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+target_ulong helper_inl(CPUX86State *env, uint32_t port)
+{
+ return address_space_ldl(&address_space_io, port,
+ cpu_get_mem_attrs(env), NULL);
+}
+
+target_ulong helper_read_crN(CPUX86State *env, int reg)
+{
+ target_ulong val;
+
+ switch (reg) {
+ default:
+ val = env->cr[reg];
+ break;
+ case 8:
+ if (!(env->hflags2 & HF2_VINTR_MASK)) {
+ val = cpu_get_apic_tpr(env_archcpu(env)->apic_state);
+ } else {
+ val = env->v_tpr;
+ }
+ break;
+ }
+ return val;
+}
+
+void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
+{
+ switch (reg) {
+ case 0:
+ cpu_x86_update_cr0(env, t0);
+ break;
+ case 3:
+ cpu_x86_update_cr3(env, t0);
+ break;
+ case 4:
+ if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) &&
+ (env->hflags & HF_CS64_MASK)) {
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
+ }
+ cpu_x86_update_cr4(env, t0);
+ break;
+ case 8:
+ if (!(env->hflags2 & HF2_VINTR_MASK)) {
+ qemu_mutex_lock_iothread();
+ cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0);
+ qemu_mutex_unlock_iothread();
+ }
+ env->v_tpr = t0 & 0x0f;
+ break;
+ default:
+ env->cr[reg] = t0;
+ break;
+ }
+}
+
+void helper_wrmsr(CPUX86State *env)
+{
+ uint64_t val;
+ CPUState *cs = env_cpu(env);
+
+ cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
+
+ val = ((uint32_t)env->regs[R_EAX]) |
+ ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
+
+ switch ((uint32_t)env->regs[R_ECX]) {
+ case MSR_IA32_SYSENTER_CS:
+ env->sysenter_cs = val & 0xffff;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ env->sysenter_esp = val;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ env->sysenter_eip = val;
+ break;
+ case MSR_IA32_APICBASE:
+ cpu_set_apic_base(env_archcpu(env)->apic_state, val);
+ break;
+ case MSR_EFER:
+ {
+ uint64_t update_mask;
+
+ update_mask = 0;
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
+ update_mask |= MSR_EFER_SCE;
+ }
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
+ update_mask |= MSR_EFER_LME;
+ }
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
+ update_mask |= MSR_EFER_FFXSR;
+ }
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
+ update_mask |= MSR_EFER_NXE;
+ }
+ if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
+ update_mask |= MSR_EFER_SVME;
+ }
+ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
+ update_mask |= MSR_EFER_FFXSR;
+ }
+ cpu_load_efer(env, (env->efer & ~update_mask) |
+ (val & update_mask));
+ }
+ break;
+ case MSR_STAR:
+ env->star = val;
+ break;
+ case MSR_PAT:
+ env->pat = val;
+ break;
+ case MSR_IA32_PKRS:
+ if (val & 0xFFFFFFFF00000000ull) {
+ goto error;
+ }
+ env->pkrs = val;
+ tlb_flush(cs);
+ break;
+ case MSR_VM_HSAVE_PA:
+ env->vm_hsave = val;
+ break;
+#ifdef TARGET_X86_64
+ case MSR_LSTAR:
+ env->lstar = val;
+ break;
+ case MSR_CSTAR:
+ env->cstar = val;
+ break;
+ case MSR_FMASK:
+ env->fmask = val;
+ break;
+ case MSR_FSBASE:
+ env->segs[R_FS].base = val;
+ break;
+ case MSR_GSBASE:
+ env->segs[R_GS].base = val;
+ break;
+ case MSR_KERNELGSBASE:
+ env->kernelgsbase = val;
+ break;
+#endif
+ case MSR_MTRRphysBase(0):
+ case MSR_MTRRphysBase(1):
+ case MSR_MTRRphysBase(2):
+ case MSR_MTRRphysBase(3):
+ case MSR_MTRRphysBase(4):
+ case MSR_MTRRphysBase(5):
+ case MSR_MTRRphysBase(6):
+ case MSR_MTRRphysBase(7):
+ env->mtrr_var[((uint32_t)env->regs[R_ECX] -
+ MSR_MTRRphysBase(0)) / 2].base = val;
+ break;
+ case MSR_MTRRphysMask(0):
+ case MSR_MTRRphysMask(1):
+ case MSR_MTRRphysMask(2):
+ case MSR_MTRRphysMask(3):
+ case MSR_MTRRphysMask(4):
+ case MSR_MTRRphysMask(5):
+ case MSR_MTRRphysMask(6):
+ case MSR_MTRRphysMask(7):
+ env->mtrr_var[((uint32_t)env->regs[R_ECX] -
+ MSR_MTRRphysMask(0)) / 2].mask = val;
+ break;
+ case MSR_MTRRfix64K_00000:
+ env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
+ MSR_MTRRfix64K_00000] = val;
+ break;
+ case MSR_MTRRfix16K_80000:
+ case MSR_MTRRfix16K_A0000:
+ env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
+ MSR_MTRRfix16K_80000 + 1] = val;
+ break;
+ case MSR_MTRRfix4K_C0000:
+ case MSR_MTRRfix4K_C8000:
+ case MSR_MTRRfix4K_D0000:
+ case MSR_MTRRfix4K_D8000:
+ case MSR_MTRRfix4K_E0000:
+ case MSR_MTRRfix4K_E8000:
+ case MSR_MTRRfix4K_F0000:
+ case MSR_MTRRfix4K_F8000:
+ env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
+ MSR_MTRRfix4K_C0000 + 3] = val;
+ break;
+ case MSR_MTRRdefType:
+ env->mtrr_deftype = val;
+ break;
+ case MSR_MCG_STATUS:
+ env->mcg_status = val;
+ break;
+ case MSR_MCG_CTL:
+ if ((env->mcg_cap & MCG_CTL_P)
+ && (val == 0 || val == ~(uint64_t)0)) {
+ env->mcg_ctl = val;
+ }
+ break;
+ case MSR_TSC_AUX:
+ env->tsc_aux = val;
+ break;
+ case MSR_IA32_MISC_ENABLE:
+ env->msr_ia32_misc_enable = val;
+ break;
+ case MSR_IA32_BNDCFGS:
+ /* FIXME: #GP if reserved bits are set. */
+ /* FIXME: Extend highest implemented bit of linear address. */
+ env->msr_bndcfgs = val;
+ cpu_sync_bndcs_hflags(env);
+ break;
+ default:
+ if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
+ && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
+ (4 * env->mcg_cap & 0xff)) {
+ uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
+ if ((offset & 0x3) != 0
+ || (val == 0 || val == ~(uint64_t)0)) {
+ env->mce_banks[offset] = val;
+ }
+ break;
+ }
+ /* XXX: exception? */
+ break;
+ }
+ return;
+error:
+ raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+}
+
+void helper_rdmsr(CPUX86State *env)
+{
+ X86CPU *x86_cpu = env_archcpu(env);
+ uint64_t val;
+
+ cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
+
+ switch ((uint32_t)env->regs[R_ECX]) {
+ case MSR_IA32_SYSENTER_CS:
+ val = env->sysenter_cs;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ val = env->sysenter_esp;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ val = env->sysenter_eip;
+ break;
+ case MSR_IA32_APICBASE:
+ val = cpu_get_apic_base(env_archcpu(env)->apic_state);
+ break;
+ case MSR_EFER:
+ val = env->efer;
+ break;
+ case MSR_STAR:
+ val = env->star;
+ break;
+ case MSR_PAT:
+ val = env->pat;
+ break;
+ case MSR_IA32_PKRS:
+ val = env->pkrs;
+ break;
+ case MSR_VM_HSAVE_PA:
+ val = env->vm_hsave;
+ break;
+ case MSR_IA32_PERF_STATUS:
+ /* tsc_increment_by_tick */
+ val = 1000ULL;
+ /* CPU multiplier */
+ val |= (((uint64_t)4ULL) << 40);
+ break;
+#ifdef TARGET_X86_64
+ case MSR_LSTAR:
+ val = env->lstar;
+ break;
+ case MSR_CSTAR:
+ val = env->cstar;
+ break;
+ case MSR_FMASK:
+ val = env->fmask;
+ break;
+ case MSR_FSBASE:
+ val = env->segs[R_FS].base;
+ break;
+ case MSR_GSBASE:
+ val = env->segs[R_GS].base;
+ break;
+ case MSR_KERNELGSBASE:
+ val = env->kernelgsbase;
+ break;
+ case MSR_TSC_AUX:
+ val = env->tsc_aux;
+ break;
+#endif
+ case MSR_SMI_COUNT:
+ val = env->msr_smi_count;
+ break;
+ case MSR_MTRRphysBase(0):
+ case MSR_MTRRphysBase(1):
+ case MSR_MTRRphysBase(2):
+ case MSR_MTRRphysBase(3):
+ case MSR_MTRRphysBase(4):
+ case MSR_MTRRphysBase(5):
+ case MSR_MTRRphysBase(6):
+ case MSR_MTRRphysBase(7):
+ val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
+ MSR_MTRRphysBase(0)) / 2].base;
+ break;
+ case MSR_MTRRphysMask(0):
+ case MSR_MTRRphysMask(1):
+ case MSR_MTRRphysMask(2):
+ case MSR_MTRRphysMask(3):
+ case MSR_MTRRphysMask(4):
+ case MSR_MTRRphysMask(5):
+ case MSR_MTRRphysMask(6):
+ case MSR_MTRRphysMask(7):
+ val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
+ MSR_MTRRphysMask(0)) / 2].mask;
+ break;
+ case MSR_MTRRfix64K_00000:
+ val = env->mtrr_fixed[0];
+ break;
+ case MSR_MTRRfix16K_80000:
+ case MSR_MTRRfix16K_A0000:
+ val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
+ MSR_MTRRfix16K_80000 + 1];
+ break;
+ case MSR_MTRRfix4K_C0000:
+ case MSR_MTRRfix4K_C8000:
+ case MSR_MTRRfix4K_D0000:
+ case MSR_MTRRfix4K_D8000:
+ case MSR_MTRRfix4K_E0000:
+ case MSR_MTRRfix4K_E8000:
+ case MSR_MTRRfix4K_F0000:
+ case MSR_MTRRfix4K_F8000:
+ val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
+ MSR_MTRRfix4K_C0000 + 3];
+ break;
+ case MSR_MTRRdefType:
+ val = env->mtrr_deftype;
+ break;
+ case MSR_MTRRcap:
+ if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
+ val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
+ MSR_MTRRcap_WC_SUPPORTED;
+ } else {
+ /* XXX: exception? */
+ val = 0;
+ }
+ break;
+ case MSR_MCG_CAP:
+ val = env->mcg_cap;
+ break;
+ case MSR_MCG_CTL:
+ if (env->mcg_cap & MCG_CTL_P) {
+ val = env->mcg_ctl;
+ } else {
+ val = 0;
+ }
+ break;
+ case MSR_MCG_STATUS:
+ val = env->mcg_status;
+ break;
+ case MSR_IA32_MISC_ENABLE:
+ val = env->msr_ia32_misc_enable;
+ break;
+ case MSR_IA32_BNDCFGS:
+ val = env->msr_bndcfgs;
+ break;
+ case MSR_IA32_UCODE_REV:
+ val = x86_cpu->ucode_rev;
+ break;
+ default:
+ if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
+ && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
+ (4 * env->mcg_cap & 0xff)) {
+ uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
+ val = env->mce_banks[offset];
+ break;
+ }
+ /* XXX: exception? */
+ val = 0;
+ break;
+ }
+ env->regs[R_EAX] = (uint32_t)(val);
+ env->regs[R_EDX] = (uint32_t)(val >> 32);
+}
+
+void helper_flush_page(CPUX86State *env, target_ulong addr)
+{
+ tlb_flush_page(env_cpu(env), addr);
+}
+
+static void QEMU_NORETURN do_hlt(CPUX86State *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+ cs->halted = 1;
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
+}
+
+void QEMU_NORETURN helper_hlt(CPUX86State *env, int next_eip_addend)
+{
+ cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
+ env->eip += next_eip_addend;
+
+ do_hlt(env);
+}
+
+void helper_monitor(CPUX86State *env, target_ulong ptr)
+{
+ if ((uint32_t)env->regs[R_ECX] != 0) {
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
+ }
+ /* XXX: store address? */
+ cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
+}
+
+void QEMU_NORETURN helper_mwait(CPUX86State *env, int next_eip_addend)
+{
+ CPUState *cs = env_cpu(env);
+
+ if ((uint32_t)env->regs[R_ECX] != 0) {
+ raise_exception_ra(env, EXCP0D_GPF, GETPC());
+ }
+ cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
+ env->eip += next_eip_addend;
+
+ /* XXX: not complete but not completely erroneous */
+ if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
+ do_pause(env);
+ } else {
+ do_hlt(env);
+ }
+}
diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c
new file mode 100644
index 0000000000..82c0856c41
--- /dev/null
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -0,0 +1,154 @@
+/*
+ * x86 segmentation related helpers: (sysemu-only code)
+ * TSS, interrupts, system calls, jumps and call/task gates, descriptors
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
+#include "tcg/helper-tcg.h"
+#include "../seg_helper.h"
+
+#ifdef TARGET_X86_64
+void helper_syscall(CPUX86State *env, int next_eip_addend)
+{
+ int selector;
+
+ if (!(env->efer & MSR_EFER_SCE)) {
+ raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
+ }
+ selector = (env->star >> 32) & 0xffff;
+ if (env->hflags & HF_LMA_MASK) {
+ int code64;
+
+ env->regs[R_ECX] = env->eip + next_eip_addend;
+ env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK;
+
+ code64 = env->hflags & HF_CS64_MASK;
+
+ env->eflags &= ~(env->fmask | RF_MASK);
+ cpu_load_eflags(env, env->eflags, 0);
+ cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
+ DESC_L_MASK);
+ cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_W_MASK | DESC_A_MASK);
+ if (code64) {
+ env->eip = env->lstar;
+ } else {
+ env->eip = env->cstar;
+ }
+ } else {
+ env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend);
+
+ env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
+ cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+ cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
+ 0, 0xffffffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_S_MASK |
+ DESC_W_MASK | DESC_A_MASK);
+ env->eip = (uint32_t)env->star;
+ }
+}
+#endif /* TARGET_X86_64 */
+
+void handle_even_inj(CPUX86State *env, int intno, int is_int,
+ int error_code, int is_hw, int rm)
+{
+ CPUState *cs = env_cpu(env);
+ uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
+ control.event_inj));
+
+ if (!(event_inj & SVM_EVTINJ_VALID)) {
+ int type;
+
+ if (is_int) {
+ type = SVM_EVTINJ_TYPE_SOFT;
+ } else {
+ type = SVM_EVTINJ_TYPE_EXEPT;
+ }
+ event_inj = intno | type | SVM_EVTINJ_VALID;
+ if (!rm && exception_has_error_code(intno)) {
+ event_inj |= SVM_EVTINJ_VALID_ERR;
+ x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
+ control.event_inj_err),
+ error_code);
+ }
+ x86_stl_phys(cs,
+ env->vm_vmcb + offsetof(struct vmcb, control.event_inj),
+ event_inj);
+ }
+}
+
+void x86_cpu_do_interrupt(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ if (cs->exception_index == EXCP_VMEXIT) {
+ assert(env->old_exception == -1);
+ do_vmexit(env);
+ } else {
+ do_interrupt_all(cpu, cs->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+ /* successfully delivered */
+ env->old_exception = -1;
+ }
+}
+
+/* check if Port I/O is allowed in TSS */
+void helper_check_io(CPUX86State *env, uint32_t addr, uint32_t size)
+{
+ uintptr_t retaddr = GETPC();
+ uint32_t io_offset, val, mask;
+
+ /* TSS must be a valid 32 bit one */
+ if (!(env->tr.flags & DESC_P_MASK) ||
+ ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+ env->tr.limit < 103) {
+ goto fail;
+ }
+ io_offset = cpu_lduw_kernel_ra(env, env->tr.base + 0x66, retaddr);
+ io_offset += (addr >> 3);
+ /* Note: the check needs two bytes */
+ if ((io_offset + 1) > env->tr.limit) {
+ goto fail;
+ }
+ val = cpu_lduw_kernel_ra(env, env->tr.base + io_offset, retaddr);
+ val >>= (addr & 7);
+ mask = (1 << size) - 1;
+ /* all bits must be zero to allow the I/O */
+ if ((val & mask) != 0) {
+ fail:
+ raise_exception_err_ra(env, EXCP0D_GPF, 0, retaddr);
+ }
+}
diff --git a/target/i386/tcg/smm_helper.c b/target/i386/tcg/sysemu/smm_helper.c
index 62d027abd3..a45b5651c3 100644
--- a/target/i386/tcg/smm_helper.c
+++ b/target/i386/tcg/sysemu/smm_helper.c
@@ -1,5 +1,5 @@
/*
- * x86 SMM helpers
+ * x86 SMM helpers (sysemu-only)
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -18,27 +18,14 @@
*/
#include "qemu/osdep.h"
-#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/log.h"
-#include "helper-tcg.h"
+#include "tcg/helper-tcg.h"
/* SMM support */
-#if defined(CONFIG_USER_ONLY)
-
-void do_smm_enter(X86CPU *cpu)
-{
-}
-
-void helper_rsm(CPUX86State *env)
-{
-}
-
-#else
-
#ifdef TARGET_X86_64
#define SMM_REVISION_ID 0x00020064
#else
@@ -330,5 +317,3 @@ void helper_rsm(CPUX86State *env)
qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP);
}
-
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target/i386/tcg/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c
index 0145afceae..9d671297cf 100644
--- a/target/i386/tcg/svm_helper.c
+++ b/target/i386/tcg/sysemu/svm_helper.c
@@ -1,5 +1,5 @@
/*
- * x86 SVM helpers
+ * x86 SVM helpers (sysemu only)
*
* Copyright (c) 2003 Fabrice Bellard
*
@@ -22,66 +22,10 @@
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
-#include "helper-tcg.h"
+#include "tcg/helper-tcg.h"
/* Secure Virtual Machine helpers */
-#if defined(CONFIG_USER_ONLY)
-
-void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
-{
-}
-
-void helper_vmmcall(CPUX86State *env)
-{
-}
-
-void helper_vmload(CPUX86State *env, int aflag)
-{
-}
-
-void helper_vmsave(CPUX86State *env, int aflag)
-{
-}
-
-void helper_stgi(CPUX86State *env)
-{
-}
-
-void helper_clgi(CPUX86State *env)
-{
-}
-
-void helper_skinit(CPUX86State *env)
-{
-}
-
-void helper_invlpga(CPUX86State *env, int aflag)
-{
-}
-
-void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
- uintptr_t retaddr)
-{
- assert(0);
-}
-
-void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
- uint64_t param)
-{
-}
-
-void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
- uint64_t param, uintptr_t retaddr)
-{
-}
-
-void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
- uint32_t next_eip_addend)
-{
-}
-#else
-
static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
const SegmentCache *sc)
{
@@ -219,18 +163,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
control.nested_cr3));
env->hflags2 |= HF2_NPT_MASK;
- if (env->cr[4] & CR4_PAE_MASK) {
- env->nested_pg_mode |= SVM_NPT_PAE;
- }
- if (env->cr[4] & CR4_PSE_MASK) {
- env->nested_pg_mode |= SVM_NPT_PSE;
- }
- if (env->hflags & HF_LMA_MASK) {
- env->nested_pg_mode |= SVM_NPT_LMA;
- }
- if (env->efer & MSR_EFER_NXE) {
- env->nested_pg_mode |= SVM_NPT_NXE;
- }
+ env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
}
/* enable intercepts */
@@ -479,31 +412,6 @@ void helper_clgi(CPUX86State *env)
env->hflags2 &= ~HF2_GIF_MASK;
}
-void helper_skinit(CPUX86State *env)
-{
- cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0, GETPC());
- /* XXX: not implemented */
- raise_exception(env, EXCP06_ILLOP);
-}
-
-void helper_invlpga(CPUX86State *env, int aflag)
-{
- X86CPU *cpu = env_archcpu(env);
- target_ulong addr;
-
- cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0, GETPC());
-
- if (aflag == 2) {
- addr = env->regs[R_EAX];
- } else {
- addr = (uint32_t)env->regs[R_EAX];
- }
-
- /* XXX: could use the ASID to see if it is needed to do the
- flush */
- tlb_flush_page(CPU(cpu), addr);
-}
-
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
uint64_t param, uintptr_t retaddr)
{
@@ -580,10 +488,9 @@ void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
}
}
-void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
- uint64_t param)
+void helper_svm_check_intercept(CPUX86State *env, uint32_t type)
{
- cpu_svm_check_intercept_param(env, type, param, GETPC());
+ cpu_svm_check_intercept_param(env, type, 0, GETPC());
}
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
@@ -796,5 +703,3 @@ void do_vmexit(CPUX86State *env)
host's code segment or non-canonical (in the case of long mode), a
#GP fault is delivered inside the host. */
}
-
-#endif
diff --git a/target/i386/tcg/sysemu/tcg-cpu.c b/target/i386/tcg/sysemu/tcg-cpu.c
new file mode 100644
index 0000000000..c223c0fe9b
--- /dev/null
+++ b/target/i386/tcg/sysemu/tcg-cpu.c
@@ -0,0 +1,83 @@
+/*
+ * i386 TCG cpu class initialization functions specific to sysemu
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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 "tcg/helper-tcg.h"
+
+#include "sysemu/sysemu.h"
+#include "qemu/units.h"
+#include "exec/address-spaces.h"
+
+#include "tcg/tcg-cpu.h"
+
+static void tcg_cpu_machine_done(Notifier *n, void *unused)
+{
+ X86CPU *cpu = container_of(n, X86CPU, machine_done);
+ MemoryRegion *smram =
+ (MemoryRegion *) object_resolve_path("/machine/smram", NULL);
+
+ if (smram) {
+ cpu->smram = g_new(MemoryRegion, 1);
+ memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram",
+ smram, 0, 4 * GiB);
+ memory_region_set_enabled(cpu->smram, true);
+ memory_region_add_subregion_overlap(cpu->cpu_as_root, 0,
+ cpu->smram, 1);
+ }
+}
+
+bool tcg_cpu_realizefn(CPUState *cs, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(cs);
+
+ /*
+ * The realize order is important, since x86_cpu_realize() checks if
+ * nothing else has been set by the user (or by accelerators) in
+ * cpu->ucode_rev and cpu->phys_bits, and the memory regions
+ * initialized here are needed for the vcpu initialization.
+ *
+ * realize order:
+ * tcg_cpu -> host_cpu -> x86_cpu
+ */
+ cpu->cpu_as_mem = g_new(MemoryRegion, 1);
+ cpu->cpu_as_root = g_new(MemoryRegion, 1);
+
+ /* Outer container... */
+ memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull);
+ memory_region_set_enabled(cpu->cpu_as_root, true);
+
+ /*
+ * ... with two regions inside: normal system memory with low
+ * priority, and...
+ */
+ memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory",
+ get_system_memory(), 0, ~0ull);
+ memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0);
+ memory_region_set_enabled(cpu->cpu_as_mem, true);
+
+ cs->num_ases = 2;
+ cpu_address_space_init(cs, 0, "cpu-memory", cs->memory);
+ cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root);
+
+ /* ... SMRAM with higher priority, linked from /machine/smram. */
+ cpu->machine_done.notify = tcg_cpu_machine_done;
+ qemu_add_machine_init_done_notifier(&cpu->machine_done);
+ return true;
+}
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 1e125d2175..ba39531aa5 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -19,14 +19,11 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "tcg-cpu.h"
-#include "exec/exec-all.h"
-#include "sysemu/runstate.h"
#include "helper-tcg.h"
+#include "qemu/accel.h"
+#include "hw/core/accel-cpu.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "hw/i386/apic.h"
-#endif
+#include "tcg-cpu.h"
/* Frob eflags into and out of the CPU temporary format. */
@@ -72,7 +69,52 @@ static struct TCGCPUOps x86_tcg_ops = {
#endif /* !CONFIG_USER_ONLY */
};
-void tcg_cpu_common_class_init(CPUClass *cc)
+static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc)
{
+ /* for x86, all cpus use the same set of operations */
cc->tcg_ops = &x86_tcg_ops;
}
+
+static void tcg_cpu_class_init(CPUClass *cc)
+{
+ cc->init_accel_cpu = tcg_cpu_init_ops;
+}
+
+/*
+ * TCG-specific defaults that override all CPU models when using TCG
+ */
+static PropValue tcg_default_props[] = {
+ { "vme", "off" },
+ { NULL, NULL },
+};
+
+static void tcg_cpu_instance_init(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ /* Special cases not set in the X86CPUDefinition structs: */
+ x86_cpu_apply_props(cpu, tcg_default_props);
+}
+
+static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+#ifndef CONFIG_USER_ONLY
+ acc->cpu_realizefn = tcg_cpu_realizefn;
+#endif /* CONFIG_USER_ONLY */
+
+ acc->cpu_class_init = tcg_cpu_class_init;
+ acc->cpu_instance_init = tcg_cpu_instance_init;
+}
+static const TypeInfo tcg_cpu_accel_type_info = {
+ .name = ACCEL_CPU_NAME("tcg"),
+
+ .parent = TYPE_ACCEL_CPU,
+ .class_init = tcg_cpu_accel_class_init,
+ .abstract = true,
+};
+static void tcg_cpu_accel_register_types(void)
+{
+ type_register_static(&tcg_cpu_accel_type_info);
+}
+type_init(tcg_cpu_accel_register_types);
diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h
index 81f02e562e..36bd300af0 100644
--- a/target/i386/tcg/tcg-cpu.h
+++ b/target/i386/tcg/tcg-cpu.h
@@ -1,15 +1,24 @@
/*
- * i386 TCG CPU class initialization
+ * i386 TCG cpu class initialization functions
*
- * Copyright 2020 SUSE LLC
+ * Copyright (c) 2003 Fabrice Bellard
*
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-
#ifndef TCG_CPU_H
#define TCG_CPU_H
-void tcg_cpu_common_class_init(CPUClass *cc);
+bool tcg_cpu_realizefn(CPUState *cs, Error **errp);
#endif /* TCG_CPU_H */
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 880bc45561..051b6dff18 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -39,16 +39,7 @@
#define PREFIX_DATA 0x08
#define PREFIX_ADR 0x10
#define PREFIX_VEX 0x20
-
-#ifdef TARGET_X86_64
-#define CODE64(s) ((s)->code64)
-#define REX_X(s) ((s)->rex_x)
-#define REX_B(s) ((s)->rex_b)
-#else
-#define CODE64(s) 0
-#define REX_X(s) 0
-#define REX_B(s) 0
-#endif
+#define PREFIX_REX 0x40
#ifdef TARGET_X86_64
# define ctztl ctz64
@@ -85,42 +76,38 @@ static TCGv_i64 cpu_bndu[4];
typedef struct DisasContext {
DisasContextBase base;
- /* current insn context */
- int override; /* -1 if no override */
- int prefix;
+ target_ulong pc; /* pc = eip + cs_base */
+ target_ulong pc_start; /* pc at TB entry */
+ target_ulong cs_base; /* base of CS segment */
+
MemOp aflag;
MemOp dflag;
- target_ulong pc_start;
- target_ulong pc; /* pc = eip + cs_base */
- /* current block context */
- target_ulong cs_base; /* base of CS segment */
- int pe; /* protected mode */
- int code32; /* 32 bit code segment */
-#ifdef TARGET_X86_64
- int lma; /* long mode active */
- int code64; /* 64 bit code segment */
- int rex_x, rex_b;
+
+ int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
+ uint8_t prefix;
+
+#ifndef CONFIG_USER_ONLY
+ uint8_t cpl; /* code priv level */
+ uint8_t iopl; /* i/o priv level */
#endif
- int vex_l; /* vex vector length */
- int vex_v; /* vex vvvv register, without 1's complement. */
- int ss32; /* 32 bit stack segment */
- CCOp cc_op; /* current CC operation */
- bool cc_op_dirty;
+ uint8_t vex_l; /* vex vector length */
+ uint8_t vex_v; /* vex vvvv register, without 1's complement. */
+ uint8_t popl_esp_hack; /* for correct popl with esp base handling */
+ uint8_t rip_offset; /* only used in x86_64, but left for simplicity */
+
#ifdef TARGET_X86_64
- bool x86_64_hregs;
+ uint8_t rex_r;
+ uint8_t rex_x;
+ uint8_t rex_b;
+ bool rex_w;
#endif
- int addseg; /* non zero if either DS/ES/SS have a non zero base */
- int f_st; /* currently unused */
- int vm86; /* vm86 mode */
- int cpl;
- int iopl;
- int tf; /* TF cpu flag */
- int jmp_opt; /* use direct block chaining for direct jumps */
- int repz_opt; /* optimize jumps within repz instructions */
+ bool jmp_opt; /* use direct block chaining for direct jumps */
+ bool repz_opt; /* optimize jumps within repz instructions */
+ bool cc_op_dirty;
+
+ CCOp cc_op; /* current CC operation */
int mem_index; /* select memory access functions */
- uint64_t flags; /* all execution flags */
- int popl_esp_hack; /* for correct popl with esp base handling */
- int rip_offset; /* only used in x86_64, but left for simplicity */
+ uint32_t flags; /* all execution flags */
int cpuid_features;
int cpuid_ext_features;
int cpuid_ext2_features;
@@ -146,11 +133,96 @@ typedef struct DisasContext {
sigjmp_buf jmpbuf;
} DisasContext;
+/* The environment in which user-only runs is constrained. */
+#ifdef CONFIG_USER_ONLY
+#define PE(S) true
+#define CPL(S) 3
+#define IOPL(S) 0
+#define SVME(S) false
+#define GUEST(S) false
+#else
+#define PE(S) (((S)->flags & HF_PE_MASK) != 0)
+#define CPL(S) ((S)->cpl)
+#define IOPL(S) ((S)->iopl)
+#define SVME(S) (((S)->flags & HF_SVME_MASK) != 0)
+#define GUEST(S) (((S)->flags & HF_GUEST_MASK) != 0)
+#endif
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
+#define VM86(S) false
+#define CODE32(S) true
+#define SS32(S) true
+#define ADDSEG(S) false
+#else
+#define VM86(S) (((S)->flags & HF_VM_MASK) != 0)
+#define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0)
+#define SS32(S) (((S)->flags & HF_SS32_MASK) != 0)
+#define ADDSEG(S) (((S)->flags & HF_ADDSEG_MASK) != 0)
+#endif
+#if !defined(TARGET_X86_64)
+#define CODE64(S) false
+#define LMA(S) false
+#elif defined(CONFIG_USER_ONLY)
+#define CODE64(S) true
+#define LMA(S) true
+#else
+#define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0)
+#define LMA(S) (((S)->flags & HF_LMA_MASK) != 0)
+#endif
+
+#ifdef TARGET_X86_64
+#define REX_PREFIX(S) (((S)->prefix & PREFIX_REX) != 0)
+#define REX_W(S) ((S)->rex_w)
+#define REX_R(S) ((S)->rex_r + 0)
+#define REX_X(S) ((S)->rex_x + 0)
+#define REX_B(S) ((S)->rex_b + 0)
+#else
+#define REX_PREFIX(S) false
+#define REX_W(S) false
+#define REX_R(S) 0
+#define REX_X(S) 0
+#define REX_B(S) 0
+#endif
+
+/*
+ * Many sysemu-only helpers are not reachable for user-only.
+ * Define stub generators here, so that we need not either sprinkle
+ * ifdefs through the translator, nor provide the helper function.
+ */
+#define STUB_HELPER(NAME, ...) \
+ static inline void gen_helper_##NAME(__VA_ARGS__) \
+ { qemu_build_not_reached(); }
+
+#ifdef CONFIG_USER_ONLY
+STUB_HELPER(clgi, TCGv_env env)
+STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
+STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
+STUB_HELPER(inb, TCGv ret, TCGv_env env, TCGv_i32 port)
+STUB_HELPER(inw, TCGv ret, TCGv_env env, TCGv_i32 port)
+STUB_HELPER(inl, TCGv ret, TCGv_env env, TCGv_i32 port)
+STUB_HELPER(monitor, TCGv_env env, TCGv addr)
+STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs)
+STUB_HELPER(outb, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
+STUB_HELPER(outw, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
+STUB_HELPER(outl, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
+STUB_HELPER(rdmsr, TCGv_env env)
+STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg)
+STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
+STUB_HELPER(stgi, TCGv_env env)
+STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type)
+STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag)
+STUB_HELPER(vmmcall, TCGv_env env)
+STUB_HELPER(vmrun, TCGv_env env, TCGv_i32 aflag, TCGv_i32 pc_ofs)
+STUB_HELPER(vmsave, TCGv_env env, TCGv_i32 aflag)
+STUB_HELPER(write_crN, TCGv_env env, TCGv_i32 reg, TCGv val)
+STUB_HELPER(wrmsr, TCGv_env env)
+#endif
+
static void gen_eob(DisasContext *s);
static void gen_jr(DisasContext *s, TCGv dest);
static void gen_jmp(DisasContext *s, target_ulong eip);
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
+static void gen_exception_gpf(DisasContext *s);
/* i386 arith/logic operations */
enum {
@@ -309,14 +381,10 @@ static void gen_update_cc_op(DisasContext *s)
*/
static inline bool byte_reg_is_xH(DisasContext *s, int reg)
{
- if (reg < 4) {
- return false;
- }
-#ifdef TARGET_X86_64
- if (reg >= 8 || s->x86_64_hregs) {
+ /* Any time the REX prefix is present, byte registers are uniform */
+ if (reg < 4 || REX_PREFIX(s)) {
return false;
}
-#endif
return true;
}
@@ -333,7 +401,7 @@ static inline MemOp mo_pushpop(DisasContext *s, MemOp ot)
/* Select the size of the stack pointer. */
static inline MemOp mo_stacksize(DisasContext *s)
{
- return CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
+ return CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16;
}
/* Select only size 64 else 32. Used for SSE operand sizes. */
@@ -466,7 +534,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0,
#endif
case MO_32:
/* 32 bit address */
- if (ovr_seg < 0 && s->addseg) {
+ if (ovr_seg < 0 && ADDSEG(s)) {
ovr_seg = def_seg;
}
if (ovr_seg < 0) {
@@ -479,7 +547,7 @@ static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0,
tcg_gen_ext16u_tl(s->A0, a0);
a0 = s->A0;
if (ovr_seg < 0) {
- if (s->addseg) {
+ if (ADDSEG(s)) {
ovr_seg = def_seg;
} else {
return;
@@ -612,37 +680,40 @@ static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n)
}
}
-static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip,
+/*
+ * Validate that access to [port, port + 1<<ot) is allowed.
+ * Raise #GP, or VMM exit if not.
+ */
+static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port,
uint32_t svm_flags)
{
- target_ulong next_eip;
-
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
- switch (ot) {
- case MO_8:
- gen_helper_check_iob(cpu_env, s->tmp2_i32);
- break;
- case MO_16:
- gen_helper_check_iow(cpu_env, s->tmp2_i32);
- break;
- case MO_32:
- gen_helper_check_iol(cpu_env, s->tmp2_i32);
- break;
- default:
- tcg_abort();
- }
+#ifdef CONFIG_USER_ONLY
+ /*
+ * We do not implement the ioperm(2) syscall, so the TSS check
+ * will always fail.
+ */
+ gen_exception_gpf(s);
+ return false;
+#else
+ if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
+ gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot));
}
- if(s->flags & HF_GUEST_MASK) {
+ if (GUEST(s)) {
+ target_ulong cur_eip = s->base.pc_next - s->cs_base;
+ target_ulong next_eip = s->pc - s->cs_base;
+
gen_update_cc_op(s);
gen_jmp_im(s, cur_eip);
- svm_flags |= (1 << (4 + ot));
- next_eip = s->pc - s->cs_base;
- tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
- gen_helper_svm_check_io(cpu_env, s->tmp2_i32,
- tcg_const_i32(svm_flags),
- tcg_const_i32(next_eip - cur_eip));
+ if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) {
+ svm_flags |= SVM_IOIO_REP_MASK;
+ }
+ svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot);
+ gen_helper_svm_check_io(cpu_env, port,
+ tcg_constant_i32(svm_flags),
+ tcg_constant_i32(next_eip - cur_eip));
}
+ return true;
+#endif
}
static inline void gen_movs(DisasContext *s, MemOp ot)
@@ -1117,16 +1188,20 @@ static inline void gen_cmps(DisasContext *s, MemOp ot)
static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
{
if (s->flags & HF_IOBPT_MASK) {
+#ifdef CONFIG_USER_ONLY
+ /* user-mode cpu should not be in IOBPT mode */
+ g_assert_not_reached();
+#else
TCGv_i32 t_size = tcg_const_i32(1 << ot);
TCGv t_next = tcg_const_tl(s->pc - s->cs_base);
gen_helper_bpt_io(cpu_env, t_port, t_size, t_next);
tcg_temp_free_i32(t_size);
tcg_temp_free(t_next);
+#endif /* CONFIG_USER_ONLY */
}
}
-
static inline void gen_ins(DisasContext *s, MemOp ot)
{
gen_string_movl_A0_EDI(s);
@@ -1272,6 +1347,42 @@ static void gen_illegal_opcode(DisasContext *s)
gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base);
}
+/* Generate #GP for the current instruction. */
+static void gen_exception_gpf(DisasContext *s)
+{
+ gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base);
+}
+
+/* Check for cpl == 0; if not, raise #GP and return false. */
+static bool check_cpl0(DisasContext *s)
+{
+ if (CPL(s) == 0) {
+ return true;
+ }
+ gen_exception_gpf(s);
+ return false;
+}
+
+/* If vm86, check for iopl == 3; if not, raise #GP and return false. */
+static bool check_vm86_iopl(DisasContext *s)
+{
+ if (!VM86(s) || IOPL(s) == 3) {
+ return true;
+ }
+ gen_exception_gpf(s);
+ return false;
+}
+
+/* Check for iopl allowing access; if not, raise #GP and return false. */
+static bool check_iopl(DisasContext *s)
+{
+ if (VM86(s) ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
+ return true;
+ }
+ gen_exception_gpf(s);
+ return false;
+}
+
/* if d == OR_TMP0, it means memory operand (address in A0) */
static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
{
@@ -2305,14 +2416,14 @@ static inline void gen_op_movl_seg_T0_vm(DisasContext *s, X86Seg seg_reg)
call this function with seg_reg == R_CS */
static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg)
{
- if (s->pe && !s->vm86) {
+ if (PE(s) && !VM86(s)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), s->tmp2_i32);
/* abort translation because the addseg value may change or
because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware
interrupts for the next instruction */
- if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS)) {
+ if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) {
s->base.is_jmp = DISAS_TOO_MANY;
}
} else {
@@ -2323,28 +2434,13 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg)
}
}
-static inline int svm_is_rep(int prefixes)
-{
- return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
-}
-
-static inline void
-gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
- uint32_t type, uint64_t param)
+static void gen_svm_check_intercept(DisasContext *s, uint32_t type)
{
/* no SVM activated; fast case */
- if (likely(!(s->flags & HF_GUEST_MASK)))
+ if (likely(!GUEST(s))) {
return;
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
- gen_helper_svm_check_intercept_param(cpu_env, tcg_const_i32(type),
- tcg_const_i64(param));
-}
-
-static inline void
-gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type)
-{
- gen_svm_check_intercept_param(s, pc_start, type, 0);
+ }
+ gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type));
}
static inline void gen_stack_update(DisasContext *s, int addend)
@@ -2363,7 +2459,7 @@ static void gen_push_v(DisasContext *s, TCGv val)
tcg_gen_subi_tl(s->A0, cpu_regs[R_ESP], size);
if (!CODE64(s)) {
- if (s->addseg) {
+ if (ADDSEG(s)) {
new_esp = s->tmp4;
tcg_gen_mov_tl(new_esp, s->A0);
}
@@ -2392,12 +2488,12 @@ static inline void gen_pop_update(DisasContext *s, MemOp ot)
static inline void gen_stack_A0(DisasContext *s)
{
- gen_lea_v_seg(s, s->ss32 ? MO_32 : MO_16, cpu_regs[R_ESP], R_SS, -1);
+ gen_lea_v_seg(s, SS32(s) ? MO_32 : MO_16, cpu_regs[R_ESP], R_SS, -1);
}
static void gen_pusha(DisasContext *s)
{
- MemOp s_ot = s->ss32 ? MO_32 : MO_16;
+ MemOp s_ot = SS32(s) ? MO_32 : MO_16;
MemOp d_ot = s->dflag;
int size = 1 << d_ot;
int i;
@@ -2413,7 +2509,7 @@ static void gen_pusha(DisasContext *s)
static void gen_popa(DisasContext *s)
{
- MemOp s_ot = s->ss32 ? MO_32 : MO_16;
+ MemOp s_ot = SS32(s) ? MO_32 : MO_16;
MemOp d_ot = s->dflag;
int size = 1 << d_ot;
int i;
@@ -2435,7 +2531,7 @@ static void gen_popa(DisasContext *s)
static void gen_enter(DisasContext *s, int esp_addend, int level)
{
MemOp d_ot = mo_pushpop(s, s->dflag);
- MemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
+ MemOp a_ot = CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16;
int size = 1 << d_ot;
/* Push BP; compute FrameTemp into T1. */
@@ -2518,10 +2614,10 @@ static void gen_interrupt(DisasContext *s, int intno,
s->base.is_jmp = DISAS_NORETURN;
}
-static void gen_debug(DisasContext *s, target_ulong cur_eip)
+static void gen_debug(DisasContext *s)
{
gen_update_cc_op(s);
- gen_jmp_im(s, cur_eip);
+ gen_jmp_im(s, s->base.pc_next - s->cs_base);
gen_helper_debug(cpu_env);
s->base.is_jmp = DISAS_NORETURN;
}
@@ -2587,7 +2683,7 @@ do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr)
} else if (recheck_tf) {
gen_helper_rechecking_single_step(cpu_env);
tcg_gen_exit_tb(NULL, 0);
- } else if (s->tf) {
+ } else if (s->flags & HF_TF_MASK) {
gen_helper_single_step(cpu_env);
} else if (jr) {
tcg_gen_lookup_and_goto_ptr();
@@ -3030,7 +3126,7 @@ static const struct SSEOpHelper_eppi sse_op_table7[256] = {
};
static void gen_sse(CPUX86State *env, DisasContext *s, int b,
- target_ulong pc_start, int rex_r)
+ target_ulong pc_start)
{
int b1, op1_offset, op2_offset, is_xmm, val;
int modrm, mod, rm, reg;
@@ -3100,8 +3196,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
modrm = x86_ldub_code(env, s);
reg = ((modrm >> 3) & 7);
- if (is_xmm)
- reg |= rex_r;
+ if (is_xmm) {
+ reg |= REX_R(s);
+ }
mod = (modrm >> 6) & 3;
if (sse_fn_epp == SSE_SPECIAL) {
b |= (b1 << 8);
@@ -3635,7 +3732,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
tcg_gen_ld16u_tl(s->T0, cpu_env,
offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val)));
}
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_op_mov_reg_v(s, ot, reg, s->T0);
break;
case 0x1d6: /* movq ea, xmm */
@@ -3679,7 +3776,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
offsetof(CPUX86State, fpregs[rm].mmx));
gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, s->ptr0);
}
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
break;
@@ -3691,7 +3788,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
}
modrm = x86_ldub_code(env, s);
rm = modrm & 7;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
if (b1 >= 2) {
goto unknown_op;
@@ -3767,7 +3864,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
/* Various integer extensions at 0f 38 f[0-f]. */
b = modrm | (b1 << 8);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
switch (b) {
case 0x3f0: /* crc32 Gd,Eb */
@@ -4121,7 +4218,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
b = modrm;
modrm = x86_ldub_code(env, s);
rm = modrm & 7;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
if (b1 >= 2) {
goto unknown_op;
@@ -4141,7 +4238,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
rm = (modrm & 7) | REX_B(s);
if (mod != 3)
gen_lea_modrm(env, s, modrm);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
val = x86_ldub_code(env, s);
switch (b) {
case 0x14: /* pextrb */
@@ -4310,7 +4407,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
/* Various integer extensions at 0f 3a f[0-f]. */
b = modrm | (b1 << 8);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
switch (b) {
case 0x3f0: /* rorx Gy,Ey, Ib */
@@ -4484,27 +4581,25 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
MemOp ot, aflag, dflag;
int modrm, reg, rm, mod, op, opreg, val;
target_ulong next_eip, tval;
- int rex_w, rex_r;
target_ulong pc_start = s->base.pc_next;
s->pc_start = s->pc = pc_start;
s->override = -1;
#ifdef TARGET_X86_64
+ s->rex_w = false;
+ s->rex_r = 0;
s->rex_x = 0;
s->rex_b = 0;
- s->x86_64_hregs = false;
#endif
s->rip_offset = 0; /* for relative ip address */
s->vex_l = 0;
s->vex_v = 0;
if (sigsetjmp(s->jmpbuf, 0) != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ gen_exception_gpf(s);
return s->pc;
}
prefixes = 0;
- rex_w = -1;
- rex_r = 0;
next_byte:
b = x86_ldub_code(env, s);
@@ -4547,12 +4642,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x40 ... 0x4f:
if (CODE64(s)) {
/* REX prefix */
- rex_w = (b >> 3) & 1;
- rex_r = (b & 0x4) << 1;
+ prefixes |= PREFIX_REX;
+ s->rex_w = (b >> 3) & 1;
+ s->rex_r = (b & 0x4) << 1;
s->rex_x = (b & 0x2) << 2;
- REX_B(s) = (b & 0x1) << 3;
- /* select uniform byte register addressing */
- s->x86_64_hregs = true;
+ s->rex_b = (b & 0x1) << 3;
goto next_byte;
}
break;
@@ -4561,7 +4655,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xc4: /* 3-byte VEX */
/* VEX prefixes cannot be used except in 32-bit mode.
Otherwise the instruction is LES or LDS. */
- if (s->code32 && !s->vm86) {
+ if (CODE32(s) && !VM86(s)) {
static const int pp_prefix[4] = {
0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ
};
@@ -4576,27 +4670,24 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
/* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ
- | PREFIX_LOCK | PREFIX_DATA)) {
+ | PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) {
goto illegal_op;
}
#ifdef TARGET_X86_64
- if (s->x86_64_hregs) {
- goto illegal_op;
- }
+ s->rex_r = (~vex2 >> 4) & 8;
#endif
- rex_r = (~vex2 >> 4) & 8;
if (b == 0xc5) {
/* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */
vex3 = vex2;
b = x86_ldub_code(env, s) | 0x100;
} else {
/* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */
+ vex3 = x86_ldub_code(env, s);
#ifdef TARGET_X86_64
s->rex_x = (~vex2 >> 3) & 8;
s->rex_b = (~vex2 >> 2) & 8;
+ s->rex_w = (vex3 >> 7) & 1;
#endif
- vex3 = x86_ldub_code(env, s);
- rex_w = (vex3 >> 7) & 1;
switch (vex2 & 0x1f) {
case 0x01: /* Implied 0f leading opcode bytes. */
b = x86_ldub_code(env, s) | 0x100;
@@ -4623,18 +4714,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
/* In 64-bit mode, the default data size is 32-bit. Select 64-bit
data with rex_w, and 16-bit data with 0x66; rex_w takes precedence
over 0x66 if both are present. */
- dflag = (rex_w > 0 ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
+ dflag = (REX_W(s) ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
/* In 64-bit mode, 0x67 selects 32-bit addressing. */
aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64);
} else {
/* In 16/32-bit mode, 0x66 selects the opposite data size. */
- if (s->code32 ^ ((prefixes & PREFIX_DATA) != 0)) {
+ if (CODE32(s) ^ ((prefixes & PREFIX_DATA) != 0)) {
dflag = MO_32;
} else {
dflag = MO_16;
}
/* In 16/32-bit mode, 0x67 selects the opposite addressing. */
- if (s->code32 ^ ((prefixes & PREFIX_ADR) != 0)) {
+ if (CODE32(s) ^ ((prefixes & PREFIX_ADR) != 0)) {
aflag = MO_32;
} else {
aflag = MO_16;
@@ -4674,7 +4765,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
switch(f) {
case 0: /* OP Ev, Gv */
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
if (mod != 3) {
@@ -4696,7 +4787,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 1: /* OP Gv, Ev */
modrm = x86_ldub_code(env, s);
mod = (modrm >> 6) & 3;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
rm = (modrm & 7) | REX_B(s);
if (mod != 3) {
gen_lea_modrm(env, s, modrm);
@@ -5019,7 +5110,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
/* operand size for jumps is 64 bit */
ot = MO_64;
} else if (op == 3 || op == 5) {
- ot = dflag != MO_16 ? MO_32 + (rex_w == 1) : MO_16;
+ ot = dflag != MO_16 ? MO_32 + REX_W(s) : MO_16;
} else if (op == 6) {
/* default push size is 64 bit */
ot = mo_pushpop(s, dflag);
@@ -5068,7 +5159,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_add_A0_im(s, 1 << ot);
gen_op_ld_v(s, MO_16, s->T0, s->A0);
do_lcall:
- if (s->pe && !s->vm86) {
+ if (PE(s) && !VM86(s)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1,
tcg_const_i32(dflag - 1),
@@ -5098,7 +5189,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_add_A0_im(s, 1 << ot);
gen_op_ld_v(s, MO_16, s->T0, s->A0);
do_ljmp:
- if (s->pe && !s->vm86) {
+ if (PE(s) && !VM86(s)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1,
tcg_const_tl(s->pc - s->cs_base));
@@ -5122,7 +5213,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
gen_op_mov_v_reg(s, ot, s->T1, reg);
@@ -5194,7 +5285,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x6b:
ot = dflag;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (b == 0x69)
s->rip_offset = insn_const_size(ot);
else if (b == 0x6b)
@@ -5246,7 +5337,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x1c1: /* xadd Ev, Gv */
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
gen_op_mov_v_reg(s, ot, s->T0, reg);
if (mod == 3) {
@@ -5278,7 +5369,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
oldv = tcg_temp_new();
newv = tcg_temp_new();
@@ -5476,7 +5567,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
if (s->base.is_jmp) {
gen_jmp_im(s, s->pc - s->cs_base);
if (reg == R_SS) {
- s->tf = 0;
+ s->flags &= ~HF_TF_MASK;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s);
@@ -5500,7 +5591,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x89: /* mov Gv, Ev */
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
/* generate a generic store */
gen_ldst_modrm(env, s, modrm, ot, reg, 1);
@@ -5526,7 +5617,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x8b: /* mov Ev, Gv */
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
gen_op_mov_reg_v(s, ot, reg, s->T0);
@@ -5542,7 +5633,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
if (s->base.is_jmp) {
gen_jmp_im(s, s->pc - s->cs_base);
if (reg == R_SS) {
- s->tf = 0;
+ s->flags &= ~HF_TF_MASK;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s);
@@ -5576,7 +5667,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
s_ot = b & 8 ? MO_SIGN | ot : ot;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -5615,7 +5706,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
{
AddressParts a = gen_lea_modrm_0(env, s, modrm);
TCGv ea = gen_lea_modrm_1(s, a);
@@ -5697,7 +5788,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x87: /* xchg Ev, Gv */
ot = mo_b_d(b, dflag);
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
if (mod == 3) {
rm = (modrm & 7) | REX_B(s);
@@ -5734,7 +5825,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
do_lxx:
ot = dflag != MO_16 ? MO_32 : MO_16;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
@@ -5817,7 +5908,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (mod != 3) {
gen_lea_modrm(env, s, modrm);
opreg = OR_TMP0;
@@ -6395,9 +6486,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x6c: /* insS */
case 0x6d:
ot = mo_b_d32(b, dflag);
- tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
- gen_check_io(s, ot, pc_start - s->cs_base,
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
+ tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+ tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+ if (!gen_check_io(s, ot, s->tmp2_i32,
+ SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) {
+ break;
+ }
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
@@ -6414,9 +6508,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x6e: /* outsS */
case 0x6f:
ot = mo_b_d32(b, dflag);
- tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
- gen_check_io(s, ot, pc_start - s->cs_base,
- svm_is_rep(prefixes) | 4);
+ tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+ tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+ if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_STR_MASK)) {
+ break;
+ }
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
@@ -6438,13 +6534,13 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xe5:
ot = mo_b_d32(b, dflag);
val = x86_ldub_code(env, s);
- tcg_gen_movi_tl(s->T0, val);
- gen_check_io(s, ot, pc_start - s->cs_base,
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+ tcg_gen_movi_i32(s->tmp2_i32, val);
+ if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
+ break;
+ }
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);
gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6456,15 +6552,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xe7:
ot = mo_b_d32(b, dflag);
val = x86_ldub_code(env, s);
- tcg_gen_movi_tl(s->T0, val);
- gen_check_io(s, ot, pc_start - s->cs_base,
- svm_is_rep(prefixes));
- gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
-
+ tcg_gen_movi_i32(s->tmp2_i32, val);
+ if (!gen_check_io(s, ot, s->tmp2_i32, 0)) {
+ break;
+ }
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
- tcg_gen_movi_i32(s->tmp2_i32, val);
+ gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6475,13 +6570,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xec:
case 0xed:
ot = mo_b_d32(b, dflag);
- tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
- gen_check_io(s, ot, pc_start - s->cs_base,
- SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
+ tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+ tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+ if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
+ break;
+ }
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);
gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6492,15 +6588,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xee:
case 0xef:
ot = mo_b_d32(b, dflag);
- tcg_gen_ext16u_tl(s->T0, cpu_regs[R_EDX]);
- gen_check_io(s, ot, pc_start - s->cs_base,
- svm_is_rep(prefixes));
- gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
-
+ tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
+ tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
+ if (!gen_check_io(s, ot, s->tmp2_i32, 0)) {
+ break;
+ }
if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
gen_io_start();
}
- tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
+ gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
gen_bpt_io(s, s->tmp2_i32, ot);
@@ -6531,7 +6627,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xca: /* lret im */
val = x86_ldsw_code(env, s);
do_lret:
- if (s->pe && !s->vm86) {
+ if (PE(s) && !VM86(s)) {
gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1),
@@ -6556,23 +6652,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
val = 0;
goto do_lret;
case 0xcf: /* iret */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
- if (!s->pe) {
- /* real mode */
- gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
- set_cc_op(s, CC_OP_EFLAGS);
- } else if (s->vm86) {
- if (s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
- set_cc_op(s, CC_OP_EFLAGS);
+ gen_svm_check_intercept(s, SVM_EXIT_IRET);
+ if (!PE(s) || VM86(s)) {
+ /* real mode or vm86 mode */
+ if (!check_vm86_iopl(s)) {
+ break;
}
+ gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
} else {
gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1),
tcg_const_i32(s->pc - s->cs_base));
- set_cc_op(s, CC_OP_EFLAGS);
}
+ set_cc_op(s, CC_OP_EFLAGS);
gen_eob(s);
break;
case 0xe8: /* call im */
@@ -6676,29 +6767,25 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
}
ot = dflag;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_cmovcc1(env, s, ot, b, modrm, reg);
break;
/************************/
/* flags */
case 0x9c: /* pushf */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ gen_svm_check_intercept(s, SVM_EXIT_PUSHF);
+ if (check_vm86_iopl(s)) {
gen_update_cc_op(s);
gen_helper_read_eflags(s->T0, cpu_env);
gen_push_v(s, s->T0);
}
break;
case 0x9d: /* popf */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ gen_svm_check_intercept(s, SVM_EXIT_POPF);
+ if (check_vm86_iopl(s)) {
ot = gen_pop_T0(s);
- if (s->cpl == 0) {
+ if (CPL(s) == 0) {
if (dflag != MO_16) {
gen_helper_write_eflags(cpu_env, s->T0,
tcg_const_i32((TF_MASK | AC_MASK |
@@ -6713,7 +6800,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
& 0xffff));
}
} else {
- if (s->cpl <= s->iopl) {
+ if (CPL(s) <= IOPL(s)) {
if (dflag != MO_16) {
gen_helper_write_eflags(cpu_env, s->T0,
tcg_const_i32((TF_MASK |
@@ -6826,7 +6913,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
do_btx:
ot = dflag;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
gen_op_mov_v_reg(s, MO_32, s->T1, reg);
@@ -6931,7 +7018,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x1bd: /* bsr / lzcnt */
ot = dflag;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
gen_extu(ot, s->T0);
@@ -7056,9 +7143,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xcd: /* int N */
val = x86_ldub_code(env, s);
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ if (check_vm86_iopl(s)) {
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
}
break;
@@ -7071,33 +7156,21 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
#ifdef WANT_ICEBP
case 0xf1: /* icebp (undocumented, exits to external debugger) */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP);
- gen_debug(s, pc_start - s->cs_base);
+ gen_svm_check_intercept(s, SVM_EXIT_ICEBP);
+ gen_debug(s);
break;
#endif
case 0xfa: /* cli */
- if (!s->vm86) {
- if (s->cpl <= s->iopl) {
- gen_helper_cli(cpu_env);
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
- } else {
- if (s->iopl == 3) {
- gen_helper_cli(cpu_env);
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
+ if (check_iopl(s)) {
+ gen_helper_cli(cpu_env);
}
break;
case 0xfb: /* sti */
- if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) {
+ if (check_iopl(s)) {
gen_helper_sti(cpu_env);
/* interruptions are enabled only the first insn after sti */
gen_jmp_im(s, s->pc - s->cs_base);
gen_eob_inhibit_irq(s, true);
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
break;
case 0x62: /* bound */
@@ -7189,15 +7262,15 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0x130: /* wrmsr */
case 0x132: /* rdmsr */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ if (check_cpl0(s)) {
gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base);
if (b & 2) {
gen_helper_rdmsr(cpu_env);
} else {
gen_helper_wrmsr(cpu_env);
+ gen_jmp_im(s, s->pc - s->cs_base);
+ gen_eob(s);
}
}
break;
@@ -7216,13 +7289,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_rdpmc(cpu_env);
+ s->base.is_jmp = DISAS_NORETURN;
break;
case 0x134: /* sysenter */
/* For Intel SYSENTER is valid on 64-bit */
if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
goto illegal_op;
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!PE(s)) {
+ gen_exception_gpf(s);
} else {
gen_helper_sysenter(cpu_env);
gen_eob(s);
@@ -7232,8 +7306,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
/* For Intel SYSEXIT is valid on 64-bit */
if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
goto illegal_op;
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!PE(s)) {
+ gen_exception_gpf(s);
} else {
gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
gen_eob(s);
@@ -7251,12 +7325,12 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_eob_worker(s, false, true);
break;
case 0x107: /* sysret */
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!PE(s)) {
+ gen_exception_gpf(s);
} else {
gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1));
/* condition codes are modified only in long mode */
- if (s->lma) {
+ if (LMA(s)) {
set_cc_op(s, CC_OP_EFLAGS);
}
/* TF handling for the sysret insn is different. The TF bit is
@@ -7273,9 +7347,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_helper_cpuid(cpu_env);
break;
case 0xf4: /* hlt */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ if (check_cpl0(s)) {
gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
@@ -7288,42 +7360,38 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
op = (modrm >> 3) & 7;
switch(op) {
case 0: /* sldt */
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ);
+ gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ);
tcg_gen_ld32u_tl(s->T0, cpu_env,
offsetof(CPUX86State, ldt.selector));
ot = mod == 3 ? dflag : MO_16;
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
break;
case 2: /* lldt */
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
+ if (check_cpl0(s)) {
+ gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_lldt(cpu_env, s->tmp2_i32);
}
break;
case 1: /* str */
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ);
+ gen_svm_check_intercept(s, SVM_EXIT_TR_READ);
tcg_gen_ld32u_tl(s->T0, cpu_env,
offsetof(CPUX86State, tr.selector));
ot = mod == 3 ? dflag : MO_16;
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
break;
case 3: /* ltr */
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
+ if (check_cpl0(s)) {
+ gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_ltr(cpu_env, s->tmp2_i32);
@@ -7331,7 +7399,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 4: /* verr */
case 5: /* verw */
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_update_cc_op(s);
@@ -7351,7 +7419,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
switch (modrm) {
CASE_MODRM_MEM_OP(0): /* sgdt */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
+ gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ);
gen_lea_modrm(env, s, modrm);
tcg_gen_ld32u_tl(s->T0,
cpu_env, offsetof(CPUX86State, gdt.limit));
@@ -7365,7 +7433,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xc8: /* monitor */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
goto illegal_op;
}
gen_update_cc_op(s);
@@ -7377,18 +7445,18 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xc9: /* mwait */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+ if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
goto illegal_op;
}
gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
- gen_eob(s);
+ s->base.is_jmp = DISAS_NORETURN;
break;
case 0xca: /* clac */
if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
- || s->cpl != 0) {
+ || CPL(s) != 0) {
goto illegal_op;
}
gen_helper_clac(cpu_env);
@@ -7398,7 +7466,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xcb: /* stac */
if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
- || s->cpl != 0) {
+ || CPL(s) != 0) {
goto illegal_op;
}
gen_helper_stac(cpu_env);
@@ -7407,7 +7475,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
CASE_MODRM_MEM_OP(1): /* sidt */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
+ gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ);
gen_lea_modrm(env, s, modrm);
tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.limit));
gen_op_st_v(s, MO_16, s->T0, s->A0);
@@ -7436,8 +7504,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
| PREFIX_REPZ | PREFIX_REPNZ))) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
@@ -7450,11 +7517,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xd8: /* VMRUN */
- if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ if (!SVME(s) || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
gen_update_cc_op(s);
@@ -7466,7 +7532,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xd9: /* VMMCALL */
- if (!(s->flags & HF_SVME_MASK)) {
+ if (!SVME(s)) {
goto illegal_op;
}
gen_update_cc_op(s);
@@ -7475,11 +7541,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xda: /* VMLOAD */
- if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ if (!SVME(s) || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
gen_update_cc_op(s);
@@ -7488,11 +7553,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xdb: /* VMSAVE */
- if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ if (!SVME(s) || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
gen_update_cc_op(s);
@@ -7501,13 +7565,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xdc: /* STGI */
- if ((!(s->flags & HF_SVME_MASK)
- && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
- || !s->pe) {
+ if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+ || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
gen_update_cc_op(s);
@@ -7517,11 +7579,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xdd: /* CLGI */
- if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ if (!SVME(s) || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
gen_update_cc_op(s);
@@ -7530,35 +7591,37 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
case 0xde: /* SKINIT */
- if ((!(s->flags & HF_SVME_MASK)
- && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
- || !s->pe) {
+ if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+ || !PE(s)) {
goto illegal_op;
}
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
- gen_helper_skinit(cpu_env);
- break;
+ gen_svm_check_intercept(s, SVM_EXIT_SKINIT);
+ /* If not intercepted, not implemented -- raise #UD. */
+ goto illegal_op;
case 0xdf: /* INVLPGA */
- if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+ if (!SVME(s) || !PE(s)) {
goto illegal_op;
}
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
- gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1));
+ gen_svm_check_intercept(s, SVM_EXIT_INVLPGA);
+ if (s->aflag == MO_64) {
+ tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]);
+ } else {
+ tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]);
+ }
+ gen_helper_flush_page(cpu_env, s->A0);
+ gen_jmp_im(s, s->pc - s->cs_base);
+ gen_eob(s);
break;
CASE_MODRM_MEM_OP(2): /* lgdt */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_WRITE);
+ gen_svm_check_intercept(s, SVM_EXIT_GDTR_WRITE);
gen_lea_modrm(env, s, modrm);
gen_op_ld_v(s, MO_16, s->T1, s->A0);
gen_add_A0_im(s, 2);
@@ -7571,11 +7634,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
CASE_MODRM_MEM_OP(3): /* lidt */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_WRITE);
+ gen_svm_check_intercept(s, SVM_EXIT_IDTR_WRITE);
gen_lea_modrm(env, s, modrm);
gen_op_ld_v(s, MO_16, s->T1, s->A0);
gen_add_A0_im(s, 2);
@@ -7588,7 +7650,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
break;
CASE_MODRM_OP(4): /* smsw */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
+ gen_svm_check_intercept(s, SVM_EXIT_READ_CR0);
tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0]));
/*
* In 32-bit mode, the higher 16 bits of the destination
@@ -7616,27 +7678,33 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64);
break;
+
CASE_MODRM_OP(6): /* lmsw */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+ gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
- gen_helper_lmsw(cpu_env, s->T0);
+ /*
+ * Only the 4 lower bits of CR0 are modified.
+ * PE cannot be set to zero if already set to one.
+ */
+ tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0]));
+ tcg_gen_andi_tl(s->T0, s->T0, 0xf);
+ tcg_gen_andi_tl(s->T1, s->T1, ~0xe);
+ tcg_gen_or_tl(s->T0, s->T0, s->T1);
+ gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0);
gen_jmp_im(s, s->pc - s->cs_base);
gen_eob(s);
break;
CASE_MODRM_MEM_OP(7): /* invlpg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if (!check_cpl0(s)) {
break;
}
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
+ gen_svm_check_intercept(s, SVM_EXIT_INVLPG);
gen_lea_modrm(env, s, modrm);
- gen_helper_invlpg(cpu_env, s->A0);
+ gen_helper_flush_page(cpu_env, s->A0);
gen_jmp_im(s, s->pc - s->cs_base);
gen_eob(s);
break;
@@ -7644,9 +7712,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0xf8: /* swapgs */
#ifdef TARGET_X86_64
if (CODE64(s)) {
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ if (check_cpl0(s)) {
tcg_gen_mov_tl(s->T0, cpu_seg_base[R_GS]);
tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
offsetof(CPUX86State, kernelgsbase));
@@ -7680,10 +7746,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x108: /* invd */
case 0x109: /* wbinvd */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
+ if (check_cpl0(s)) {
+ gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
/* nothing to do */
}
break;
@@ -7695,7 +7759,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
d_ot = dflag;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
mod = (modrm >> 6) & 3;
rm = (modrm & 7) | REX_B(s);
@@ -7717,7 +7781,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
TCGLabel *label1;
TCGv t0, t1, t2, a0;
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
t0 = tcg_temp_local_new();
t1 = tcg_temp_local_new();
@@ -7765,11 +7829,11 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
{
TCGLabel *label1;
TCGv t0;
- if (!s->pe || s->vm86)
+ if (!PE(s) || VM86(s))
goto illegal_op;
ot = dflag != MO_16 ? MO_32 : MO_16;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
t0 = tcg_temp_local_new();
gen_update_cc_op(s);
@@ -7810,7 +7874,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
if (s->flags & HF_MPX_EN_MASK) {
mod = (modrm >> 6) & 3;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (prefixes & PREFIX_REPZ) {
/* bndcl */
if (reg >= 4
@@ -7900,7 +7964,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
if (s->flags & HF_MPX_EN_MASK) {
mod = (modrm >> 6) & 3;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (mod != 3 && (prefixes & PREFIX_REPZ)) {
/* bndmk */
if (reg >= 4
@@ -8002,65 +8066,59 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
gen_nop_modrm(env, s, modrm);
break;
+
case 0x120: /* mov reg, crN */
case 0x122: /* mov crN, reg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- modrm = x86_ldub_code(env, s);
- /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
- * AMD documentation (24594.pdf) and testing of
- * intel 386 and 486 processors all show that the mod bits
- * are assumed to be 1's, regardless of actual values.
- */
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
- if (CODE64(s))
- ot = MO_64;
- else
- ot = MO_32;
- if ((prefixes & PREFIX_LOCK) && (reg == 0) &&
+ if (!check_cpl0(s)) {
+ break;
+ }
+ modrm = x86_ldub_code(env, s);
+ /*
+ * Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of Intel 386 and 486
+ * processors all show that the mod bits are assumed to be 1's,
+ * regardless of actual values.
+ */
+ rm = (modrm & 7) | REX_B(s);
+ reg = ((modrm >> 3) & 7) | REX_R(s);
+ switch (reg) {
+ case 0:
+ if ((prefixes & PREFIX_LOCK) &&
(s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) {
reg = 8;
}
- switch(reg) {
- case 0:
- case 2:
- case 3:
- case 4:
- case 8:
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
- if (b & 2) {
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_op_mov_v_reg(s, ot, s->T0, rm);
- gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
- s->T0);
- gen_jmp_im(s, s->pc - s->cs_base);
- gen_eob(s);
- } else {
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_read_crN(s->T0, cpu_env, tcg_const_i32(reg));
- gen_op_mov_reg_v(s, ot, rm, s->T0);
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_jmp(s, s->pc - s->cs_base);
- }
- }
- break;
- default:
- goto unknown_op;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ goto unknown_op;
+ }
+ ot = (CODE64(s) ? MO_64 : MO_32);
+
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ if (b & 2) {
+ gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg);
+ gen_op_mov_v_reg(s, ot, s->T0, rm);
+ gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0);
+ gen_jmp_im(s, s->pc - s->cs_base);
+ gen_eob(s);
+ } else {
+ gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg);
+ gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg));
+ gen_op_mov_reg_v(s, ot, rm, s->T0);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_jmp(s, s->pc - s->cs_base);
}
}
break;
+
case 0x121: /* mov reg, drN */
case 0x123: /* mov drN, reg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
+ if (check_cpl0(s)) {
modrm = x86_ldub_code(env, s);
/* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
* AMD documentation (24594.pdf) and testing of
@@ -8068,7 +8126,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
* are assumed to be 1's, regardless of actual values.
*/
rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (CODE64(s))
ot = MO_64;
else
@@ -8077,14 +8135,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
goto illegal_op;
}
if (b & 2) {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
+ gen_svm_check_intercept(s, SVM_EXIT_WRITE_DR0 + reg);
gen_op_mov_v_reg(s, ot, s->T0, rm);
tcg_gen_movi_i32(s->tmp2_i32, reg);
gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0);
gen_jmp_im(s, s->pc - s->cs_base);
gen_eob(s);
} else {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg);
+ gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg);
tcg_gen_movi_i32(s->tmp2_i32, reg);
gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32);
gen_op_mov_reg_v(s, ot, rm, s->T0);
@@ -8092,10 +8150,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
}
break;
case 0x106: /* clts */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+ if (check_cpl0(s)) {
+ gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
gen_helper_clts(cpu_env);
/* abort block because static cpu state changed */
gen_jmp_im(s, s->pc - s->cs_base);
@@ -8111,7 +8167,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
/* generate a generic store */
gen_ldst_modrm(env, s, modrm, ot, reg, 1);
break;
@@ -8322,12 +8378,17 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
gen_nop_modrm(env, s, modrm);
break;
case 0x1aa: /* rsm */
- gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM);
+ gen_svm_check_intercept(s, SVM_EXIT_RSM);
if (!(s->flags & HF_SMM_MASK))
goto illegal_op;
+#ifdef CONFIG_USER_ONLY
+ /* we should not be in SMM mode */
+ g_assert_not_reached();
+#else
gen_update_cc_op(s);
gen_jmp_im(s, s->pc - s->cs_base);
gen_helper_rsm(cpu_env);
+#endif /* CONFIG_USER_ONLY */
gen_eob(s);
break;
case 0x1b8: /* SSE4.2 popcnt */
@@ -8338,7 +8399,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
goto illegal_op;
modrm = x86_ldub_code(env, s);
- reg = ((modrm >> 3) & 7) | rex_r;
+ reg = ((modrm >> 3) & 7) | REX_R(s);
if (s->prefix & PREFIX_DATA) {
ot = MO_16;
@@ -8366,7 +8427,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
case 0x1c2:
case 0x1c4 ... 0x1c6:
case 0x1d0 ... 0x1fe:
- gen_sse(env, s, b, pc_start, rex_r);
+ gen_sse(env, s, b, pc_start);
break;
default:
goto unknown_op;
@@ -8466,20 +8527,31 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
DisasContext *dc = container_of(dcbase, DisasContext, base);
CPUX86State *env = cpu->env_ptr;
uint32_t flags = dc->base.tb->flags;
- target_ulong cs_base = dc->base.tb->cs_base;
-
- dc->pe = (flags >> HF_PE_SHIFT) & 1;
- dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
- dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
- dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
- dc->f_st = 0;
- dc->vm86 = (flags >> VM_SHIFT) & 1;
- dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
- dc->iopl = (flags >> IOPL_SHIFT) & 3;
- dc->tf = (flags >> TF_SHIFT) & 1;
+ int cpl = (flags >> HF_CPL_SHIFT) & 3;
+ int iopl = (flags >> IOPL_SHIFT) & 3;
+
+ dc->cs_base = dc->base.tb->cs_base;
+ dc->flags = flags;
+#ifndef CONFIG_USER_ONLY
+ dc->cpl = cpl;
+ dc->iopl = iopl;
+#endif
+
+ /* We make some simplifying assumptions; validate they're correct. */
+ g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0));
+ g_assert(CPL(dc) == cpl);
+ g_assert(IOPL(dc) == iopl);
+ g_assert(VM86(dc) == ((flags & HF_VM_MASK) != 0));
+ g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0));
+ g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0));
+ g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
+ g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
+ g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
+ g_assert(SVME(dc) == ((flags & HF_SVME_MASK) != 0));
+ g_assert(GUEST(dc) == ((flags & HF_GUEST_MASK) != 0));
+
dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_dirty = false;
- dc->cs_base = cs_base;
dc->popl_esp_hack = 0;
/* select memory access functions */
dc->mem_index = 0;
@@ -8492,29 +8564,14 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
-#ifdef TARGET_X86_64
- dc->lma = (flags >> HF_LMA_SHIFT) & 1;
- dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
-#endif
- dc->flags = flags;
- dc->jmp_opt = !(dc->tf || dc->base.singlestep_enabled ||
- (flags & HF_INHIBIT_IRQ_MASK));
- /* Do not optimize repz jumps at all in icount mode, because
- rep movsS instructions are execured with different paths
- in !repz_opt and repz_opt modes. The first one was used
- always except single step mode. And this setting
- disables jumps optimization and control paths become
- equivalent in run and single step modes.
- Now there will be no jump optimization for repz in
- record/replay modes and there will always be an
- additional step for ecx=0 when icount is enabled.
+ dc->jmp_opt = !(dc->base.singlestep_enabled ||
+ (flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)));
+ /*
+ * If jmp_opt, we want to handle each string instruction individually.
+ * For icount also disable repz optimization so that each iteration
+ * is accounted separately.
*/
dc->repz_opt = !dc->jmp_opt && !(tb_cflags(dc->base.tb) & CF_USE_ICOUNT);
-#if 0
- /* check addseg logic */
- if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
- printf("ERROR addseg\n");
-#endif
dc->T0 = tcg_temp_new();
dc->T1 = tcg_temp_new();
@@ -8548,8 +8605,7 @@ static bool i386_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
/* If RF is set, suppress an internally generated breakpoint. */
int flags = dc->base.tb->flags & HF_RF_MASK ? BP_GDB : BP_ANY;
if (bp->flags & flags) {
- gen_debug(dc, dc->base.pc_next - dc->cs_base);
- dc->base.is_jmp = DISAS_NORETURN;
+ gen_debug(dc);
/* The address covered by the breakpoint must be included in
[tb->pc, tb->pc + tb->size) in order to for it to be
properly cleared -- thus we increment the PC here so that
@@ -8578,7 +8634,7 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
pc_next = disas_insn(dc, cpu);
- if (dc->tf || (dc->base.tb->flags & HF_INHIBIT_IRQ_MASK)) {
+ if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
/* if single step mode, we generate only one instruction and
generate an exception */
/* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c
new file mode 100644
index 0000000000..a89b5228fd
--- /dev/null
+++ b/target/i386/tcg/user/excp_helper.c
@@ -0,0 +1,39 @@
+/*
+ * x86 exception helpers - user-mode specific code
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "exec/exec-all.h"
+#include "tcg/helper-tcg.h"
+
+bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ env->cr[2] = addr;
+ env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT;
+ env->error_code |= PG_ERROR_U_MASK;
+ cs->exception_index = EXCP0E_PAGE;
+ env->exception_is_int = 0;
+ env->exception_next_eip = -1;
+ cpu_loop_exit_restore(cs, retaddr);
+}
diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build
new file mode 100644
index 0000000000..1df6bc4343
--- /dev/null
+++ b/target/i386/tcg/user/meson.build
@@ -0,0 +1,4 @@
+i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files(
+ 'excp_helper.c',
+ 'seg_helper.c',
+))
diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c
new file mode 100644
index 0000000000..67481b0aa8
--- /dev/null
+++ b/target/i386/tcg/user/seg_helper.c
@@ -0,0 +1,109 @@
+/*
+ * x86 segmentation related helpers (user-mode code):
+ * TSS, interrupts, system calls, jumps and call/task gates, descriptors
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.1 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 "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "tcg/helper-tcg.h"
+#include "tcg/seg_helper.h"
+
+#ifdef TARGET_X86_64
+void helper_syscall(CPUX86State *env, int next_eip_addend)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = EXCP_SYSCALL;
+ env->exception_is_int = 0;
+ env->exception_next_eip = env->eip + next_eip_addend;
+ cpu_loop_exit(cs);
+}
+#endif /* TARGET_X86_64 */
+
+/*
+ * fake user mode interrupt. is_int is TRUE if coming from the int
+ * instruction. next_eip is the env->eip value AFTER the interrupt
+ * instruction. It is only relevant if is_int is TRUE or if intno
+ * is EXCP_SYSCALL.
+ */
+static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
+ int error_code, target_ulong next_eip)
+{
+ if (is_int) {
+ SegmentCache *dt;
+ target_ulong ptr;
+ int dpl, cpl, shift;
+ uint32_t e2;
+
+ dt = &env->idt;
+ if (env->hflags & HF_LMA_MASK) {
+ shift = 4;
+ } else {
+ shift = 3;
+ }
+ ptr = dt->base + (intno << shift);
+ e2 = cpu_ldl_kernel(env, ptr + 4);
+
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ cpl = env->hflags & HF_CPL_MASK;
+ /* check privilege if software int */
+ if (dpl < cpl) {
+ raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2);
+ }
+ }
+
+ /* Since we emulate only user space, we cannot do more than
+ exiting the emulation with the suitable exception and error
+ code. So update EIP for INT 0x80 and EXCP_SYSCALL. */
+ if (is_int || intno == EXCP_SYSCALL) {
+ env->eip = next_eip;
+ }
+}
+
+void x86_cpu_do_interrupt(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ /* if user mode only, we simulate a fake exception
+ which will be handled outside the cpu execution
+ loop */
+ do_interrupt_user(env, cs->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip);
+ /* successfully delivered */
+ env->old_exception = -1;
+}
+
+void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector)
+{
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ int dpl = (env->eflags & VM_MASK) ? 3 : 0;
+ selector &= 0xffff;
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ (selector << 4), 0xffff,
+ DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
+ DESC_A_MASK | (dpl << DESC_DPL_SHIFT));
+ } else {
+ helper_load_seg(env, seg_reg, selector);
+ }
+}
diff --git a/target/lm32/README b/target/lm32/README
deleted file mode 100644
index ba3508a711..0000000000
--- a/target/lm32/README
+++ /dev/null
@@ -1,45 +0,0 @@
-LatticeMico32 target
---------------------
-
-General
--------
-All opcodes including the JUART CSRs are supported.
-
-
-JTAG UART
----------
-JTAG UART is routed to a serial console device. For the current boards it
-is the second one. Ie to enable it in the qemu virtual console window use
-the following command line parameters:
- -serial vc -serial vc
-This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
-available as virtual consoles.
-
-
-Semihosting
------------
-Semihosting on this target is supported. Some system calls like read, write
-and exit are executed on the host if semihosting is enabled. See
-target/lm32-semi.c for all supported system calls. Emulation aware programs
-can use this mechanism to shut down the virtual machine and print to the
-host console. See the tcg tests for an example.
-
-
-Special instructions
---------------------
-The translation recognizes one special instruction to halt the cpu:
- and r0, r0, r0
-On real hardware this instruction is a nop. It is not used by GCC and
-should (hopefully) not be used within hand-crafted assembly.
-Insert this instruction in your idle loop to reduce the cpu load on the
-host.
-
-
-Ignoring the MSB of the address bus
------------------------------------
-Some SoC ignores the MSB on the address bus. Thus creating a shadow memory
-area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
-0x80000000-0xffffffff is not cached and used to access IO devices. This
-behaviour can be enabled with:
- cpu_lm32_set_phys_msb_ignore(env, 1);
-
diff --git a/target/lm32/TODO b/target/lm32/TODO
deleted file mode 100644
index e163c42ebe..0000000000
--- a/target/lm32/TODO
+++ /dev/null
@@ -1 +0,0 @@
-* linux-user emulation
diff --git a/target/lm32/cpu-param.h b/target/lm32/cpu-param.h
deleted file mode 100644
index d89574ad19..0000000000
--- a/target/lm32/cpu-param.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * LatticeMico32 cpu parameters for qemu.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- * SPDX-License-Identifier: LGPL-2.0+
- */
-
-#ifndef LM32_CPU_PARAM_H
-#define LM32_CPU_PARAM_H 1
-
-#define TARGET_LONG_BITS 32
-#define TARGET_PAGE_BITS 12
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
-#define NB_MMU_MODES 1
-
-#endif
diff --git a/target/lm32/cpu-qom.h b/target/lm32/cpu-qom.h
deleted file mode 100644
index 245b35cd1d..0000000000
--- a/target/lm32/cpu-qom.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * QEMU LatticeMico32 CPU
- *
- * Copyright (c) 2012 SUSE LINUX Products GmbH
- *
- * 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.1 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/lgpl-2.1.html>
- */
-#ifndef QEMU_LM32_CPU_QOM_H
-#define QEMU_LM32_CPU_QOM_H
-
-#include "hw/core/cpu.h"
-#include "qom/object.h"
-
-#define TYPE_LM32_CPU "lm32-cpu"
-
-OBJECT_DECLARE_TYPE(LM32CPU, LM32CPUClass,
- LM32_CPU)
-
-/**
- * LM32CPUClass:
- * @parent_realize: The parent class' realize handler.
- * @parent_reset: The parent class' reset handler.
- *
- * A LatticeMico32 CPU model.
- */
-struct LM32CPUClass {
- /*< private >*/
- CPUClass parent_class;
- /*< public >*/
-
- DeviceRealize parent_realize;
- DeviceReset parent_reset;
-};
-
-
-#endif
diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
deleted file mode 100644
index c23d72874c..0000000000
--- a/target/lm32/cpu.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * QEMU LatticeMico32 CPU
- *
- * Copyright (c) 2012 SUSE LINUX Products GmbH
- *
- * 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.1 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/lgpl-2.1.html>
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/qemu-print.h"
-#include "cpu.h"
-
-
-static void lm32_cpu_set_pc(CPUState *cs, vaddr value)
-{
- LM32CPU *cpu = LM32_CPU(cs);
-
- cpu->env.pc = value;
-}
-
-static void lm32_cpu_list_entry(gpointer data, gpointer user_data)
-{
- ObjectClass *oc = data;
- const char *typename = object_class_get_name(oc);
- char *name;
-
- name = g_strndup(typename, strlen(typename) - strlen(LM32_CPU_TYPE_SUFFIX));
- qemu_printf(" %s\n", name);
- g_free(name);
-}
-
-
-void lm32_cpu_list(void)
-{
- GSList *list;
-
- list = object_class_get_list_sorted(TYPE_LM32_CPU, false);
- qemu_printf("Available CPUs:\n");
- g_slist_foreach(list, lm32_cpu_list_entry, NULL);
- g_slist_free(list);
-}
-
-static void lm32_cpu_init_cfg_reg(LM32CPU *cpu)
-{
- CPULM32State *env = &cpu->env;
- uint32_t cfg = 0;
-
- if (cpu->features & LM32_FEATURE_MULTIPLY) {
- cfg |= CFG_M;
- }
-
- if (cpu->features & LM32_FEATURE_DIVIDE) {
- cfg |= CFG_D;
- }
-
- if (cpu->features & LM32_FEATURE_SHIFT) {
- cfg |= CFG_S;
- }
-
- if (cpu->features & LM32_FEATURE_SIGN_EXTEND) {
- cfg |= CFG_X;
- }
-
- if (cpu->features & LM32_FEATURE_I_CACHE) {
- cfg |= CFG_IC;
- }
-
- if (cpu->features & LM32_FEATURE_D_CACHE) {
- cfg |= CFG_DC;
- }
-
- if (cpu->features & LM32_FEATURE_CYCLE_COUNT) {
- cfg |= CFG_CC;
- }
-
- cfg |= (cpu->num_interrupts << CFG_INT_SHIFT);
- cfg |= (cpu->num_breakpoints << CFG_BP_SHIFT);
- cfg |= (cpu->num_watchpoints << CFG_WP_SHIFT);
- cfg |= (cpu->revision << CFG_REV_SHIFT);
-
- env->cfg = cfg;
-}
-
-static bool lm32_cpu_has_work(CPUState *cs)
-{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
-static void lm32_cpu_reset(DeviceState *dev)
-{
- CPUState *s = CPU(dev);
- LM32CPU *cpu = LM32_CPU(s);
- LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu);
- CPULM32State *env = &cpu->env;
-
- lcc->parent_reset(dev);
-
- /* reset cpu state */
- memset(env, 0, offsetof(CPULM32State, end_reset_fields));
-
- lm32_cpu_init_cfg_reg(cpu);
-}
-
-static void lm32_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
-{
- info->mach = bfd_mach_lm32;
- info->print_insn = print_insn_lm32;
-}
-
-static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)
-{
- CPUState *cs = CPU(dev);
- LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev);
- Error *local_err = NULL;
-
- cpu_exec_realizefn(cs, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- cpu_reset(cs);
-
- qemu_init_vcpu(cs);
-
- lcc->parent_realize(dev, errp);
-}
-
-static void lm32_cpu_initfn(Object *obj)
-{
- LM32CPU *cpu = LM32_CPU(obj);
- CPULM32State *env = &cpu->env;
-
- cpu_set_cpustate_pointers(cpu);
-
- env->flags = 0;
-}
-
-static void lm32_basic_cpu_initfn(Object *obj)
-{
- LM32CPU *cpu = LM32_CPU(obj);
-
- cpu->revision = 3;
- cpu->num_interrupts = 32;
- cpu->num_breakpoints = 4;
- cpu->num_watchpoints = 4;
- cpu->features = LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_CYCLE_COUNT;
-}
-
-static void lm32_standard_cpu_initfn(Object *obj)
-{
- LM32CPU *cpu = LM32_CPU(obj);
-
- cpu->revision = 3;
- cpu->num_interrupts = 32;
- cpu->num_breakpoints = 4;
- cpu->num_watchpoints = 4;
- cpu->features = LM32_FEATURE_MULTIPLY
- | LM32_FEATURE_DIVIDE
- | LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_I_CACHE
- | LM32_FEATURE_CYCLE_COUNT;
-}
-
-static void lm32_full_cpu_initfn(Object *obj)
-{
- LM32CPU *cpu = LM32_CPU(obj);
-
- cpu->revision = 3;
- cpu->num_interrupts = 32;
- cpu->num_breakpoints = 4;
- cpu->num_watchpoints = 4;
- cpu->features = LM32_FEATURE_MULTIPLY
- | LM32_FEATURE_DIVIDE
- | LM32_FEATURE_SHIFT
- | LM32_FEATURE_SIGN_EXTEND
- | LM32_FEATURE_I_CACHE
- | LM32_FEATURE_D_CACHE
- | LM32_FEATURE_CYCLE_COUNT;
-}
-
-static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model)
-{
- ObjectClass *oc;
- char *typename;
-
- typename = g_strdup_printf(LM32_CPU_TYPE_NAME("%s"), cpu_model);
- oc = object_class_by_name(typename);
- g_free(typename);
- if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_LM32_CPU) ||
- object_class_is_abstract(oc))) {
- oc = NULL;
- }
- return oc;
-}
-
-#include "hw/core/tcg-cpu-ops.h"
-
-static struct TCGCPUOps lm32_tcg_ops = {
- .initialize = lm32_translate_init,
- .cpu_exec_interrupt = lm32_cpu_exec_interrupt,
- .tlb_fill = lm32_cpu_tlb_fill,
- .debug_excp_handler = lm32_debug_excp_handler,
-
-#ifndef CONFIG_USER_ONLY
- .do_interrupt = lm32_cpu_do_interrupt,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static void lm32_cpu_class_init(ObjectClass *oc, void *data)
-{
- LM32CPUClass *lcc = LM32_CPU_CLASS(oc);
- CPUClass *cc = CPU_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- device_class_set_parent_realize(dc, lm32_cpu_realizefn,
- &lcc->parent_realize);
- device_class_set_parent_reset(dc, lm32_cpu_reset, &lcc->parent_reset);
-
- cc->class_by_name = lm32_cpu_class_by_name;
- cc->has_work = lm32_cpu_has_work;
- cc->dump_state = lm32_cpu_dump_state;
- cc->set_pc = lm32_cpu_set_pc;
- cc->gdb_read_register = lm32_cpu_gdb_read_register;
- cc->gdb_write_register = lm32_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
- cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
- cc->vmsd = &vmstate_lm32_cpu;
-#endif
- cc->gdb_num_core_regs = 32 + 7;
- cc->gdb_stop_before_watchpoint = true;
- cc->disas_set_info = lm32_cpu_disas_set_info;
- cc->tcg_ops = &lm32_tcg_ops;
-}
-
-#define DEFINE_LM32_CPU_TYPE(cpu_model, initfn) \
- { \
- .parent = TYPE_LM32_CPU, \
- .name = LM32_CPU_TYPE_NAME(cpu_model), \
- .instance_init = initfn, \
- }
-
-static const TypeInfo lm32_cpus_type_infos[] = {
- { /* base class should be registered first */
- .name = TYPE_LM32_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(LM32CPU),
- .instance_init = lm32_cpu_initfn,
- .abstract = true,
- .class_size = sizeof(LM32CPUClass),
- .class_init = lm32_cpu_class_init,
- },
- DEFINE_LM32_CPU_TYPE("lm32-basic", lm32_basic_cpu_initfn),
- DEFINE_LM32_CPU_TYPE("lm32-standard", lm32_standard_cpu_initfn),
- DEFINE_LM32_CPU_TYPE("lm32-full", lm32_full_cpu_initfn),
-};
-
-DEFINE_TYPES(lm32_cpus_type_infos)
diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h
deleted file mode 100644
index ea7c01ca8b..0000000000
--- a/target/lm32/cpu.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * LatticeMico32 virtual CPU header.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef LM32_CPU_H
-#define LM32_CPU_H
-
-#include "cpu-qom.h"
-#include "exec/cpu-defs.h"
-
-typedef struct CPULM32State CPULM32State;
-
-static inline int cpu_mmu_index(CPULM32State *env, bool ifetch)
-{
- return 0;
-}
-
-/* Exceptions indices */
-enum {
- EXCP_RESET = 0,
- EXCP_BREAKPOINT,
- EXCP_INSN_BUS_ERROR,
- EXCP_WATCHPOINT,
- EXCP_DATA_BUS_ERROR,
- EXCP_DIVIDE_BY_ZERO,
- EXCP_IRQ,
- EXCP_SYSTEMCALL
-};
-
-/* Registers */
-enum {
- R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10,
- R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20,
- R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30,
- R_R31
-};
-
-/* Register aliases */
-enum {
- R_GP = R_R26,
- R_FP = R_R27,
- R_SP = R_R28,
- R_RA = R_R29,
- R_EA = R_R30,
- R_BA = R_R31
-};
-
-/* IE flags */
-enum {
- IE_IE = (1<<0),
- IE_EIE = (1<<1),
- IE_BIE = (1<<2),
-};
-
-/* DC flags */
-enum {
- DC_SS = (1<<0),
- DC_RE = (1<<1),
- DC_C0 = (1<<2),
- DC_C1 = (1<<3),
- DC_C2 = (1<<4),
- DC_C3 = (1<<5),
-};
-
-/* CFG mask */
-enum {
- CFG_M = (1<<0),
- CFG_D = (1<<1),
- CFG_S = (1<<2),
- CFG_U = (1<<3),
- CFG_X = (1<<4),
- CFG_CC = (1<<5),
- CFG_IC = (1<<6),
- CFG_DC = (1<<7),
- CFG_G = (1<<8),
- CFG_H = (1<<9),
- CFG_R = (1<<10),
- CFG_J = (1<<11),
- CFG_INT_SHIFT = 12,
- CFG_BP_SHIFT = 18,
- CFG_WP_SHIFT = 22,
- CFG_REV_SHIFT = 26,
-};
-
-/* CSRs */
-enum {
- CSR_IE = 0x00,
- CSR_IM = 0x01,
- CSR_IP = 0x02,
- CSR_ICC = 0x03,
- CSR_DCC = 0x04,
- CSR_CC = 0x05,
- CSR_CFG = 0x06,
- CSR_EBA = 0x07,
- CSR_DC = 0x08,
- CSR_DEBA = 0x09,
- CSR_JTX = 0x0e,
- CSR_JRX = 0x0f,
- CSR_BP0 = 0x10,
- CSR_BP1 = 0x11,
- CSR_BP2 = 0x12,
- CSR_BP3 = 0x13,
- CSR_WP0 = 0x18,
- CSR_WP1 = 0x19,
- CSR_WP2 = 0x1a,
- CSR_WP3 = 0x1b,
-};
-
-enum {
- LM32_FEATURE_MULTIPLY = 1,
- LM32_FEATURE_DIVIDE = 2,
- LM32_FEATURE_SHIFT = 4,
- LM32_FEATURE_SIGN_EXTEND = 8,
- LM32_FEATURE_I_CACHE = 16,
- LM32_FEATURE_D_CACHE = 32,
- LM32_FEATURE_CYCLE_COUNT = 64,
-};
-
-enum {
- LM32_FLAG_IGNORE_MSB = 1,
-};
-
-struct CPULM32State {
- /* general registers */
- uint32_t regs[32];
-
- /* special registers */
- uint32_t pc; /* program counter */
- uint32_t ie; /* interrupt enable */
- uint32_t icc; /* instruction cache control */
- uint32_t dcc; /* data cache control */
- uint32_t cc; /* cycle counter */
- uint32_t cfg; /* configuration */
-
- /* debug registers */
- uint32_t dc; /* debug control */
- uint32_t bp[4]; /* breakpoints */
- uint32_t wp[4]; /* watchpoints */
-
- struct CPUBreakpoint *cpu_breakpoint[4];
- struct CPUWatchpoint *cpu_watchpoint[4];
-
- /* Fields up to this point are cleared by a CPU reset */
- struct {} end_reset_fields;
-
- /* Fields from here on are preserved across CPU reset. */
- uint32_t eba; /* exception base address */
- uint32_t deba; /* debug exception base address */
-
- /* interrupt controller handle for callbacks */
- DeviceState *pic_state;
- /* JTAG UART handle for callbacks */
- DeviceState *juart_state;
-
- /* processor core features */
- uint32_t flags;
-
-};
-
-/**
- * LM32CPU:
- * @env: #CPULM32State
- *
- * A LatticeMico32 CPU.
- */
-struct LM32CPU {
- /*< private >*/
- CPUState parent_obj;
- /*< public >*/
-
- CPUNegativeOffsetState neg;
- CPULM32State env;
-
- uint32_t revision;
- uint8_t num_interrupts;
- uint8_t num_breakpoints;
- uint8_t num_watchpoints;
- uint32_t features;
-};
-
-
-#ifndef CONFIG_USER_ONLY
-extern const VMStateDescription vmstate_lm32_cpu;
-#endif
-
-void lm32_cpu_do_interrupt(CPUState *cpu);
-bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
-void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
-int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-
-typedef enum {
- LM32_WP_DISABLED = 0,
- LM32_WP_READ,
- LM32_WP_WRITE,
- LM32_WP_READ_WRITE,
-} lm32_wp_t;
-
-static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx)
-{
- assert(idx < 4);
- return (dc >> (idx+1)*2) & 0x3;
-}
-
-/* you can call this signal handler from your SIGBUS and SIGSEGV
- signal handlers to inform the virtual CPU of exceptions. non zero
- is returned if the signal was handled by the virtual CPU. */
-int cpu_lm32_signal_handler(int host_signum, void *pinfo,
- void *puc);
-void lm32_cpu_list(void);
-void lm32_translate_init(void);
-void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value);
-void QEMU_NORETURN raise_exception(CPULM32State *env, int index);
-void lm32_debug_excp_handler(CPUState *cs);
-void lm32_breakpoint_insert(CPULM32State *env, int index, target_ulong address);
-void lm32_breakpoint_remove(CPULM32State *env, int index);
-void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
- lm32_wp_t wp_type);
-void lm32_watchpoint_remove(CPULM32State *env, int index);
-bool lm32_cpu_do_semihosting(CPUState *cs);
-
-#define LM32_CPU_TYPE_SUFFIX "-" TYPE_LM32_CPU
-#define LM32_CPU_TYPE_NAME(model) model LM32_CPU_TYPE_SUFFIX
-#define CPU_RESOLVING_TYPE TYPE_LM32_CPU
-
-#define cpu_list lm32_cpu_list
-#define cpu_signal_handler cpu_lm32_signal_handler
-
-bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-
-typedef CPULM32State CPUArchState;
-typedef LM32CPU ArchCPU;
-
-#include "exec/cpu-all.h"
-
-static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc,
- target_ulong *cs_base, uint32_t *flags)
-{
- *pc = env->pc;
- *cs_base = 0;
- *flags = 0;
-}
-
-#endif
diff --git a/target/lm32/gdbstub.c b/target/lm32/gdbstub.c
deleted file mode 100644
index 56f508a5b6..0000000000
--- a/target/lm32/gdbstub.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * LM32 gdb server stub
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- * Copyright (c) 2013 SUSE LINUX Products GmbH
- *
- * 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.1 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 "exec/gdbstub.h"
-#include "hw/lm32/lm32_pic.h"
-
-int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
-
- if (n < 32) {
- return gdb_get_reg32(mem_buf, env->regs[n]);
- } else {
- switch (n) {
- case 32:
- return gdb_get_reg32(mem_buf, env->pc);
- /* FIXME: put in right exception ID */
- case 33:
- return gdb_get_reg32(mem_buf, 0);
- case 34:
- return gdb_get_reg32(mem_buf, env->eba);
- case 35:
- return gdb_get_reg32(mem_buf, env->deba);
- case 36:
- return gdb_get_reg32(mem_buf, env->ie);
- case 37:
- return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state));
- case 38:
- return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state));
- }
- }
- return 0;
-}
-
-int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPUClass *cc = CPU_GET_CLASS(cs);
- CPULM32State *env = &cpu->env;
- uint32_t tmp;
-
- if (n > cc->gdb_num_core_regs) {
- return 0;
- }
-
- tmp = ldl_p(mem_buf);
-
- if (n < 32) {
- env->regs[n] = tmp;
- } else {
- switch (n) {
- case 32:
- env->pc = tmp;
- break;
- case 34:
- env->eba = tmp;
- break;
- case 35:
- env->deba = tmp;
- break;
- case 36:
- env->ie = tmp;
- break;
- case 37:
- lm32_pic_set_im(env->pic_state, tmp);
- break;
- case 38:
- lm32_pic_set_ip(env->pic_state, tmp);
- break;
- }
- }
- return 4;
-}
diff --git a/target/lm32/helper.c b/target/lm32/helper.c
deleted file mode 100644
index 01cc3c53a5..0000000000
--- a/target/lm32/helper.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * LatticeMico32 helper routines.
- *
- * Copyright (c) 2010-2014 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "exec/exec-all.h"
-#include "qemu/host-utils.h"
-#include "semihosting/semihost.h"
-#include "exec/log.h"
-
-bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
- int prot;
-
- address &= TARGET_PAGE_MASK;
- prot = PAGE_BITS;
- if (env->flags & LM32_FLAG_IGNORE_MSB) {
- tlb_set_page(cs, address, address & 0x7fffffff, prot, mmu_idx,
- TARGET_PAGE_SIZE);
- } else {
- tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
- }
- return true;
-}
-
-hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- LM32CPU *cpu = LM32_CPU(cs);
-
- addr &= TARGET_PAGE_MASK;
- if (cpu->env.flags & LM32_FLAG_IGNORE_MSB) {
- return addr & 0x7fffffff;
- } else {
- return addr;
- }
-}
-
-void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address)
-{
- cpu_breakpoint_insert(env_cpu(env), address, BP_CPU,
- &env->cpu_breakpoint[idx]);
-}
-
-void lm32_breakpoint_remove(CPULM32State *env, int idx)
-{
- if (!env->cpu_breakpoint[idx]) {
- return;
- }
-
- cpu_breakpoint_remove_by_ref(env_cpu(env), env->cpu_breakpoint[idx]);
- env->cpu_breakpoint[idx] = NULL;
-}
-
-void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address,
- lm32_wp_t wp_type)
-{
- int flags = 0;
-
- switch (wp_type) {
- case LM32_WP_DISABLED:
- /* nothing to do */
- break;
- case LM32_WP_READ:
- flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_READ;
- break;
- case LM32_WP_WRITE:
- flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_WRITE;
- break;
- case LM32_WP_READ_WRITE:
- flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_ACCESS;
- break;
- }
-
- if (flags != 0) {
- cpu_watchpoint_insert(env_cpu(env), address, 1, flags,
- &env->cpu_watchpoint[idx]);
- }
-}
-
-void lm32_watchpoint_remove(CPULM32State *env, int idx)
-{
- if (!env->cpu_watchpoint[idx]) {
- return;
- }
-
- cpu_watchpoint_remove_by_ref(env_cpu(env), env->cpu_watchpoint[idx]);
- env->cpu_watchpoint[idx] = NULL;
-}
-
-static bool check_watchpoints(CPULM32State *env)
-{
- LM32CPU *cpu = env_archcpu(env);
- int i;
-
- for (i = 0; i < cpu->num_watchpoints; i++) {
- if (env->cpu_watchpoint[i] &&
- env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
- return true;
- }
- }
- return false;
-}
-
-void lm32_debug_excp_handler(CPUState *cs)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
- CPUBreakpoint *bp;
-
- if (cs->watchpoint_hit) {
- if (cs->watchpoint_hit->flags & BP_CPU) {
- cs->watchpoint_hit = NULL;
- if (check_watchpoints(env)) {
- raise_exception(env, EXCP_WATCHPOINT);
- } else {
- cpu_loop_exit_noexc(cs);
- }
- }
- } else {
- QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
- if (bp->pc == env->pc) {
- if (bp->flags & BP_CPU) {
- raise_exception(env, EXCP_BREAKPOINT);
- }
- break;
- }
- }
- }
-}
-
-void lm32_cpu_do_interrupt(CPUState *cs)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
-
- qemu_log_mask(CPU_LOG_INT,
- "exception at pc=%x type=%x\n", env->pc, cs->exception_index);
-
- switch (cs->exception_index) {
- case EXCP_SYSTEMCALL:
- if (unlikely(semihosting_enabled())) {
- /* do_semicall() returns true if call was handled. Otherwise
- * do the normal exception handling. */
- if (lm32_cpu_do_semihosting(cs)) {
- env->pc += 4;
- break;
- }
- }
- /* fall through */
- case EXCP_INSN_BUS_ERROR:
- case EXCP_DATA_BUS_ERROR:
- case EXCP_DIVIDE_BY_ZERO:
- case EXCP_IRQ:
- /* non-debug exceptions */
- env->regs[R_EA] = env->pc;
- env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
- env->ie &= ~IE_IE;
- if (env->dc & DC_RE) {
- env->pc = env->deba + (cs->exception_index * 32);
- } else {
- env->pc = env->eba + (cs->exception_index * 32);
- }
- log_cpu_state_mask(CPU_LOG_INT, cs, 0);
- break;
- case EXCP_BREAKPOINT:
- case EXCP_WATCHPOINT:
- /* debug exceptions */
- env->regs[R_BA] = env->pc;
- env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
- env->ie &= ~IE_IE;
- env->pc = env->deba + (cs->exception_index * 32);
- log_cpu_state_mask(CPU_LOG_INT, cs, 0);
- break;
- default:
- cpu_abort(cs, "unhandled exception type=%d\n",
- cs->exception_index);
- break;
- }
-}
-
-bool lm32_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
-
- if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->ie & IE_IE)) {
- cs->exception_index = EXCP_IRQ;
- lm32_cpu_do_interrupt(cs);
- return true;
- }
- return false;
-}
-
-/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
- * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
- * 0x80000000-0xffffffff is not cached and used to access IO devices. */
-void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value)
-{
- if (value) {
- env->flags |= LM32_FLAG_IGNORE_MSB;
- } else {
- env->flags &= ~LM32_FLAG_IGNORE_MSB;
- }
-}
diff --git a/target/lm32/helper.h b/target/lm32/helper.h
deleted file mode 100644
index 445578c439..0000000000
--- a/target/lm32/helper.h
+++ /dev/null
@@ -1,14 +0,0 @@
-DEF_HELPER_2(raise_exception, void, env, i32)
-DEF_HELPER_1(hlt, void, env)
-DEF_HELPER_3(wcsr_bp, void, env, i32, i32)
-DEF_HELPER_3(wcsr_wp, void, env, i32, i32)
-DEF_HELPER_2(wcsr_dc, void, env, i32)
-DEF_HELPER_2(wcsr_im, void, env, i32)
-DEF_HELPER_2(wcsr_ip, void, env, i32)
-DEF_HELPER_2(wcsr_jtx, void, env, i32)
-DEF_HELPER_2(wcsr_jrx, void, env, i32)
-DEF_HELPER_1(rcsr_im, i32, env)
-DEF_HELPER_1(rcsr_ip, i32, env)
-DEF_HELPER_1(rcsr_jtx, i32, env)
-DEF_HELPER_1(rcsr_jrx, i32, env)
-DEF_HELPER_1(ill, void, env)
diff --git a/target/lm32/lm32-semi.c b/target/lm32/lm32-semi.c
deleted file mode 100644
index 661a770249..0000000000
--- a/target/lm32/lm32-semi.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Lattice Mico32 semihosting syscall interface
- *
- * Copyright (c) 2014 Michael Walle <michael@walle.cc>
- *
- * Based on target/m68k/m68k-semi.c, which is
- * Copyright (c) 2005-2007 CodeSourcery.
- *
- * 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 "cpu.h"
-#include "exec/helper-proto.h"
-#include "exec/softmmu-semi.h"
-
-enum {
- TARGET_SYS_exit = 1,
- TARGET_SYS_open = 2,
- TARGET_SYS_close = 3,
- TARGET_SYS_read = 4,
- TARGET_SYS_write = 5,
- TARGET_SYS_lseek = 6,
- TARGET_SYS_fstat = 10,
- TARGET_SYS_stat = 15,
-};
-
-enum {
- NEWLIB_O_RDONLY = 0x0,
- NEWLIB_O_WRONLY = 0x1,
- NEWLIB_O_RDWR = 0x2,
- NEWLIB_O_APPEND = 0x8,
- NEWLIB_O_CREAT = 0x200,
- NEWLIB_O_TRUNC = 0x400,
- NEWLIB_O_EXCL = 0x800,
-};
-
-static int translate_openflags(int flags)
-{
- int hf;
-
- if (flags & NEWLIB_O_WRONLY) {
- hf = O_WRONLY;
- } else if (flags & NEWLIB_O_RDWR) {
- hf = O_RDWR;
- } else {
- hf = O_RDONLY;
- }
-
- if (flags & NEWLIB_O_APPEND) {
- hf |= O_APPEND;
- }
-
- if (flags & NEWLIB_O_CREAT) {
- hf |= O_CREAT;
- }
-
- if (flags & NEWLIB_O_TRUNC) {
- hf |= O_TRUNC;
- }
-
- if (flags & NEWLIB_O_EXCL) {
- hf |= O_EXCL;
- }
-
- return hf;
-}
-
-struct newlib_stat {
- int16_t newlib_st_dev; /* device */
- uint16_t newlib_st_ino; /* inode */
- uint16_t newlib_st_mode; /* protection */
- uint16_t newlib_st_nlink; /* number of hard links */
- uint16_t newlib_st_uid; /* user ID of owner */
- uint16_t newlib_st_gid; /* group ID of owner */
- int16_t newlib_st_rdev; /* device type (if inode device) */
- int32_t newlib_st_size; /* total size, in bytes */
- int32_t newlib_st_atime; /* time of last access */
- uint32_t newlib_st_spare1;
- int32_t newlib_st_mtime; /* time of last modification */
- uint32_t newlib_st_spare2;
- int32_t newlib_st_ctime; /* time of last change */
- uint32_t newlib_st_spare3;
-} QEMU_PACKED;
-
-static int translate_stat(CPULM32State *env, target_ulong addr,
- struct stat *s)
-{
- struct newlib_stat *p;
-
- p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0);
- if (!p) {
- return 0;
- }
- p->newlib_st_dev = cpu_to_be16(s->st_dev);
- p->newlib_st_ino = cpu_to_be16(s->st_ino);
- p->newlib_st_mode = cpu_to_be16(s->st_mode);
- p->newlib_st_nlink = cpu_to_be16(s->st_nlink);
- p->newlib_st_uid = cpu_to_be16(s->st_uid);
- p->newlib_st_gid = cpu_to_be16(s->st_gid);
- p->newlib_st_rdev = cpu_to_be16(s->st_rdev);
- p->newlib_st_size = cpu_to_be32(s->st_size);
- p->newlib_st_atime = cpu_to_be32(s->st_atime);
- p->newlib_st_mtime = cpu_to_be32(s->st_mtime);
- p->newlib_st_ctime = cpu_to_be32(s->st_ctime);
- unlock_user(p, addr, sizeof(struct newlib_stat));
-
- return 1;
-}
-
-bool lm32_cpu_do_semihosting(CPUState *cs)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
-
- int ret = -1;
- target_ulong nr, arg0, arg1, arg2;
- void *p;
- struct stat s;
-
- nr = env->regs[R_R8];
- arg0 = env->regs[R_R1];
- arg1 = env->regs[R_R2];
- arg2 = env->regs[R_R3];
-
- switch (nr) {
- case TARGET_SYS_exit:
- /* void _exit(int rc) */
- exit(arg0);
-
- case TARGET_SYS_open:
- /* int open(const char *pathname, int flags) */
- p = lock_user_string(arg0);
- if (!p) {
- ret = -1;
- } else {
- ret = open(p, translate_openflags(arg2));
- unlock_user(p, arg0, 0);
- }
- break;
-
- case TARGET_SYS_read:
- /* ssize_t read(int fd, const void *buf, size_t count) */
- p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
- if (!p) {
- ret = -1;
- } else {
- ret = read(arg0, p, arg2);
- unlock_user(p, arg1, arg2);
- }
- break;
-
- case TARGET_SYS_write:
- /* ssize_t write(int fd, const void *buf, size_t count) */
- p = lock_user(VERIFY_READ, arg1, arg2, 1);
- if (!p) {
- ret = -1;
- } else {
- ret = write(arg0, p, arg2);
- unlock_user(p, arg1, 0);
- }
- break;
-
- case TARGET_SYS_close:
- /* int close(int fd) */
- /* don't close stdin/stdout/stderr */
- if (arg0 > 2) {
- ret = close(arg0);
- } else {
- ret = 0;
- }
- break;
-
- case TARGET_SYS_lseek:
- /* off_t lseek(int fd, off_t offset, int whence */
- ret = lseek(arg0, arg1, arg2);
- break;
-
- case TARGET_SYS_stat:
- /* int stat(const char *path, struct stat *buf) */
- p = lock_user_string(arg0);
- if (!p) {
- ret = -1;
- } else {
- ret = stat(p, &s);
- unlock_user(p, arg0, 0);
- if (translate_stat(env, arg1, &s) == 0) {
- ret = -1;
- }
- }
- break;
-
- case TARGET_SYS_fstat:
- /* int stat(int fd, struct stat *buf) */
- ret = fstat(arg0, &s);
- if (ret == 0) {
- if (translate_stat(env, arg1, &s) == 0) {
- ret = -1;
- }
- }
- break;
-
- default:
- /* unhandled */
- return false;
- }
-
- env->regs[R_R1] = ret;
- return true;
-}
diff --git a/target/lm32/machine.c b/target/lm32/machine.c
deleted file mode 100644
index 365eaa2e47..0000000000
--- a/target/lm32/machine.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "migration/cpu.h"
-
-static const VMStateDescription vmstate_env = {
- .name = "env",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, CPULM32State, 32),
- VMSTATE_UINT32(pc, CPULM32State),
- VMSTATE_UINT32(ie, CPULM32State),
- VMSTATE_UINT32(icc, CPULM32State),
- VMSTATE_UINT32(dcc, CPULM32State),
- VMSTATE_UINT32(cc, CPULM32State),
- VMSTATE_UINT32(eba, CPULM32State),
- VMSTATE_UINT32(dc, CPULM32State),
- VMSTATE_UINT32(deba, CPULM32State),
- VMSTATE_UINT32_ARRAY(bp, CPULM32State, 4),
- VMSTATE_UINT32_ARRAY(wp, CPULM32State, 4),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_lm32_cpu = {
- .name = "cpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/target/lm32/meson.build b/target/lm32/meson.build
deleted file mode 100644
index ef0eef07f1..0000000000
--- a/target/lm32/meson.build
+++ /dev/null
@@ -1,15 +0,0 @@
-lm32_ss = ss.source_set()
-lm32_ss.add(files(
- 'cpu.c',
- 'gdbstub.c',
- 'helper.c',
- 'lm32-semi.c',
- 'op_helper.c',
- 'translate.c',
-))
-
-lm32_softmmu_ss = ss.source_set()
-lm32_softmmu_ss.add(files('machine.c'))
-
-target_arch += {'lm32': lm32_ss}
-target_softmmu_arch += {'lm32': lm32_softmmu_ss}
diff --git a/target/lm32/op_helper.c b/target/lm32/op_helper.c
deleted file mode 100644
index e39fcd5647..0000000000
--- a/target/lm32/op_helper.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-#include "qemu/host-utils.h"
-#include "qemu/main-loop.h"
-#include "sysemu/runstate.h"
-
-#include "hw/lm32/lm32_pic.h"
-#include "hw/char/lm32_juart.h"
-
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-
-#ifndef CONFIG_USER_ONLY
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-void raise_exception(CPULM32State *env, int index)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = index;
- cpu_loop_exit(cs);
-}
-
-void HELPER(raise_exception)(CPULM32State *env, uint32_t index)
-{
- raise_exception(env, index);
-}
-
-void HELPER(hlt)(CPULM32State *env)
-{
- CPUState *cs = env_cpu(env);
-
- cs->halted = 1;
- cs->exception_index = EXCP_HLT;
- cpu_loop_exit(cs);
-}
-
-void HELPER(ill)(CPULM32State *env)
-{
-#ifndef CONFIG_USER_ONLY
- CPUState *cs = env_cpu(env);
- fprintf(stderr, "VM paused due to illegal instruction. "
- "Connect a debugger or switch to the monitor console "
- "to find out more.\n");
- vm_stop(RUN_STATE_PAUSED);
- cs->halted = 1;
- raise_exception(env, EXCP_HALTED);
-#endif
-}
-
-void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx)
-{
- uint32_t addr = bp & ~1;
-
- assert(idx < 4);
-
- env->bp[idx] = bp;
- lm32_breakpoint_remove(env, idx);
- if (bp & 1) {
- lm32_breakpoint_insert(env, idx, addr);
- }
-}
-
-void HELPER(wcsr_wp)(CPULM32State *env, uint32_t wp, uint32_t idx)
-{
- lm32_wp_t wp_type;
-
- assert(idx < 4);
-
- env->wp[idx] = wp;
-
- wp_type = lm32_wp_type(env->dc, idx);
- lm32_watchpoint_remove(env, idx);
- if (wp_type != LM32_WP_DISABLED) {
- lm32_watchpoint_insert(env, idx, wp, wp_type);
- }
-}
-
-void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc)
-{
- uint32_t old_dc;
- int i;
- lm32_wp_t old_type;
- lm32_wp_t new_type;
-
- old_dc = env->dc;
- env->dc = dc;
-
- for (i = 0; i < 4; i++) {
- old_type = lm32_wp_type(old_dc, i);
- new_type = lm32_wp_type(dc, i);
-
- if (old_type != new_type) {
- lm32_watchpoint_remove(env, i);
- if (new_type != LM32_WP_DISABLED) {
- lm32_watchpoint_insert(env, i, env->wp[i], new_type);
- }
- }
- }
-}
-
-void HELPER(wcsr_im)(CPULM32State *env, uint32_t im)
-{
- qemu_mutex_lock_iothread();
- lm32_pic_set_im(env->pic_state, im);
- qemu_mutex_unlock_iothread();
-}
-
-void HELPER(wcsr_ip)(CPULM32State *env, uint32_t im)
-{
- qemu_mutex_lock_iothread();
- lm32_pic_set_ip(env->pic_state, im);
- qemu_mutex_unlock_iothread();
-}
-
-void HELPER(wcsr_jtx)(CPULM32State *env, uint32_t jtx)
-{
- lm32_juart_set_jtx(env->juart_state, jtx);
-}
-
-void HELPER(wcsr_jrx)(CPULM32State *env, uint32_t jrx)
-{
- lm32_juart_set_jrx(env->juart_state, jrx);
-}
-
-uint32_t HELPER(rcsr_im)(CPULM32State *env)
-{
- return lm32_pic_get_im(env->pic_state);
-}
-
-uint32_t HELPER(rcsr_ip)(CPULM32State *env)
-{
- return lm32_pic_get_ip(env->pic_state);
-}
-
-uint32_t HELPER(rcsr_jtx)(CPULM32State *env)
-{
- return lm32_juart_get_jtx(env->juart_state);
-}
-
-uint32_t HELPER(rcsr_jrx)(CPULM32State *env)
-{
- return lm32_juart_get_jrx(env->juart_state);
-}
-#endif
-
diff --git a/target/lm32/translate.c b/target/lm32/translate.c
deleted file mode 100644
index 20c70d03f1..0000000000
--- a/target/lm32/translate.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*
- * LatticeMico32 main translation routines.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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.1 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 "disas/disas.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-#include "exec/translator.h"
-#include "tcg/tcg-op.h"
-#include "qemu/qemu-print.h"
-
-#include "exec/cpu_ldst.h"
-#include "hw/lm32/lm32_pic.h"
-
-#include "exec/helper-gen.h"
-
-#include "trace-tcg.h"
-#include "exec/log.h"
-
-
-#define DISAS_LM32 0
-
-#define LOG_DIS(...) \
- do { \
- if (DISAS_LM32) { \
- qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \
- } \
- } while (0)
-
-#define EXTRACT_FIELD(src, start, end) \
- (((src) >> start) & ((1 << (end - start + 1)) - 1))
-
-#define MEM_INDEX 0
-
-/* is_jmp field values */
-#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
-#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
-#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
-
-static TCGv cpu_R[32];
-static TCGv cpu_pc;
-static TCGv cpu_ie;
-static TCGv cpu_icc;
-static TCGv cpu_dcc;
-static TCGv cpu_cc;
-static TCGv cpu_cfg;
-static TCGv cpu_eba;
-static TCGv cpu_dc;
-static TCGv cpu_deba;
-static TCGv cpu_bp[4];
-static TCGv cpu_wp[4];
-
-#include "exec/gen-icount.h"
-
-enum {
- OP_FMT_RI,
- OP_FMT_RR,
- OP_FMT_CR,
- OP_FMT_I
-};
-
-/* This is the state at translation time. */
-typedef struct DisasContext {
- target_ulong pc;
-
- /* Decoder. */
- int format;
- uint32_t ir;
- uint8_t opcode;
- uint8_t r0, r1, r2, csr;
- uint16_t imm5;
- uint16_t imm16;
- uint32_t imm26;
-
- unsigned int delayed_branch;
- unsigned int tb_flags, synced_flags; /* tb dependent flags. */
- int is_jmp;
-
- TranslationBlock *tb;
- int singlestep_enabled;
-
- uint32_t features;
- uint8_t num_breakpoints;
- uint8_t num_watchpoints;
-} DisasContext;
-
-static const char *regnames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26/gp", "r27/fp", "r28/sp", "r29/ra",
- "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0",
- "wp1", "wp2", "wp3"
-};
-
-static inline int zero_extend(unsigned int val, int width)
-{
- return val & ((1 << width) - 1);
-}
-
-static inline int sign_extend(unsigned int val, int width)
-{
- int sval;
-
- /* LSL. */
- val <<= 32 - width;
- sval = val;
- /* ASR. */
- sval >>= 32 - width;
-
- return sval;
-}
-
-static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
-{
- TCGv_i32 tmp = tcg_const_i32(index);
-
- gen_helper_raise_exception(cpu_env, tmp);
- tcg_temp_free_i32(tmp);
-}
-
-static inline void t_gen_illegal_insn(DisasContext *dc)
-{
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- gen_helper_ill(cpu_env);
-}
-
-static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
-{
- if (unlikely(dc->singlestep_enabled)) {
- return false;
- }
-
-#ifndef CONFIG_USER_ONLY
- return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
-#else
- return true;
-#endif
-}
-
-static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
-{
- if (use_goto_tb(dc, dest)) {
- tcg_gen_goto_tb(n);
- tcg_gen_movi_tl(cpu_pc, dest);
- tcg_gen_exit_tb(dc->tb, n);
- } else {
- tcg_gen_movi_tl(cpu_pc, dest);
- if (dc->singlestep_enabled) {
- t_gen_raise_exception(dc, EXCP_DEBUG);
- }
- tcg_gen_exit_tb(NULL, 0);
- }
-}
-
-static void dec_add(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- if (dc->r0 == R_R0) {
- if (dc->r1 == R_R0 && dc->imm16 == 0) {
- LOG_DIS("nop\n");
- } else {
- LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16));
- }
- } else {
- LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- }
- } else {
- LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- sign_extend(dc->imm16, 16));
- } else {
- tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_and(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- zero_extend(dc->imm16, 16));
- } else {
- if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) {
- tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
- gen_helper_hlt(cpu_env);
- } else {
- tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
- }
-}
-
-static void dec_andhi(DisasContext *dc)
-{
- LOG_DIS("andhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
-
- tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
-}
-
-static void dec_b(DisasContext *dc)
-{
- if (dc->r0 == R_RA) {
- LOG_DIS("ret\n");
- } else if (dc->r0 == R_EA) {
- LOG_DIS("eret\n");
- } else if (dc->r0 == R_BA) {
- LOG_DIS("bret\n");
- } else {
- LOG_DIS("b r%d\n", dc->r0);
- }
-
- /* restore IE.IE in case of an eret */
- if (dc->r0 == R_EA) {
- TCGv t0 = tcg_temp_new();
- TCGLabel *l1 = gen_new_label();
- tcg_gen_andi_tl(t0, cpu_ie, IE_EIE);
- tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1);
- tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
- gen_set_label(l1);
- tcg_temp_free(t0);
- } else if (dc->r0 == R_BA) {
- TCGv t0 = tcg_temp_new();
- TCGLabel *l1 = gen_new_label();
- tcg_gen_andi_tl(t0, cpu_ie, IE_BIE);
- tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1);
- tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
- gen_set_label(l1);
- tcg_temp_free(t0);
- }
- tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
-
- dc->is_jmp = DISAS_JUMP;
-}
-
-static void dec_bi(DisasContext *dc)
-{
- LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26));
-
- gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
-
- dc->is_jmp = DISAS_TB_JUMP;
-}
-
-static inline void gen_cond_branch(DisasContext *dc, int cond)
-{
- TCGLabel *l1 = gen_new_label();
- tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1);
- gen_goto_tb(dc, 0, dc->pc + 4);
- gen_set_label(l1);
- gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16)));
- dc->is_jmp = DISAS_TB_JUMP;
-}
-
-static void dec_be(DisasContext *dc)
-{
- LOG_DIS("be r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16) * 4);
-
- gen_cond_branch(dc, TCG_COND_EQ);
-}
-
-static void dec_bg(DisasContext *dc)
-{
- LOG_DIS("bg r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16 * 4));
-
- gen_cond_branch(dc, TCG_COND_GT);
-}
-
-static void dec_bge(DisasContext *dc)
-{
- LOG_DIS("bge r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16) * 4);
-
- gen_cond_branch(dc, TCG_COND_GE);
-}
-
-static void dec_bgeu(DisasContext *dc)
-{
- LOG_DIS("bgeu r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16) * 4);
-
- gen_cond_branch(dc, TCG_COND_GEU);
-}
-
-static void dec_bgu(DisasContext *dc)
-{
- LOG_DIS("bgu r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16) * 4);
-
- gen_cond_branch(dc, TCG_COND_GTU);
-}
-
-static void dec_bne(DisasContext *dc)
-{
- LOG_DIS("bne r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16) * 4);
-
- gen_cond_branch(dc, TCG_COND_NE);
-}
-
-static void dec_call(DisasContext *dc)
-{
- LOG_DIS("call r%d\n", dc->r0);
-
- tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
- tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
-
- dc->is_jmp = DISAS_JUMP;
-}
-
-static void dec_calli(DisasContext *dc)
-{
- LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4);
-
- tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
- gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
-
- dc->is_jmp = DISAS_TB_JUMP;
-}
-
-static inline void gen_compare(DisasContext *dc, int cond)
-{
- int i;
-
- if (dc->format == OP_FMT_RI) {
- switch (cond) {
- case TCG_COND_GEU:
- case TCG_COND_GTU:
- i = zero_extend(dc->imm16, 16);
- break;
- default:
- i = sign_extend(dc->imm16, 16);
- break;
- }
-
- tcg_gen_setcondi_tl(cond, cpu_R[dc->r1], cpu_R[dc->r0], i);
- } else {
- tcg_gen_setcond_tl(cond, cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_cmpe(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpei r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_EQ);
-}
-
-static void dec_cmpg(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_GT);
-}
-
-static void dec_cmpge(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_GE);
-}
-
-static void dec_cmpgeu(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_GEU);
-}
-
-static void dec_cmpgu(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_GTU);
-}
-
-static void dec_cmpne(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- } else {
- LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- gen_compare(dc, TCG_COND_NE);
-}
-
-static void dec_divu(DisasContext *dc)
-{
- TCGLabel *l1;
-
- LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
-
- if (!(dc->features & LM32_FEATURE_DIVIDE)) {
- qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- l1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
- gen_set_label(l1);
- tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
-}
-
-static void dec_lb(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_lbu(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_lh(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_lhu(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_lw(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16));
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_modu(DisasContext *dc)
-{
- TCGLabel *l1;
-
- LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
-
- if (!(dc->features & LM32_FEATURE_DIVIDE)) {
- qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- l1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
- gen_set_label(l1);
- tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
-}
-
-static void dec_mul(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("muli r%d, r%d, %d\n", dc->r1, dc->r0,
- sign_extend(dc->imm16, 16));
- } else {
- LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (!(dc->features & LM32_FEATURE_MULTIPLY)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "hardware multiplier is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- sign_extend(dc->imm16, 16));
- } else {
- tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_nor(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("nori r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (dc->format == OP_FMT_RI) {
- TCGv t0 = tcg_temp_new();
- tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16));
- tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0);
- tcg_temp_free(t0);
- } else {
- tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_or(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- if (dc->r1 == R_R0) {
- LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0);
- } else {
- LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- zero_extend(dc->imm16, 16));
- } else {
- tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_orhi(DisasContext *dc)
-{
- if (dc->r0 == R_R0) {
- LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16);
- } else {
- LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
- }
-
- tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
-}
-
-static void dec_scall(DisasContext *dc)
-{
- switch (dc->imm5) {
- case 2:
- LOG_DIS("break\n");
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_BREAKPOINT);
- break;
- case 7:
- LOG_DIS("scall\n");
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc);
- t_gen_illegal_insn(dc);
- break;
- }
-}
-
-static void dec_rcsr(DisasContext *dc)
-{
- LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr);
-
- switch (dc->csr) {
- case CSR_IE:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie);
- break;
- case CSR_IM:
- gen_helper_rcsr_im(cpu_R[dc->r2], cpu_env);
- break;
- case CSR_IP:
- gen_helper_rcsr_ip(cpu_R[dc->r2], cpu_env);
- break;
- case CSR_CC:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc);
- break;
- case CSR_CFG:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg);
- break;
- case CSR_EBA:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba);
- break;
- case CSR_DC:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc);
- break;
- case CSR_DEBA:
- tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba);
- break;
- case CSR_JTX:
- gen_helper_rcsr_jtx(cpu_R[dc->r2], cpu_env);
- break;
- case CSR_JRX:
- gen_helper_rcsr_jrx(cpu_R[dc->r2], cpu_env);
- break;
- case CSR_ICC:
- case CSR_DCC:
- case CSR_BP0:
- case CSR_BP1:
- case CSR_BP2:
- case CSR_BP3:
- case CSR_WP0:
- case CSR_WP1:
- case CSR_WP2:
- case CSR_WP3:
- qemu_log_mask(LOG_GUEST_ERROR, "invalid read access csr=%x\n", dc->csr);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "read_csr: unknown csr=%x\n", dc->csr);
- break;
- }
-}
-
-static void dec_sb(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_sextb(DisasContext *dc)
-{
- LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
-
- if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "hardware sign extender is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
-}
-
-static void dec_sexth(DisasContext *dc)
-{
- LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
-
- if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "hardware sign extender is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
-}
-
-static void dec_sh(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_sl(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
- } else {
- LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (!(dc->features & LM32_FEATURE_SHIFT)) {
- qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
- } else {
- TCGv t0 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
- tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
- tcg_temp_free(t0);
- }
-}
-
-static void dec_sr(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
- } else {
- LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- /* The real CPU (w/o hardware shifter) only supports right shift by exactly
- * one bit */
- if (dc->format == OP_FMT_RI) {
- if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "hardware shifter is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
- tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
- } else {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_local_new();
- tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
-
- if (!(dc->features & LM32_FEATURE_SHIFT)) {
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1);
- t_gen_illegal_insn(dc);
- tcg_gen_br(l2);
- }
-
- gen_set_label(l1);
- tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
- gen_set_label(l2);
-
- tcg_temp_free(t0);
- }
-}
-
-static void dec_sru(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
- } else {
- LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (dc->format == OP_FMT_RI) {
- if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "hardware shifter is not available\n");
- t_gen_illegal_insn(dc);
- return;
- }
- tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
- } else {
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_local_new();
- tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
-
- if (!(dc->features & LM32_FEATURE_SHIFT)) {
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1);
- t_gen_illegal_insn(dc);
- tcg_gen_br(l2);
- }
-
- gen_set_label(l1);
- tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
- gen_set_label(l2);
-
- tcg_temp_free(t0);
- }
-}
-
-static void dec_sub(DisasContext *dc)
-{
- LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
-
- tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
-}
-
-static void dec_sw(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1);
-
- t0 = tcg_temp_new();
- tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
- tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX);
- tcg_temp_free(t0);
-}
-
-static void dec_user(DisasContext *dc)
-{
- LOG_DIS("user");
-
- qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n");
- t_gen_illegal_insn(dc);
-}
-
-static void dec_wcsr(DisasContext *dc)
-{
- int no;
-
- LOG_DIS("wcsr %d, r%d\n", dc->csr, dc->r1);
-
- switch (dc->csr) {
- case CSR_IE:
- tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]);
- tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
- dc->is_jmp = DISAS_UPDATE;
- break;
- case CSR_IM:
- /* mark as an io operation because it could cause an interrupt */
- if (tb_cflags(dc->tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_wcsr_im(cpu_env, cpu_R[dc->r1]);
- tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
- dc->is_jmp = DISAS_UPDATE;
- break;
- case CSR_IP:
- /* mark as an io operation because it could cause an interrupt */
- if (tb_cflags(dc->tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_wcsr_ip(cpu_env, cpu_R[dc->r1]);
- tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
- dc->is_jmp = DISAS_UPDATE;
- break;
- case CSR_ICC:
- /* TODO */
- break;
- case CSR_DCC:
- /* TODO */
- break;
- case CSR_EBA:
- tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]);
- break;
- case CSR_DEBA:
- tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]);
- break;
- case CSR_JTX:
- gen_helper_wcsr_jtx(cpu_env, cpu_R[dc->r1]);
- break;
- case CSR_JRX:
- gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]);
- break;
- case CSR_DC:
- gen_helper_wcsr_dc(cpu_env, cpu_R[dc->r1]);
- break;
- case CSR_BP0:
- case CSR_BP1:
- case CSR_BP2:
- case CSR_BP3:
- no = dc->csr - CSR_BP0;
- if (dc->num_breakpoints <= no) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "breakpoint #%i is not available\n", no);
- t_gen_illegal_insn(dc);
- break;
- }
- gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
- break;
- case CSR_WP0:
- case CSR_WP1:
- case CSR_WP2:
- case CSR_WP3:
- no = dc->csr - CSR_WP0;
- if (dc->num_watchpoints <= no) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "watchpoint #%i is not available\n", no);
- t_gen_illegal_insn(dc);
- break;
- }
- gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no));
- break;
- case CSR_CC:
- case CSR_CFG:
- qemu_log_mask(LOG_GUEST_ERROR, "invalid write access csr=%x\n",
- dc->csr);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "write_csr: unknown csr=%x\n",
- dc->csr);
- break;
- }
-}
-
-static void dec_xnor(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("xnori r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- if (dc->r1 == R_R0) {
- LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0);
- } else {
- LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- zero_extend(dc->imm16, 16));
- tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]);
- } else {
- tcg_gen_eqv_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_xor(DisasContext *dc)
-{
- if (dc->format == OP_FMT_RI) {
- LOG_DIS("xori r%d, r%d, %d\n", dc->r1, dc->r0,
- zero_extend(dc->imm16, 16));
- } else {
- LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
- }
-
- if (dc->format == OP_FMT_RI) {
- tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
- zero_extend(dc->imm16, 16));
- } else {
- tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
- }
-}
-
-static void dec_ill(DisasContext *dc)
-{
- qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode);
- t_gen_illegal_insn(dc);
-}
-
-typedef void (*DecoderInfo)(DisasContext *dc);
-static const DecoderInfo decinfo[] = {
- dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh,
- dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl,
- dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne,
- dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi,
- dec_cmpne,
- dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill,
- dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl,
- dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth,
- dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli,
- dec_cmpne
-};
-
-static inline void decode(DisasContext *dc, uint32_t ir)
-{
- dc->ir = ir;
- LOG_DIS("%8.8x\t", dc->ir);
-
- dc->opcode = EXTRACT_FIELD(ir, 26, 31);
-
- dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
- dc->imm16 = EXTRACT_FIELD(ir, 0, 15);
- dc->imm26 = EXTRACT_FIELD(ir, 0, 25);
-
- dc->csr = EXTRACT_FIELD(ir, 21, 25);
- dc->r0 = EXTRACT_FIELD(ir, 21, 25);
- dc->r1 = EXTRACT_FIELD(ir, 16, 20);
- dc->r2 = EXTRACT_FIELD(ir, 11, 15);
-
- /* bit 31 seems to indicate insn type. */
- if (ir & (1 << 31)) {
- dc->format = OP_FMT_RR;
- } else {
- dc->format = OP_FMT_RI;
- }
-
- assert(ARRAY_SIZE(decinfo) == 64);
- assert(dc->opcode < 64);
-
- decinfo[dc->opcode](dc);
-}
-
-/* generate intermediate code for basic block 'tb'. */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
-{
- CPULM32State *env = cs->env_ptr;
- LM32CPU *cpu = env_archcpu(env);
- struct DisasContext ctx, *dc = &ctx;
- uint32_t pc_start;
- uint32_t page_start;
- int num_insns;
-
- pc_start = tb->pc;
- dc->features = cpu->features;
- dc->num_breakpoints = cpu->num_breakpoints;
- dc->num_watchpoints = cpu->num_watchpoints;
- dc->tb = tb;
-
- dc->is_jmp = DISAS_NEXT;
- dc->pc = pc_start;
- dc->singlestep_enabled = cs->singlestep_enabled;
-
- if (pc_start & 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "unaligned PC=%x. Ignoring lowest bits.\n", pc_start);
- pc_start &= ~3;
- }
-
- page_start = pc_start & TARGET_PAGE_MASK;
- num_insns = 0;
-
- gen_tb_start(tb);
- do {
- tcg_gen_insn_start(dc->pc);
- num_insns++;
-
- if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- t_gen_raise_exception(dc, EXCP_DEBUG);
- dc->is_jmp = DISAS_UPDATE;
- /* The address covered by the breakpoint must be included in
- [tb->pc, tb->pc + tb->size) in order to for it to be
- properly cleared -- thus we increment the PC here so that
- the logic setting tb->size below does the right thing. */
- dc->pc += 4;
- break;
- }
-
- /* Pretty disas. */
- LOG_DIS("%8.8x:\t", dc->pc);
-
- if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
- gen_io_start();
- }
-
- decode(dc, cpu_ldl_code(env, dc->pc));
- dc->pc += 4;
- } while (!dc->is_jmp
- && !tcg_op_buf_full()
- && !cs->singlestep_enabled
- && !singlestep
- && (dc->pc - page_start < TARGET_PAGE_SIZE)
- && num_insns < max_insns);
-
-
- if (unlikely(cs->singlestep_enabled)) {
- if (dc->is_jmp == DISAS_NEXT) {
- tcg_gen_movi_tl(cpu_pc, dc->pc);
- }
- t_gen_raise_exception(dc, EXCP_DEBUG);
- } else {
- switch (dc->is_jmp) {
- case DISAS_NEXT:
- gen_goto_tb(dc, 1, dc->pc);
- break;
- default:
- case DISAS_JUMP:
- case DISAS_UPDATE:
- /* indicate that the hash table must be used
- to find the next TB */
- tcg_gen_exit_tb(NULL, 0);
- break;
- case DISAS_TB_JUMP:
- /* nothing more to generate */
- break;
- }
- }
-
- gen_tb_end(tb, num_insns);
-
- tb->size = dc->pc - pc_start;
- tb->icount = num_insns;
-
-#ifdef DEBUG_DISAS
- if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
- && qemu_log_in_addr_range(pc_start)) {
- FILE *logfile = qemu_log_lock();
- qemu_log("\n");
- log_target_disas(cs, pc_start, dc->pc - pc_start);
- qemu_log_unlock(logfile);
- }
-#endif
-}
-
-void lm32_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- LM32CPU *cpu = LM32_CPU(cs);
- CPULM32State *env = &cpu->env;
- int i;
-
- if (!env) {
- return;
- }
-
- qemu_fprintf(f, "IN: PC=%x %s\n",
- env->pc, lookup_symbol(env->pc));
-
- qemu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n",
- env->ie,
- (env->ie & IE_IE) ? 1 : 0,
- (env->ie & IE_EIE) ? 1 : 0,
- (env->ie & IE_BIE) ? 1 : 0,
- lm32_pic_get_im(env->pic_state),
- lm32_pic_get_ip(env->pic_state));
- qemu_fprintf(f, "eba=%8.8x deba=%8.8x\n",
- env->eba,
- env->deba);
-
- for (i = 0; i < 32; i++) {
- qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
- if ((i + 1) % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
- qemu_fprintf(f, "\n\n");
-}
-
-void restore_state_to_opc(CPULM32State *env, TranslationBlock *tb,
- target_ulong *data)
-{
- env->pc = data[0];
-}
-
-void lm32_translate_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cpu_R); i++) {
- cpu_R[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, regs[i]),
- regnames[i]);
- }
-
- for (i = 0; i < ARRAY_SIZE(cpu_bp); i++) {
- cpu_bp[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, bp[i]),
- regnames[32+i]);
- }
-
- for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) {
- cpu_wp[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, wp[i]),
- regnames[36+i]);
- }
-
- cpu_pc = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, pc),
- "pc");
- cpu_ie = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, ie),
- "ie");
- cpu_icc = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, icc),
- "icc");
- cpu_dcc = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, dcc),
- "dcc");
- cpu_cc = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, cc),
- "cc");
- cpu_cfg = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, cfg),
- "cfg");
- cpu_eba = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, eba),
- "eba");
- cpu_dc = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, dc),
- "dc");
- cpu_deba = tcg_global_mem_new(cpu_env,
- offsetof(CPULM32State, deba),
- "deba");
-}
-
diff --git a/target/meson.build b/target/meson.build
index 0e2c4b69cb..2f6940255e 100644
--- a/target/meson.build
+++ b/target/meson.build
@@ -5,11 +5,9 @@ subdir('cris')
subdir('hexagon')
subdir('hppa')
subdir('i386')
-subdir('lm32')
subdir('m68k')
subdir('microblaze')
subdir('mips')
-subdir('moxie')
subdir('nios2')
subdir('openrisc')
subdir('ppc')
@@ -19,5 +17,4 @@ subdir('s390x')
subdir('sh4')
subdir('sparc')
subdir('tricore')
-subdir('unicore32')
subdir('xtensa')
diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h
index 1c2d6d35a7..ad1116e8c1 100644
--- a/target/mips/fpu_helper.h
+++ b/target/mips/fpu_helper.h
@@ -27,8 +27,14 @@ static inline void restore_flush_mode(CPUMIPSState *env)
static inline void restore_snan_bit_mode(CPUMIPSState *env)
{
- set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0,
- &env->active_fpu.fp_status);
+ bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008);
+
+ /*
+ * With nan2008, SNaNs are silenced in the usual way.
+ * Before that, SNaNs are not silenced; default nans are produced.
+ */
+ set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status);
+ set_default_nan_mode(!nan2008, &env->active_fpu.fp_status);
}
static inline void restore_fp_status(CPUMIPSState *env)
diff --git a/target/moxie/cpu-param.h b/target/moxie/cpu-param.h
deleted file mode 100644
index 9a40ef525c..0000000000
--- a/target/moxie/cpu-param.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Moxie cpu parameters for qemu.
- *
- * Copyright (c) 2008, 2010, 2013 Anthony Green
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#ifndef MOXIE_CPU_PARAM_H
-#define MOXIE_CPU_PARAM_H 1
-
-#define TARGET_LONG_BITS 32
-#define TARGET_PAGE_BITS 12 /* 4k */
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
-#define NB_MMU_MODES 1
-
-#endif
diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c
deleted file mode 100644
index 83bec34d36..0000000000
--- a/target/moxie/cpu.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * QEMU Moxie CPU
- *
- * Copyright (c) 2013 Anthony Green
- *
- * 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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "migration/vmstate.h"
-#include "machine.h"
-
-static void moxie_cpu_set_pc(CPUState *cs, vaddr value)
-{
- MoxieCPU *cpu = MOXIE_CPU(cs);
-
- cpu->env.pc = value;
-}
-
-static bool moxie_cpu_has_work(CPUState *cs)
-{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
-}
-
-static void moxie_cpu_reset(DeviceState *dev)
-{
- CPUState *s = CPU(dev);
- MoxieCPU *cpu = MOXIE_CPU(s);
- MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(cpu);
- CPUMoxieState *env = &cpu->env;
-
- mcc->parent_reset(dev);
-
- memset(env, 0, offsetof(CPUMoxieState, end_reset_fields));
- env->pc = 0x1000;
-}
-
-static void moxie_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
-{
- info->mach = bfd_arch_moxie;
- info->print_insn = print_insn_moxie;
-}
-
-static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)
-{
- CPUState *cs = CPU(dev);
- MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev);
- Error *local_err = NULL;
-
- cpu_exec_realizefn(cs, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- qemu_init_vcpu(cs);
- cpu_reset(cs);
-
- mcc->parent_realize(dev, errp);
-}
-
-static void moxie_cpu_initfn(Object *obj)
-{
- MoxieCPU *cpu = MOXIE_CPU(obj);
-
- cpu_set_cpustate_pointers(cpu);
-}
-
-static ObjectClass *moxie_cpu_class_by_name(const char *cpu_model)
-{
- ObjectClass *oc;
- char *typename;
-
- typename = g_strdup_printf(MOXIE_CPU_TYPE_NAME("%s"), cpu_model);
- oc = object_class_by_name(typename);
- g_free(typename);
- if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_MOXIE_CPU) ||
- object_class_is_abstract(oc))) {
- return NULL;
- }
- return oc;
-}
-
-#include "hw/core/tcg-cpu-ops.h"
-
-static struct TCGCPUOps moxie_tcg_ops = {
- .initialize = moxie_translate_init,
- .tlb_fill = moxie_cpu_tlb_fill,
-
-#ifndef CONFIG_USER_ONLY
- .do_interrupt = moxie_cpu_do_interrupt,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static void moxie_cpu_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- CPUClass *cc = CPU_CLASS(oc);
- MoxieCPUClass *mcc = MOXIE_CPU_CLASS(oc);
-
- device_class_set_parent_realize(dc, moxie_cpu_realizefn,
- &mcc->parent_realize);
- device_class_set_parent_reset(dc, moxie_cpu_reset, &mcc->parent_reset);
-
- cc->class_by_name = moxie_cpu_class_by_name;
-
- cc->has_work = moxie_cpu_has_work;
- cc->dump_state = moxie_cpu_dump_state;
- cc->set_pc = moxie_cpu_set_pc;
-#ifndef CONFIG_USER_ONLY
- cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
- cc->vmsd = &vmstate_moxie_cpu;
-#endif
- cc->disas_set_info = moxie_cpu_disas_set_info;
- cc->tcg_ops = &moxie_tcg_ops;
-}
-
-static void moxielite_initfn(Object *obj)
-{
- /* Set cpu feature flags */
-}
-
-static void moxie_any_initfn(Object *obj)
-{
- /* Set cpu feature flags */
-}
-
-#define DEFINE_MOXIE_CPU_TYPE(cpu_model, initfn) \
- { \
- .parent = TYPE_MOXIE_CPU, \
- .instance_init = initfn, \
- .name = MOXIE_CPU_TYPE_NAME(cpu_model), \
- }
-
-static const TypeInfo moxie_cpus_type_infos[] = {
- { /* base class should be registered first */
- .name = TYPE_MOXIE_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(MoxieCPU),
- .instance_init = moxie_cpu_initfn,
- .class_size = sizeof(MoxieCPUClass),
- .class_init = moxie_cpu_class_init,
- },
- DEFINE_MOXIE_CPU_TYPE("MoxieLite", moxielite_initfn),
- DEFINE_MOXIE_CPU_TYPE("any", moxie_any_initfn),
-};
-
-DEFINE_TYPES(moxie_cpus_type_infos)
diff --git a/target/moxie/cpu.h b/target/moxie/cpu.h
deleted file mode 100644
index bd6ab66084..0000000000
--- a/target/moxie/cpu.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Moxie emulation
- *
- * Copyright (c) 2008, 2010, 2013 Anthony Green
- *
- * 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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef MOXIE_CPU_H
-#define MOXIE_CPU_H
-
-#include "exec/cpu-defs.h"
-#include "qom/object.h"
-
-#define MOXIE_EX_DIV0 0
-#define MOXIE_EX_BAD 1
-#define MOXIE_EX_IRQ 2
-#define MOXIE_EX_SWI 3
-#define MOXIE_EX_MMU_MISS 4
-#define MOXIE_EX_BREAK 16
-
-typedef struct CPUMoxieState {
-
- uint32_t flags; /* general execution flags */
- uint32_t gregs[16]; /* general registers */
- uint32_t sregs[256]; /* special registers */
- uint32_t pc; /* program counter */
- /* Instead of saving the cc value, we save the cmp arguments
- and compute cc on demand. */
- uint32_t cc_a; /* reg a for condition code calculation */
- uint32_t cc_b; /* reg b for condition code calculation */
-
- void *irq[8];
-
- /* Fields up to this point are cleared by a CPU reset */
- struct {} end_reset_fields;
-} CPUMoxieState;
-
-#include "hw/core/cpu.h"
-
-#define TYPE_MOXIE_CPU "moxie-cpu"
-
-OBJECT_DECLARE_TYPE(MoxieCPU, MoxieCPUClass,
- MOXIE_CPU)
-
-/**
- * MoxieCPUClass:
- * @parent_reset: The parent class' reset handler.
- *
- * A Moxie CPU model.
- */
-struct MoxieCPUClass {
- /*< private >*/
- CPUClass parent_class;
- /*< public >*/
-
- DeviceRealize parent_realize;
- DeviceReset parent_reset;
-};
-
-/**
- * MoxieCPU:
- * @env: #CPUMoxieState
- *
- * A Moxie CPU.
- */
-struct MoxieCPU {
- /*< private >*/
- CPUState parent_obj;
- /*< public >*/
-
- CPUNegativeOffsetState neg;
- CPUMoxieState env;
-};
-
-
-void moxie_cpu_do_interrupt(CPUState *cs);
-void moxie_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-void moxie_translate_init(void);
-int cpu_moxie_signal_handler(int host_signum, void *pinfo,
- void *puc);
-
-#define MOXIE_CPU_TYPE_SUFFIX "-" TYPE_MOXIE_CPU
-#define MOXIE_CPU_TYPE_NAME(model) model MOXIE_CPU_TYPE_SUFFIX
-#define CPU_RESOLVING_TYPE TYPE_MOXIE_CPU
-
-#define cpu_signal_handler cpu_moxie_signal_handler
-
-static inline int cpu_mmu_index(CPUMoxieState *env, bool ifetch)
-{
- return 0;
-}
-
-typedef CPUMoxieState CPUArchState;
-typedef MoxieCPU ArchCPU;
-
-#include "exec/cpu-all.h"
-
-static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc,
- target_ulong *cs_base, uint32_t *flags)
-{
- *pc = env->pc;
- *cs_base = 0;
- *flags = 0;
-}
-
-bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-
-#endif /* MOXIE_CPU_H */
diff --git a/target/moxie/helper.c b/target/moxie/helper.c
deleted file mode 100644
index b1919f62b3..0000000000
--- a/target/moxie/helper.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Moxie helper routines.
- *
- * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green
- *
- * 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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "mmu.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "qemu/host-utils.h"
-#include "exec/helper-proto.h"
-
-void helper_raise_exception(CPUMoxieState *env, int ex)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = ex;
- /* Stash the exception type. */
- env->sregs[2] = ex;
- /* Stash the address where the exception occurred. */
- cpu_restore_state(cs, GETPC(), true);
- env->sregs[5] = env->pc;
- /* Jump to the exception handline routine. */
- env->pc = env->sregs[1];
- cpu_loop_exit(cs);
-}
-
-uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b)
-{
- if (unlikely(b == 0)) {
- helper_raise_exception(env, MOXIE_EX_DIV0);
- return 0;
- }
- if (unlikely(a == INT_MIN && b == -1)) {
- return INT_MIN;
- }
-
- return (int32_t)a / (int32_t)b;
-}
-
-uint32_t helper_udiv(CPUMoxieState *env, uint32_t a, uint32_t b)
-{
- if (unlikely(b == 0)) {
- helper_raise_exception(env, MOXIE_EX_DIV0);
- return 0;
- }
- return a / b;
-}
-
-void helper_debug(CPUMoxieState *env)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = EXCP_DEBUG;
- cpu_loop_exit(cs);
-}
-
-bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- MoxieCPU *cpu = MOXIE_CPU(cs);
- CPUMoxieState *env = &cpu->env;
- MoxieMMUResult res;
- int prot, miss;
-
- address &= TARGET_PAGE_MASK;
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- miss = moxie_mmu_translate(&res, env, address, access_type, mmu_idx);
- if (likely(!miss)) {
- tlb_set_page(cs, address, res.phy, prot, mmu_idx, TARGET_PAGE_SIZE);
- return true;
- }
- if (probe) {
- return false;
- }
-
- cs->exception_index = MOXIE_EX_MMU_MISS;
- cpu_loop_exit_restore(cs, retaddr);
-}
-
-void moxie_cpu_do_interrupt(CPUState *cs)
-{
- switch (cs->exception_index) {
- case MOXIE_EX_BREAK:
- break;
- default:
- break;
- }
-}
-
-hwaddr moxie_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- MoxieCPU *cpu = MOXIE_CPU(cs);
- uint32_t phy = addr;
- MoxieMMUResult res;
- int miss;
-
- miss = moxie_mmu_translate(&res, &cpu->env, addr, 0, 0);
- if (!miss) {
- phy = res.phy;
- }
- return phy;
-}
diff --git a/target/moxie/helper.h b/target/moxie/helper.h
deleted file mode 100644
index d94ef7a17e..0000000000
--- a/target/moxie/helper.h
+++ /dev/null
@@ -1,5 +0,0 @@
-DEF_HELPER_2(raise_exception, void, env, int)
-DEF_HELPER_1(debug, void, env)
-
-DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32)
-DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32)
diff --git a/target/moxie/machine.c b/target/moxie/machine.c
deleted file mode 100644
index d0f177048c..0000000000
--- a/target/moxie/machine.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "machine.h"
-#include "migration/cpu.h"
-
-const VMStateDescription vmstate_moxie_cpu = {
- .name = "cpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(flags, CPUMoxieState),
- VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16),
- VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256),
- VMSTATE_UINT32(pc, CPUMoxieState),
- VMSTATE_UINT32(cc_a, CPUMoxieState),
- VMSTATE_UINT32(cc_b, CPUMoxieState),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/target/moxie/machine.h b/target/moxie/machine.h
deleted file mode 100644
index a1b72907ae..0000000000
--- a/target/moxie/machine.h
+++ /dev/null
@@ -1 +0,0 @@
-extern const VMStateDescription vmstate_moxie_cpu;
diff --git a/target/moxie/meson.build b/target/moxie/meson.build
deleted file mode 100644
index b4beb528cc..0000000000
--- a/target/moxie/meson.build
+++ /dev/null
@@ -1,14 +0,0 @@
-moxie_ss = ss.source_set()
-moxie_ss.add(files(
- 'cpu.c',
- 'helper.c',
- 'machine.c',
- 'machine.c',
- 'translate.c',
-))
-
-moxie_softmmu_ss = ss.source_set()
-moxie_softmmu_ss.add(files('mmu.c'))
-
-target_arch += {'moxie': moxie_ss}
-target_softmmu_arch += {'moxie': moxie_softmmu_ss}
diff --git a/target/moxie/mmu.c b/target/moxie/mmu.c
deleted file mode 100644
index 87783a36f8..0000000000
--- a/target/moxie/mmu.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Moxie mmu emulation.
- *
- * Copyright (c) 2008, 2013 Anthony Green
- *
- * 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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "mmu.h"
-
-int moxie_mmu_translate(MoxieMMUResult *res,
- CPUMoxieState *env, uint32_t vaddr,
- int rw, int mmu_idx)
-{
- /* Perform no translation yet. */
- res->phy = vaddr;
- return 0;
-}
diff --git a/target/moxie/mmu.h b/target/moxie/mmu.h
deleted file mode 100644
index d80690f4d2..0000000000
--- a/target/moxie/mmu.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef TARGET_MOXIE_MMU_H
-#define TARGET_MOXIE_MMU_H
-
-#define MOXIE_MMU_ERR_EXEC 0
-#define MOXIE_MMU_ERR_READ 1
-#define MOXIE_MMU_ERR_WRITE 2
-#define MOXIE_MMU_ERR_FLUSH 3
-
-typedef struct {
- uint32_t phy;
- uint32_t pfn;
- int cause_op;
-} MoxieMMUResult;
-
-int moxie_mmu_translate(MoxieMMUResult *res,
- CPUMoxieState *env, uint32_t vaddr,
- int rw, int mmu_idx);
-
-#endif
diff --git a/target/moxie/translate.c b/target/moxie/translate.c
deleted file mode 100644
index 24a742b25e..0000000000
--- a/target/moxie/translate.c
+++ /dev/null
@@ -1,892 +0,0 @@
-/*
- * Moxie emulation for qemu: main translation routines.
- *
- * Copyright (c) 2009, 2013 Anthony Green
- *
- * 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.1 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 program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* For information on the Moxie architecture, see
- * http://moxielogic.org/wiki
- */
-
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "disas/disas.h"
-#include "tcg/tcg-op.h"
-#include "exec/cpu_ldst.h"
-#include "qemu/qemu-print.h"
-
-#include "exec/helper-proto.h"
-#include "exec/helper-gen.h"
-#include "exec/log.h"
-
-/* This is the state at translation time. */
-typedef struct DisasContext {
- TranslationBlock *tb;
- target_ulong pc, saved_pc;
- uint32_t opcode;
- uint32_t fp_status;
- /* Routine used to access memory */
- int memidx;
- int bstate;
- target_ulong btarget;
- int singlestep_enabled;
-} DisasContext;
-
-enum {
- BS_NONE = 0, /* We go out of the TB without reaching a branch or an
- * exception condition */
- BS_STOP = 1, /* We want to stop translation for any reason */
- BS_BRANCH = 2, /* We reached a branch condition */
- BS_EXCP = 3, /* We reached an exception condition */
-};
-
-static TCGv cpu_pc;
-static TCGv cpu_gregs[16];
-static TCGv cc_a, cc_b;
-
-#include "exec/gen-icount.h"
-
-#define REG(x) (cpu_gregs[x])
-
-/* Extract the signed 10-bit offset from a 16-bit branch
- instruction. */
-static int extract_branch_offset(int opcode)
-{
- return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1;
-}
-
-void moxie_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- MoxieCPU *cpu = MOXIE_CPU(cs);
- CPUMoxieState *env = &cpu->env;
- int i;
- qemu_fprintf(f, "pc=0x%08x\n", env->pc);
- qemu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n",
- env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]);
- for (i = 4; i < 16; i += 4) {
- qemu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n",
- i - 2, env->gregs[i], i - 1, env->gregs[i + 1],
- i, env->gregs[i + 2], i + 1, env->gregs[i + 3]);
- }
- for (i = 4; i < 16; i += 4) {
- qemu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n",
- i - 2, env->sregs[i], i - 1, env->sregs[i + 1],
- i, env->sregs[i + 2], i + 1, env->sregs[i + 3]);
- }
-}
-
-void moxie_translate_init(void)
-{
- int i;
- static const char * const gregnames[16] = {
- "$fp", "$sp", "$r0", "$r1",
- "$r2", "$r3", "$r4", "$r5",
- "$r6", "$r7", "$r8", "$r9",
- "$r10", "$r11", "$r12", "$r13"
- };
-
- cpu_pc = tcg_global_mem_new_i32(cpu_env,
- offsetof(CPUMoxieState, pc), "$pc");
- for (i = 0; i < 16; i++)
- cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env,
- offsetof(CPUMoxieState, gregs[i]),
- gregnames[i]);
-
- cc_a = tcg_global_mem_new_i32(cpu_env,
- offsetof(CPUMoxieState, cc_a), "cc_a");
- cc_b = tcg_global_mem_new_i32(cpu_env,
- offsetof(CPUMoxieState, cc_b), "cc_b");
-}
-
-static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
-{
- if (unlikely(ctx->singlestep_enabled)) {
- return false;
- }
-
-#ifndef CONFIG_USER_ONLY
- return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
-#else
- return true;
-#endif
-}
-
-static inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx,
- int n, target_ulong dest)
-{
- if (use_goto_tb(ctx, dest)) {
- tcg_gen_goto_tb(n);
- tcg_gen_movi_i32(cpu_pc, dest);
- tcg_gen_exit_tb(ctx->tb, n);
- } else {
- tcg_gen_movi_i32(cpu_pc, dest);
- if (ctx->singlestep_enabled) {
- gen_helper_debug(cpu_env);
- }
- tcg_gen_exit_tb(NULL, 0);
- }
-}
-
-static int decode_opc(MoxieCPU *cpu, DisasContext *ctx)
-{
- CPUMoxieState *env = &cpu->env;
-
- /* Local cache for the instruction opcode. */
- int opcode;
- /* Set the default instruction length. */
- int length = 2;
-
- /* Examine the 16-bit opcode. */
- opcode = ctx->opcode;
-
- /* Decode instruction. */
- if (opcode & (1 << 15)) {
- if (opcode & (1 << 14)) {
- /* This is a Form 3 instruction. */
- int inst = (opcode >> 10 & 0xf);
-
-#define BRANCH(cond) \
- do { \
- TCGLabel *l1 = gen_new_label(); \
- tcg_gen_brcond_i32(cond, cc_a, cc_b, l1); \
- gen_goto_tb(env, ctx, 1, ctx->pc+2); \
- gen_set_label(l1); \
- gen_goto_tb(env, ctx, 0, extract_branch_offset(opcode) + ctx->pc+2); \
- ctx->bstate = BS_BRANCH; \
- } while (0)
-
- switch (inst) {
- case 0x00: /* beq */
- BRANCH(TCG_COND_EQ);
- break;
- case 0x01: /* bne */
- BRANCH(TCG_COND_NE);
- break;
- case 0x02: /* blt */
- BRANCH(TCG_COND_LT);
- break;
- case 0x03: /* bgt */
- BRANCH(TCG_COND_GT);
- break;
- case 0x04: /* bltu */
- BRANCH(TCG_COND_LTU);
- break;
- case 0x05: /* bgtu */
- BRANCH(TCG_COND_GTU);
- break;
- case 0x06: /* bge */
- BRANCH(TCG_COND_GE);
- break;
- case 0x07: /* ble */
- BRANCH(TCG_COND_LE);
- break;
- case 0x08: /* bgeu */
- BRANCH(TCG_COND_GEU);
- break;
- case 0x09: /* bleu */
- BRANCH(TCG_COND_LEU);
- break;
- default:
- {
- TCGv temp = tcg_temp_new_i32();
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- tcg_gen_movi_i32(temp, MOXIE_EX_BAD);
- gen_helper_raise_exception(cpu_env, temp);
- tcg_temp_free_i32(temp);
- }
- break;
- }
- } else {
- /* This is a Form 2 instruction. */
- int inst = (opcode >> 12 & 0x3);
- switch (inst) {
- case 0x00: /* inc */
- {
- int a = (opcode >> 8) & 0xf;
- unsigned int v = (opcode & 0xff);
- tcg_gen_addi_i32(REG(a), REG(a), v);
- }
- break;
- case 0x01: /* dec */
- {
- int a = (opcode >> 8) & 0xf;
- unsigned int v = (opcode & 0xff);
- tcg_gen_subi_i32(REG(a), REG(a), v);
- }
- break;
- case 0x02: /* gsr */
- {
- int a = (opcode >> 8) & 0xf;
- unsigned v = (opcode & 0xff);
- tcg_gen_ld_i32(REG(a), cpu_env,
- offsetof(CPUMoxieState, sregs[v]));
- }
- break;
- case 0x03: /* ssr */
- {
- int a = (opcode >> 8) & 0xf;
- unsigned v = (opcode & 0xff);
- tcg_gen_st_i32(REG(a), cpu_env,
- offsetof(CPUMoxieState, sregs[v]));
- }
- break;
- default:
- {
- TCGv temp = tcg_temp_new_i32();
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- tcg_gen_movi_i32(temp, MOXIE_EX_BAD);
- gen_helper_raise_exception(cpu_env, temp);
- tcg_temp_free_i32(temp);
- }
- break;
- }
- }
- } else {
- /* This is a Form 1 instruction. */
- int inst = opcode >> 8;
- switch (inst) {
- case 0x00: /* nop */
- break;
- case 0x01: /* ldi.l (immediate) */
- {
- int reg = (opcode >> 4) & 0xf;
- int val = cpu_ldl_code(env, ctx->pc+2);
- tcg_gen_movi_i32(REG(reg), val);
- length = 6;
- }
- break;
- case 0x02: /* mov (register-to-register) */
- {
- int dest = (opcode >> 4) & 0xf;
- int src = opcode & 0xf;
- tcg_gen_mov_i32(REG(dest), REG(src));
- }
- break;
- case 0x03: /* jsra */
- {
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
-
- tcg_gen_movi_i32(t1, ctx->pc + 6);
-
- /* Make space for the static chain and return address. */
- tcg_gen_subi_i32(t2, REG(1), 8);
- tcg_gen_mov_i32(REG(1), t2);
- tcg_gen_qemu_st32(t1, REG(1), ctx->memidx);
-
- /* Push the current frame pointer. */
- tcg_gen_subi_i32(t2, REG(1), 4);
- tcg_gen_mov_i32(REG(1), t2);
- tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx);
-
- /* Set the pc and $fp. */
- tcg_gen_mov_i32(REG(0), REG(1));
-
- gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc+2));
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- ctx->bstate = BS_BRANCH;
- length = 6;
- }
- break;
- case 0x04: /* ret */
- {
- TCGv t1 = tcg_temp_new_i32();
-
- /* The new $sp is the old $fp. */
- tcg_gen_mov_i32(REG(1), REG(0));
-
- /* Pop the frame pointer. */
- tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx);
- tcg_gen_addi_i32(t1, REG(1), 4);
- tcg_gen_mov_i32(REG(1), t1);
-
-
- /* Pop the return address and skip over the static chain
- slot. */
- tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx);
- tcg_gen_addi_i32(t1, REG(1), 8);
- tcg_gen_mov_i32(REG(1), t1);
-
- tcg_temp_free_i32(t1);
-
- /* Jump... */
- tcg_gen_exit_tb(NULL, 0);
-
- ctx->bstate = BS_BRANCH;
- }
- break;
- case 0x05: /* add.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_add_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x06: /* push */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- tcg_gen_subi_i32(t1, REG(a), 4);
- tcg_gen_mov_i32(REG(a), t1);
- tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx);
- tcg_temp_free_i32(t1);
- }
- break;
- case 0x07: /* pop */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
- TCGv t1 = tcg_temp_new_i32();
-
- tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx);
- tcg_gen_addi_i32(t1, REG(a), 4);
- tcg_gen_mov_i32(REG(a), t1);
- tcg_temp_free_i32(t1);
- }
- break;
- case 0x08: /* lda.l */
- {
- int reg = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x09: /* sta.l */
- {
- int val = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x0a: /* ld.l (register indirect) */
- {
- int src = opcode & 0xf;
- int dest = (opcode >> 4) & 0xf;
-
- tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx);
- }
- break;
- case 0x0b: /* st.l */
- {
- int dest = (opcode >> 4) & 0xf;
- int val = opcode & 0xf;
-
- tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx);
- }
- break;
- case 0x0c: /* ldo.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld32u(t2, t1, ctx->memidx);
- tcg_gen_mov_i32(REG(a), t2);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- case 0x0d: /* sto.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st32(REG(b), t1, ctx->memidx);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- case 0x0e: /* cmp */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_mov_i32(cc_a, REG(a));
- tcg_gen_mov_i32(cc_b, REG(b));
- }
- break;
- case 0x19: /* jsr */
- {
- int fnreg = (opcode >> 4) & 0xf;
-
- /* Load the stack pointer into T0. */
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
-
- tcg_gen_movi_i32(t1, ctx->pc+2);
-
- /* Make space for the static chain and return address. */
- tcg_gen_subi_i32(t2, REG(1), 8);
- tcg_gen_mov_i32(REG(1), t2);
- tcg_gen_qemu_st32(t1, REG(1), ctx->memidx);
-
- /* Push the current frame pointer. */
- tcg_gen_subi_i32(t2, REG(1), 4);
- tcg_gen_mov_i32(REG(1), t2);
- tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx);
-
- /* Set the pc and $fp. */
- tcg_gen_mov_i32(REG(0), REG(1));
- tcg_gen_mov_i32(cpu_pc, REG(fnreg));
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
- tcg_gen_exit_tb(NULL, 0);
- ctx->bstate = BS_BRANCH;
- }
- break;
- case 0x1a: /* jmpa */
- {
- tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_exit_tb(NULL, 0);
- ctx->bstate = BS_BRANCH;
- length = 6;
- }
- break;
- case 0x1b: /* ldi.b (immediate) */
- {
- int reg = (opcode >> 4) & 0xf;
- int val = cpu_ldl_code(env, ctx->pc+2);
- tcg_gen_movi_i32(REG(reg), val);
- length = 6;
- }
- break;
- case 0x1c: /* ld.b (register indirect) */
- {
- int src = opcode & 0xf;
- int dest = (opcode >> 4) & 0xf;
-
- tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx);
- }
- break;
- case 0x1d: /* lda.b */
- {
- int reg = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x1e: /* st.b */
- {
- int dest = (opcode >> 4) & 0xf;
- int val = opcode & 0xf;
-
- tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx);
- }
- break;
- case 0x1f: /* sta.b */
- {
- int val = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x20: /* ldi.s (immediate) */
- {
- int reg = (opcode >> 4) & 0xf;
- int val = cpu_ldl_code(env, ctx->pc+2);
- tcg_gen_movi_i32(REG(reg), val);
- length = 6;
- }
- break;
- case 0x21: /* ld.s (register indirect) */
- {
- int src = opcode & 0xf;
- int dest = (opcode >> 4) & 0xf;
-
- tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx);
- }
- break;
- case 0x22: /* lda.s */
- {
- int reg = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x23: /* st.s */
- {
- int dest = (opcode >> 4) & 0xf;
- int val = opcode & 0xf;
-
- tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx);
- }
- break;
- case 0x24: /* sta.s */
- {
- int val = (opcode >> 4) & 0xf;
-
- TCGv ptr = tcg_temp_new_i32();
- tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx);
- tcg_temp_free_i32(ptr);
-
- length = 6;
- }
- break;
- case 0x25: /* jmp */
- {
- int reg = (opcode >> 4) & 0xf;
- tcg_gen_mov_i32(cpu_pc, REG(reg));
- tcg_gen_exit_tb(NULL, 0);
- ctx->bstate = BS_BRANCH;
- }
- break;
- case 0x26: /* and */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_and_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x27: /* lshr */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv sv = tcg_temp_new_i32();
- tcg_gen_andi_i32(sv, REG(b), 0x1f);
- tcg_gen_shr_i32(REG(a), REG(a), sv);
- tcg_temp_free_i32(sv);
- }
- break;
- case 0x28: /* ashl */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv sv = tcg_temp_new_i32();
- tcg_gen_andi_i32(sv, REG(b), 0x1f);
- tcg_gen_shl_i32(REG(a), REG(a), sv);
- tcg_temp_free_i32(sv);
- }
- break;
- case 0x29: /* sub.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_sub_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x2a: /* neg */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_neg_i32(REG(a), REG(b));
- }
- break;
- case 0x2b: /* or */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_or_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x2c: /* not */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_not_i32(REG(a), REG(b));
- }
- break;
- case 0x2d: /* ashr */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv sv = tcg_temp_new_i32();
- tcg_gen_andi_i32(sv, REG(b), 0x1f);
- tcg_gen_sar_i32(REG(a), REG(a), sv);
- tcg_temp_free_i32(sv);
- }
- break;
- case 0x2e: /* xor */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_xor_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x2f: /* mul.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- tcg_gen_mul_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x30: /* swi */
- {
- int val = cpu_ldl_code(env, ctx->pc+2);
-
- TCGv temp = tcg_temp_new_i32();
- tcg_gen_movi_i32(temp, val);
- tcg_gen_st_i32(temp, cpu_env,
- offsetof(CPUMoxieState, sregs[3]));
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- tcg_gen_movi_i32(temp, MOXIE_EX_SWI);
- gen_helper_raise_exception(cpu_env, temp);
- tcg_temp_free_i32(temp);
-
- length = 6;
- }
- break;
- case 0x31: /* div.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- gen_helper_div(REG(a), cpu_env, REG(a), REG(b));
- }
- break;
- case 0x32: /* udiv.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- gen_helper_udiv(REG(a), cpu_env, REG(a), REG(b));
- }
- break;
- case 0x33: /* mod.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
- tcg_gen_rem_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x34: /* umod.l */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
- tcg_gen_remu_i32(REG(a), REG(a), REG(b));
- }
- break;
- case 0x35: /* brk */
- {
- TCGv temp = tcg_temp_new_i32();
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- tcg_gen_movi_i32(temp, MOXIE_EX_BREAK);
- gen_helper_raise_exception(cpu_env, temp);
- tcg_temp_free_i32(temp);
- }
- break;
- case 0x36: /* ldo.b */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld8u(t2, t1, ctx->memidx);
- tcg_gen_mov_i32(REG(a), t2);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- case 0x37: /* sto.b */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st8(REG(b), t1, ctx->memidx);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- case 0x38: /* ldo.s */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_ld16u(t2, t1, ctx->memidx);
- tcg_gen_mov_i32(REG(a), t2);
-
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- case 0x39: /* sto.s */
- {
- int a = (opcode >> 4) & 0xf;
- int b = opcode & 0xf;
-
- TCGv t1 = tcg_temp_new_i32();
- TCGv t2 = tcg_temp_new_i32();
- tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2));
- tcg_gen_qemu_st16(REG(b), t1, ctx->memidx);
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
-
- length = 6;
- }
- break;
- default:
- {
- TCGv temp = tcg_temp_new_i32();
- tcg_gen_movi_i32(cpu_pc, ctx->pc);
- tcg_gen_movi_i32(temp, MOXIE_EX_BAD);
- gen_helper_raise_exception(cpu_env, temp);
- tcg_temp_free_i32(temp);
- }
- break;
- }
- }
-
- return length;
-}
-
-/* generate intermediate code for basic block 'tb'. */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
-{
- CPUMoxieState *env = cs->env_ptr;
- MoxieCPU *cpu = env_archcpu(env);
- DisasContext ctx;
- target_ulong pc_start;
- int num_insns;
-
- pc_start = tb->pc;
- ctx.pc = pc_start;
- ctx.saved_pc = -1;
- ctx.tb = tb;
- ctx.memidx = 0;
- ctx.singlestep_enabled = 0;
- ctx.bstate = BS_NONE;
- num_insns = 0;
-
- gen_tb_start(tb);
- do {
- tcg_gen_insn_start(ctx.pc);
- num_insns++;
-
- if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
- tcg_gen_movi_i32(cpu_pc, ctx.pc);
- gen_helper_debug(cpu_env);
- ctx.bstate = BS_EXCP;
- /* The address covered by the breakpoint must be included in
- [tb->pc, tb->pc + tb->size) in order to for it to be
- properly cleared -- thus we increment the PC here so that
- the logic setting tb->size below does the right thing. */
- ctx.pc += 2;
- goto done_generating;
- }
-
- ctx.opcode = cpu_lduw_code(env, ctx.pc);
- ctx.pc += decode_opc(cpu, &ctx);
-
- if (num_insns >= max_insns) {
- break;
- }
- if (cs->singlestep_enabled) {
- break;
- }
- if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) {
- break;
- }
- } while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
-
- if (cs->singlestep_enabled) {
- tcg_gen_movi_tl(cpu_pc, ctx.pc);
- gen_helper_debug(cpu_env);
- } else {
- switch (ctx.bstate) {
- case BS_STOP:
- case BS_NONE:
- gen_goto_tb(env, &ctx, 0, ctx.pc);
- break;
- case BS_EXCP:
- tcg_gen_exit_tb(NULL, 0);
- break;
- case BS_BRANCH:
- default:
- break;
- }
- }
- done_generating:
- gen_tb_end(tb, num_insns);
-
- tb->size = ctx.pc - pc_start;
- tb->icount = num_insns;
-}
-
-void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb,
- target_ulong *data)
-{
- env->pc = data[0];
-}
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index 9ab04b2c38..9210e61ef4 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -17,7 +17,6 @@
#include "elf.h"
#include "sysemu/dump.h"
#include "sysemu/kvm.h"
-#include "exec/helper-proto.h"
#ifdef TARGET_PPC64
#define ELFCLASS ELFCLASS64
@@ -176,7 +175,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
vmxregset->avr[i].u64[1] = avr->u64[1];
}
}
- vmxregset->vscr.u32[3] = cpu_to_dump32(s, helper_mfvscr(&cpu->env));
+ vmxregset->vscr.u32[3] = cpu_to_dump32(s, ppc_get_vscr(&cpu->env));
}
static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c
index e501a7ff6f..d957d1a687 100644
--- a/target/ppc/cpu.c
+++ b/target/ppc/cpu.c
@@ -20,6 +20,10 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "cpu-models.h"
+#include "cpu-qom.h"
+#include "exec/log.h"
+#include "fpu/softfloat-helpers.h"
+#include "mmu-hash64.h"
target_ulong cpu_read_xer(CPUPPCState *env)
{
@@ -45,3 +49,46 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer)
(1ul << XER_OV) | (1ul << XER_CA) |
(1ul << XER_OV32) | (1ul << XER_CA32));
}
+
+void ppc_store_vscr(CPUPPCState *env, uint32_t vscr)
+{
+ env->vscr = vscr & ~(1u << VSCR_SAT);
+ /* Which bit we set is completely arbitrary, but clear the rest. */
+ env->vscr_sat.u64[0] = vscr & (1u << VSCR_SAT);
+ env->vscr_sat.u64[1] = 0;
+ set_flush_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status);
+}
+
+uint32_t ppc_get_vscr(CPUPPCState *env)
+{
+ uint32_t sat = (env->vscr_sat.u64[0] | env->vscr_sat.u64[1]) != 0;
+ return env->vscr | (sat << VSCR_SAT);
+}
+
+#ifdef CONFIG_SOFTMMU
+void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
+ qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
+ assert(!cpu->vhyp);
+#if defined(TARGET_PPC64)
+ if (mmu_is_64bit(env->mmu_model)) {
+ target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
+ target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+ if (value & ~sdr_mask) {
+ error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1",
+ value & ~sdr_mask);
+ value &= sdr_mask;
+ }
+ if (htabsize > 28) {
+ error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
+ htabsize);
+ return;
+ }
+ }
+#endif /* defined(TARGET_PPC64) */
+ /* FIXME: Should check for valid HTABMASK values in 32-bit case */
+ env->spr[SPR_SDR1] = value;
+}
+#endif /* CONFIG_SOFTMMU */
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 733a2168c4..cab33a3680 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -131,11 +131,7 @@ enum {
POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception */
/* EOL */
POWERPC_EXCP_NB = 103,
- /* QEMU exceptions: used internally during code translation */
- POWERPC_EXCP_STOP = 0x200, /* stop translation */
- POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */
/* QEMU exceptions: special cases we want to stop translation */
- POWERPC_EXCP_SYNC = 0x202, /* context synchronizing instruction */
POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only */
};
@@ -1297,6 +1293,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
void ppc_store_ptcr(CPUPPCState *env, target_ulong value);
#endif /* !defined(CONFIG_USER_ONLY) */
void ppc_store_msr(CPUPPCState *env, target_ulong value);
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_cpu_list(void);
@@ -2641,7 +2638,15 @@ static inline ppc_avr_t *cpu_avr_ptr(CPUPPCState *env, int i)
return (ppc_avr_t *)((uintptr_t)env + avr_full_offset(i));
}
+static inline bool ppc_has_spr(PowerPCCPU *cpu, int spr)
+{
+ /* We can test whether the SPR is defined by checking for a valid name */
+ return cpu->env.spr_cb[spr].name != NULL;
+}
+
void dump_mmu(CPUPPCState *env);
void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len);
+void ppc_store_vscr(CPUPPCState *env, uint32_t vscr);
+uint32_t ppc_get_vscr(CPUPPCState *env);
#endif /* PPC_CPU_H */
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/cpu_init.c
index 66e6a4a746..22ecbccad8 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/cpu_init.c
@@ -18,6 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "disas/dis-asm.h"
#include "exec/gdbstub.h"
#include "kvm_ppc.h"
@@ -42,682 +43,19 @@
#include "fpu/softfloat.h"
#include "qapi/qapi-commands-machine-target.h"
+#include "exec/helper-proto.h"
+#include "helper_regs.h"
+#include "internal.h"
+#include "spr_tcg.h"
+
/* #define PPC_DEBUG_SPR */
-/* #define PPC_DUMP_SPR_ACCESSES */
/* #define USE_APPLE_GDB */
-/*
- * Generic callbacks:
- * do nothing but store/retrieve spr value
- */
-static void spr_load_dump_spr(int sprn)
-{
-#ifdef PPC_DUMP_SPR_ACCESSES
- TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_load_dump_spr(cpu_env, t0);
- tcg_temp_free_i32(t0);
-#endif
-}
-
-static void spr_read_generic(DisasContext *ctx, int gprn, int sprn)
-{
- gen_load_spr(cpu_gpr[gprn], sprn);
- spr_load_dump_spr(sprn);
-}
-
-static void spr_store_dump_spr(int sprn)
-{
-#ifdef PPC_DUMP_SPR_ACCESSES
- TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_store_dump_spr(cpu_env, t0);
- tcg_temp_free_i32(t0);
-#endif
-}
-
-static void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
-{
- gen_store_spr(sprn, cpu_gpr[gprn]);
- spr_store_dump_spr(sprn);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
-{
-#ifdef TARGET_PPC64
- TCGv t0 = tcg_temp_new();
- tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]);
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
- spr_store_dump_spr(sprn);
-#else
- spr_write_generic(ctx, sprn, gprn);
-#endif
-}
-
-static void spr_write_clear(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- gen_load_spr(t0, sprn);
- tcg_gen_neg_tl(t1, cpu_gpr[gprn]);
- tcg_gen_and_tl(t0, t0, t1);
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
-}
-
-static void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
-{
-}
-
-#endif
-
-/* SPR common to all PowerPC */
-/* XER */
-static void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
-{
- gen_read_xer(ctx, cpu_gpr[gprn]);
-}
-
-static void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
-{
- gen_write_xer(cpu_gpr[gprn]);
-}
-
-/* LR */
-static void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr);
-}
-
-static void spr_write_lr(DisasContext *ctx, int sprn, int gprn)
-{
- tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
-}
-
-/* CFAR */
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-static void spr_read_cfar(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar);
-}
-
-static void spr_write_cfar(DisasContext *ctx, int sprn, int gprn)
-{
- tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]);
-}
-#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
-
-/* CTR */
-static void spr_read_ctr(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr);
-}
-
-static void spr_write_ctr(DisasContext *ctx, int sprn, int gprn)
-{
- tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]);
-}
-
-/* User read access to SPR */
-/* USPRx */
-/* UMMCRx */
-/* UPMCx */
-/* USIA */
-/* UDECR */
-static void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
-{
- gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
-}
-
-#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
-static void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
-{
- gen_store_spr(sprn + 0x10, cpu_gpr[gprn]);
-}
-#endif
-
-/* SPR common to all non-embedded PowerPC */
-/* DECR */
-#if !defined(CONFIG_USER_ONLY)
-static void spr_read_decr(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_decr(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_decr(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_decr(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-#endif
-
-/* SPR common to all non-embedded PowerPC, except 601 */
-/* Time base */
-static void spr_read_tbl(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_tbl(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_read_tbu(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_tbu(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-ATTRIBUTE_UNUSED
-static void spr_read_atbl(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_atbl(cpu_gpr[gprn], cpu_env);
-}
-
-ATTRIBUTE_UNUSED
-static void spr_read_atbu(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_atbu(cpu_gpr[gprn], cpu_env);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_tbl(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_tbu(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-ATTRIBUTE_UNUSED
-static void spr_write_atbl(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]);
-}
-
-ATTRIBUTE_UNUSED
-static void spr_write_atbu(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]);
-}
-
-#if defined(TARGET_PPC64)
-ATTRIBUTE_UNUSED
-static void spr_read_purr(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_purr(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_purr(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_purr(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-/* HDECR */
-static void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_end();
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_read_vtb(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_vtb(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_vtb(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_vtb(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_tbu40(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-#endif
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-/* IBAT0U...IBAT0U */
-/* IBAT0L...IBAT7L */
-static void spr_read_ibat(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
-}
-
-static void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4]));
-}
-
-static void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4);
- gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
- gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4);
- gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-/* DBAT0U...DBAT7U */
-/* DBAT0L...DBAT7L */
-static void spr_read_dbat(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2]));
-}
-
-static void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4]));
-}
-
-static void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
- gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
- gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
- gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
- gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-/* SDR1 */
-static void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]);
-}
-
-#if defined(TARGET_PPC64)
-/* 64 bits PowerPC specific SPRs */
-/* PIDR */
-static void spr_write_pidr(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_read_hior(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix));
-}
-
-static void spr_write_hior(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
- tcg_temp_free(t0);
-}
-static void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_write_pcr(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_pcr(cpu_env, cpu_gpr[gprn]);
-}
-
-/* DPDES */
-static void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env);
-}
-
-static void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]);
-}
-#endif
-#endif
-
-/* PowerPC 601 specific registers */
-/* RTC */
-static void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
-}
-
-static void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
- /* Must stop the translation as endianness may have changed */
- gen_stop_exception(ctx);
-}
-#endif
-
-/* Unified bats */
-#if !defined(CONFIG_USER_ONLY)
-static void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
-}
-
-static void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-#endif
-
-/* PowerPC 40x specific registers */
-#if !defined(CONFIG_USER_ONLY)
-static void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_store_spr(sprn, cpu_gpr[gprn]);
- gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
- /* We must stop translation as we may have rebooted */
- gen_stop_exception(ctx);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-
-static void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn)
-{
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]);
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
-}
-#endif
-
-/* PowerPC 403 specific registers */
-/* PBL1 / PBU1 / PBL2 / PBU2 */
-#if !defined(CONFIG_USER_ONLY)
-static void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1]));
-}
-
-static void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1);
- gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_pir(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF);
- gen_store_spr(SPR_PIR, t0);
- tcg_temp_free(t0);
-}
-#endif
-
-/* SPE specific registers */
-static void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn)
-{
- TCGv_i32 t0 = tcg_temp_new_i32();
- tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
- tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0);
- tcg_temp_free_i32(t0);
-}
-
-static void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_temp_new_i32();
- tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]);
- tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
- tcg_temp_free_i32(t0);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-/* Callback used to write the exception vector base */
-static void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
-}
-
-static void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
-{
- int sprn_offs;
-
- if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
- sprn_offs = sprn - SPR_BOOKE_IVOR0;
- } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
- sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
- } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
- sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
- } else {
- printf("Trying to write an unknown exception vector %d %03x\n",
- sprn, sprn);
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
- return;
- }
-
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
-}
-#endif
-
static inline void vscr_init(CPUPPCState *env, uint32_t val)
{
/* Altivec always uses round-to-nearest */
set_float_rounding_mode(float_round_nearest_even, &env->vec_status);
- helper_mtvscr(env, val);
+ ppc_store_vscr(env, val);
}
/**
@@ -813,7 +151,7 @@ static void _spr_register(CPUPPCState *env, int num, const char *name,
oea_read, oea_write, 0, ival)
/* Generic PowerPC SPRs */
-static void gen_spr_generic(CPUPPCState *env)
+static void register_generic_sprs(CPUPPCState *env)
{
/* Integer processing */
spr_register(env, SPR_XER, "XER",
@@ -858,7 +196,7 @@ static void gen_spr_generic(CPUPPCState *env)
}
/* SPR common to all non-embedded PowerPC, including 601 */
-static void gen_spr_ne_601(CPUPPCState *env)
+static void register_ne_601_sprs(CPUPPCState *env)
{
/* Exception processing */
spr_register_kvm(env, SPR_DSISR, "DSISR",
@@ -877,7 +215,7 @@ static void gen_spr_ne_601(CPUPPCState *env)
}
/* Storage Description Register 1 */
-static void gen_spr_sdr1(CPUPPCState *env)
+static void register_sdr1_sprs(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
if (env->has_hv_mode) {
@@ -900,7 +238,7 @@ static void gen_spr_sdr1(CPUPPCState *env)
}
/* BATs 0-3 */
-static void gen_low_BATs(CPUPPCState *env)
+static void register_low_BATs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_IBAT0U, "IBAT0U",
@@ -972,7 +310,7 @@ static void gen_low_BATs(CPUPPCState *env)
}
/* BATs 4-7 */
-static void gen_high_BATs(CPUPPCState *env)
+static void register_high_BATs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_IBAT4U, "IBAT4U",
@@ -1044,7 +382,7 @@ static void gen_high_BATs(CPUPPCState *env)
}
/* Generic PowerPC time base */
-static void gen_tbl(CPUPPCState *env)
+static void register_tbl(CPUPPCState *env)
{
spr_register(env, SPR_VTBL, "TBL",
&spr_read_tbl, SPR_NOACCESS,
@@ -1065,7 +403,7 @@ static void gen_tbl(CPUPPCState *env)
}
/* Softare table search registers */
-static void gen_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
+static void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
{
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = nb_tlbs;
@@ -1104,7 +442,7 @@ static void gen_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
}
/* SPR common to MPC755 and G2 */
-static void gen_spr_G2_755(CPUPPCState *env)
+static void register_G2_755_sprs(CPUPPCState *env)
{
/* SGPRs */
spr_register(env, SPR_SPRG4, "SPRG4",
@@ -1126,7 +464,7 @@ static void gen_spr_G2_755(CPUPPCState *env)
}
/* SPR common to all 7xx PowerPC implementations */
-static void gen_spr_7xx(CPUPPCState *env)
+static void register_7xx_sprs(CPUPPCState *env)
{
/* Breakpoints */
/* XXX : not implemented */
@@ -1225,106 +563,7 @@ static void gen_spr_7xx(CPUPPCState *env)
}
#ifdef TARGET_PPC64
-#ifndef CONFIG_USER_ONLY
-static void spr_write_amr(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
-
- /*
- * Note, the HV=1 PR=0 case is handled earlier by simply using
- * spr_write_generic for HV mode in the SPR table
- */
-
- /* Build insertion mask into t1 based on context */
- if (ctx->pr) {
- gen_load_spr(t1, SPR_UAMOR);
- } else {
- gen_load_spr(t1, SPR_AMOR);
- }
-
- /* Mask new bits into t2 */
- tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
-
- /* Load AMR and clear new bits in t0 */
- gen_load_spr(t0, SPR_AMR);
- tcg_gen_andc_tl(t0, t0, t1);
-
- /* Or'in new bits and write it out */
- tcg_gen_or_tl(t0, t0, t2);
- gen_store_spr(SPR_AMR, t0);
- spr_store_dump_spr(SPR_AMR);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
-}
-
-static void spr_write_uamor(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
-
- /*
- * Note, the HV=1 case is handled earlier by simply using
- * spr_write_generic for HV mode in the SPR table
- */
-
- /* Build insertion mask into t1 based on context */
- gen_load_spr(t1, SPR_AMOR);
-
- /* Mask new bits into t2 */
- tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
-
- /* Load AMR and clear new bits in t0 */
- gen_load_spr(t0, SPR_UAMOR);
- tcg_gen_andc_tl(t0, t0, t1);
-
- /* Or'in new bits and write it out */
- tcg_gen_or_tl(t0, t0, t2);
- gen_store_spr(SPR_UAMOR, t0);
- spr_store_dump_spr(SPR_UAMOR);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
-}
-
-static void spr_write_iamr(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
-
- /*
- * Note, the HV=1 case is handled earlier by simply using
- * spr_write_generic for HV mode in the SPR table
- */
-
- /* Build insertion mask into t1 based on context */
- gen_load_spr(t1, SPR_AMOR);
-
- /* Mask new bits into t2 */
- tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
-
- /* Load AMR and clear new bits in t0 */
- gen_load_spr(t0, SPR_IAMR);
- tcg_gen_andc_tl(t0, t0, t1);
-
- /* Or'in new bits and write it out */
- tcg_gen_or_tl(t0, t0, t2);
- gen_store_spr(SPR_IAMR, t0);
- spr_store_dump_spr(SPR_IAMR);
-
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
-}
-#endif /* CONFIG_USER_ONLY */
-
-static void gen_spr_amr(CPUPPCState *env)
+static void register_amr_sprs(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
/*
@@ -1356,7 +595,7 @@ static void gen_spr_amr(CPUPPCState *env)
#endif /* !CONFIG_USER_ONLY */
}
-static void gen_spr_iamr(CPUPPCState *env)
+static void register_iamr_sprs(CPUPPCState *env)
{
#ifndef CONFIG_USER_ONLY
spr_register_kvm_hv(env, SPR_IAMR, "IAMR",
@@ -1368,16 +607,7 @@ static void gen_spr_iamr(CPUPPCState *env)
}
#endif /* TARGET_PPC64 */
-#ifndef CONFIG_USER_ONLY
-static void spr_read_thrm(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_fixup_thrm(cpu_env);
- gen_load_spr(cpu_gpr[gprn], sprn);
- spr_load_dump_spr(sprn);
-}
-#endif /* !CONFIG_USER_ONLY */
-
-static void gen_spr_thrm(CPUPPCState *env)
+static void register_thrm_sprs(CPUPPCState *env)
{
/* Thermal management */
/* XXX : not implemented */
@@ -1398,7 +628,7 @@ static void gen_spr_thrm(CPUPPCState *env)
}
/* SPR specific to PowerPC 604 implementation */
-static void gen_spr_604(CPUPPCState *env)
+static void register_604_sprs(CPUPPCState *env)
{
/* Processor identification */
spr_register(env, SPR_PIR, "PIR",
@@ -1451,7 +681,7 @@ static void gen_spr_604(CPUPPCState *env)
}
/* SPR specific to PowerPC 603 implementation */
-static void gen_spr_603(CPUPPCState *env)
+static void register_603_sprs(CPUPPCState *env)
{
/* External access control */
/* XXX : not implemented */
@@ -1469,7 +699,7 @@ static void gen_spr_603(CPUPPCState *env)
}
/* SPR specific to PowerPC G2 implementation */
-static void gen_spr_G2(CPUPPCState *env)
+static void register_G2_sprs(CPUPPCState *env)
{
/* Memory base address */
/* MBAR */
@@ -1521,7 +751,7 @@ static void gen_spr_G2(CPUPPCState *env)
}
/* SPR specific to PowerPC 602 implementation */
-static void gen_spr_602(CPUPPCState *env)
+static void register_602_sprs(CPUPPCState *env)
{
/* ESA registers */
/* XXX : not implemented */
@@ -1569,7 +799,7 @@ static void gen_spr_602(CPUPPCState *env)
}
/* SPR specific to PowerPC 601 implementation */
-static void gen_spr_601(CPUPPCState *env)
+static void register_601_sprs(CPUPPCState *env)
{
/* Multiplication/division register */
/* MQ */
@@ -1645,7 +875,7 @@ static void gen_spr_601(CPUPPCState *env)
#endif
}
-static void gen_spr_74xx(CPUPPCState *env)
+static void register_74xx_sprs(CPUPPCState *env)
{
/* Processor identification */
spr_register(env, SPR_PIR, "PIR",
@@ -1695,7 +925,7 @@ static void gen_spr_74xx(CPUPPCState *env)
0x00000000);
}
-static void gen_l3_ctrl(CPUPPCState *env)
+static void register_l3_ctrl(CPUPPCState *env)
{
/* L3CR */
/* XXX : not implemented */
@@ -1717,7 +947,7 @@ static void gen_l3_ctrl(CPUPPCState *env)
0x00000000);
}
-static void gen_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
+static void register_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
{
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = nb_tlbs;
@@ -1742,58 +972,7 @@ static void gen_74xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways)
#endif
}
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
-
- tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR0_DCE | L1CSR0_CPE);
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
-}
-
-static void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
-
- tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR1_ICE | L1CSR1_CPE);
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
-}
-
-static void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv t0 = tcg_temp_new();
-
- tcg_gen_andi_tl(t0, cpu_gpr[gprn],
- ~(E500_L2CSR0_L2FI | E500_L2CSR0_L2FL | E500_L2CSR0_L2LFC));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
-}
-
-static void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]);
-}
-
-static void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32(sprn);
- gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-static void spr_write_eplc(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]);
-}
-static void spr_write_epsc(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]);
-}
-
-#endif
-
-static void gen_spr_usprg3(CPUPPCState *env)
+static void register_usprg3_sprs(CPUPPCState *env)
{
spr_register(env, SPR_USPRG3, "USPRG3",
&spr_read_ureg, SPR_NOACCESS,
@@ -1801,7 +980,7 @@ static void gen_spr_usprg3(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_usprgh(CPUPPCState *env)
+static void register_usprgh_sprs(CPUPPCState *env)
{
spr_register(env, SPR_USPRG4, "USPRG4",
&spr_read_ureg, SPR_NOACCESS,
@@ -1822,7 +1001,7 @@ static void gen_spr_usprgh(CPUPPCState *env)
}
/* PowerPC BookE SPR */
-static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
+static void register_BookE_sprs(CPUPPCState *env, uint64_t ivor_mask)
{
const char *ivor_names[64] = {
"IVOR0", "IVOR1", "IVOR2", "IVOR3",
@@ -1998,7 +1177,8 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
0x00000000);
}
-static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
+#if !defined(CONFIG_USER_ONLY)
+static inline uint32_t register_tlbncfg(uint32_t assoc, uint32_t minsize,
uint32_t maxsize, uint32_t flags,
uint32_t nentries)
{
@@ -2007,9 +1187,10 @@ static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
(maxsize << TLBnCFG_MAXSIZE_SHIFT) |
flags | nentries;
}
+#endif /* !CONFIG_USER_ONLY */
/* BookE 2.06 storage control registers */
-static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
+static void register_BookE206_sprs(CPUPPCState *env, uint32_t mas_mask,
uint32_t *tlbncfg, uint32_t mmucfg)
{
#if !defined(CONFIG_USER_ONLY)
@@ -2097,11 +1278,11 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
}
#endif
- gen_spr_usprgh(env);
+ register_usprgh_sprs(env);
}
/* SPR specific to PowerPC 440 implementation */
-static void gen_spr_440(CPUPPCState *env)
+static void register_440_sprs(CPUPPCState *env)
{
/* Cache control */
/* XXX : not implemented */
@@ -2242,7 +1423,7 @@ static void gen_spr_440(CPUPPCState *env)
}
/* SPR shared between PowerPC 40x implementations */
-static void gen_spr_40x(CPUPPCState *env)
+static void register_40x_sprs(CPUPPCState *env)
{
/* Cache */
/* not emulated, as QEMU do not emulate caches */
@@ -2297,7 +1478,7 @@ static void gen_spr_40x(CPUPPCState *env)
}
/* SPR specific to PowerPC 405 implementation */
-static void gen_spr_405(CPUPPCState *env)
+static void register_405_sprs(CPUPPCState *env)
{
/* MMU */
spr_register(env, SPR_40x_PID, "PID",
@@ -2399,11 +1580,11 @@ static void gen_spr_405(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
spr_read_generic, &spr_write_generic,
0x00000000);
- gen_spr_usprgh(env);
+ register_usprgh_sprs(env);
}
/* SPR shared between PowerPC 401 & 403 implementations */
-static void gen_spr_401_403(CPUPPCState *env)
+static void register_401_403_sprs(CPUPPCState *env)
{
/* Time base */
spr_register(env, SPR_403_VTBL, "TBL",
@@ -2431,7 +1612,7 @@ static void gen_spr_401_403(CPUPPCState *env)
}
/* SPR specific to PowerPC 401 implementation */
-static void gen_spr_401(CPUPPCState *env)
+static void register_401_sprs(CPUPPCState *env)
{
/* Debug interface */
/* XXX : not implemented */
@@ -2473,9 +1654,9 @@ static void gen_spr_401(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_401x2(CPUPPCState *env)
+static void register_401x2_sprs(CPUPPCState *env)
{
- gen_spr_401(env);
+ register_401_sprs(env);
spr_register(env, SPR_40x_PID, "PID",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -2487,7 +1668,7 @@ static void gen_spr_401x2(CPUPPCState *env)
}
/* SPR specific to PowerPC 403 implementation */
-static void gen_spr_403(CPUPPCState *env)
+static void register_403_sprs(CPUPPCState *env)
{
/* Debug interface */
/* XXX : not implemented */
@@ -2523,7 +1704,7 @@ static void gen_spr_403(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_403_real(CPUPPCState *env)
+static void register_403_real_sprs(CPUPPCState *env)
{
spr_register(env, SPR_403_PBL1, "PBL1",
SPR_NOACCESS, SPR_NOACCESS,
@@ -2543,7 +1724,7 @@ static void gen_spr_403_real(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_403_mmu(CPUPPCState *env)
+static void register_403_mmu_sprs(CPUPPCState *env)
{
/* MMU */
spr_register(env, SPR_40x_PID, "PID",
@@ -2557,7 +1738,7 @@ static void gen_spr_403_mmu(CPUPPCState *env)
}
/* SPR specific to PowerPC compression coprocessor extension */
-static void gen_spr_compress(CPUPPCState *env)
+static void register_compress_sprs(CPUPPCState *env)
{
/* XXX : not implemented */
spr_register(env, SPR_401_SKR, "SKR",
@@ -2566,7 +1747,7 @@ static void gen_spr_compress(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_5xx_8xx(CPUPPCState *env)
+static void register_5xx_8xx_sprs(CPUPPCState *env)
{
/* Exception processing */
spr_register_kvm(env, SPR_DSISR, "DSISR",
@@ -2684,7 +1865,7 @@ static void gen_spr_5xx_8xx(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_5xx(CPUPPCState *env)
+static void register_5xx_sprs(CPUPPCState *env)
{
/* XXX : not implemented */
spr_register(env, SPR_RCPU_MI_GRA, "MI_GRA",
@@ -2793,7 +1974,7 @@ static void gen_spr_5xx(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_8xx(CPUPPCState *env)
+static void register_8xx_sprs(CPUPPCState *env)
{
/* XXX : not implemented */
spr_register(env, SPR_MPC_IC_CST, "IC_CST",
@@ -3528,9 +2709,9 @@ static bool ppc_cpu_interrupts_big_endian_lpcr(PowerPCCPU *cpu)
static void init_proc_401(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_401(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_401_sprs(env);
init_excp_4xx_real(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -3574,10 +2755,10 @@ POWERPC_FAMILY(401)(ObjectClass *oc, void *data)
static void init_proc_401x2(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_401x2(env);
- gen_spr_compress(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_401x2_sprs(env);
+ register_compress_sprs(env);
/* Memory management */
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64;
@@ -3632,11 +2813,11 @@ POWERPC_FAMILY(401x2)(ObjectClass *oc, void *data)
static void init_proc_401x3(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_401(env);
- gen_spr_401x2(env);
- gen_spr_compress(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_401_sprs(env);
+ register_401x2_sprs(env);
+ register_compress_sprs(env);
init_excp_4xx_softmmu(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -3685,10 +2866,10 @@ POWERPC_FAMILY(401x3)(ObjectClass *oc, void *data)
static void init_proc_IOP480(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_401x2(env);
- gen_spr_compress(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_401x2_sprs(env);
+ register_compress_sprs(env);
/* Memory management */
#if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64;
@@ -3743,10 +2924,10 @@ POWERPC_FAMILY(IOP480)(ObjectClass *oc, void *data)
static void init_proc_403(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_403(env);
- gen_spr_403_real(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_403_sprs(env);
+ register_403_real_sprs(env);
init_excp_4xx_real(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -3790,11 +2971,11 @@ POWERPC_FAMILY(403)(ObjectClass *oc, void *data)
static void init_proc_403GCX(CPUPPCState *env)
{
- gen_spr_40x(env);
- gen_spr_401_403(env);
- gen_spr_403(env);
- gen_spr_403_real(env);
- gen_spr_403_mmu(env);
+ register_40x_sprs(env);
+ register_401_403_sprs(env);
+ register_403_sprs(env);
+ register_403_real_sprs(env);
+ register_403_mmu_sprs(env);
/* Bus access control */
/* not emulated, as QEMU never does speculative access */
spr_register(env, SPR_40x_SGR, "SGR",
@@ -3858,9 +3039,9 @@ POWERPC_FAMILY(403GCX)(ObjectClass *oc, void *data)
static void init_proc_405(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_40x(env);
- gen_spr_405(env);
+ register_tbl(env);
+ register_40x_sprs(env);
+ register_405_sprs(env);
/* Bus access control */
/* not emulated, as QEMU never does speculative access */
spr_register(env, SPR_40x_SGR, "SGR",
@@ -3924,10 +3105,10 @@ POWERPC_FAMILY(405)(ObjectClass *oc, void *data)
static void init_proc_440EP(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_BookE(env, 0x000000000000FFFFULL);
- gen_spr_440(env);
- gen_spr_usprgh(env);
+ register_tbl(env);
+ register_BookE_sprs(env, 0x000000000000FFFFULL);
+ register_440_sprs(env);
+ register_usprgh_sprs(env);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4066,10 +3247,10 @@ POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data)
static void init_proc_440GP(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_BookE(env, 0x000000000000FFFFULL);
- gen_spr_440(env);
- gen_spr_usprgh(env);
+ register_tbl(env);
+ register_BookE_sprs(env, 0x000000000000FFFFULL);
+ register_440_sprs(env);
+ register_usprgh_sprs(env);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4149,10 +3330,10 @@ POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data)
static void init_proc_440x4(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_BookE(env, 0x000000000000FFFFULL);
- gen_spr_440(env);
- gen_spr_usprgh(env);
+ register_tbl(env);
+ register_BookE_sprs(env, 0x000000000000FFFFULL);
+ register_440_sprs(env);
+ register_usprgh_sprs(env);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4232,10 +3413,10 @@ POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data)
static void init_proc_440x5(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_BookE(env, 0x000000000000FFFFULL);
- gen_spr_440(env);
- gen_spr_usprgh(env);
+ register_tbl(env);
+ register_BookE_sprs(env, 0x000000000000FFFFULL);
+ register_440_sprs(env);
+ register_usprgh_sprs(env);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4371,9 +3552,9 @@ POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data)
static void init_proc_MPC5xx(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_5xx_8xx(env);
- gen_spr_5xx(env);
+ register_tbl(env);
+ register_5xx_8xx_sprs(env);
+ register_5xx_sprs(env);
init_excp_MPC5xx(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -4415,9 +3596,9 @@ POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data)
static void init_proc_MPC8xx(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_5xx_8xx(env);
- gen_spr_8xx(env);
+ register_tbl(env);
+ register_5xx_8xx_sprs(env);
+ register_8xx_sprs(env);
init_excp_MPC8xx(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -4459,12 +3640,12 @@ POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data)
static void init_proc_G2(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_G2_755(env);
- gen_spr_G2(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_G2_755_sprs(env);
+ register_G2_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
@@ -4488,9 +3669,9 @@ static void init_proc_G2(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_G2(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -4538,12 +3719,12 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data)
static void init_proc_G2LE(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_G2_755(env);
- gen_spr_G2(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_G2_755_sprs(env);
+ register_G2_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* External access control */
/* XXX : not implemented */
spr_register(env, SPR_EAR, "EAR",
@@ -4568,9 +3749,9 @@ static void init_proc_G2LE(CPUPPCState *env)
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_G2(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -4621,15 +3802,15 @@ POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data)
static void init_proc_e200(CPUPPCState *env)
{
/* Time base */
- gen_tbl(env);
- gen_spr_BookE(env, 0x000000070000FFFFULL);
+ register_tbl(env);
+ register_BookE_sprs(env, 0x000000070000FFFFULL);
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_SPEFSCR, "SPEFSCR",
&spr_read_spefscr, &spr_write_spefscr,
&spr_read_spefscr, &spr_write_spefscr,
0x00000000);
/* Memory management */
- gen_spr_BookE206(env, 0x0000005D, NULL, 0);
+ register_BookE206_sprs(env, 0x0000005D, NULL, 0);
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4775,11 +3956,11 @@ POWERPC_FAMILY(e200)(ObjectClass *oc, void *data)
static void init_proc_e300(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_603(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_603_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -4823,9 +4004,9 @@ static void init_proc_e300(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_603(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -4873,31 +4054,6 @@ POWERPC_FAMILY(e300)(ObjectClass *oc, void *data)
POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK;
}
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_mas73(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv val = tcg_temp_new();
- tcg_gen_ext32u_tl(val, cpu_gpr[gprn]);
- gen_store_spr(SPR_BOOKE_MAS3, val);
- tcg_gen_shri_tl(val, cpu_gpr[gprn], 32);
- gen_store_spr(SPR_BOOKE_MAS7, val);
- tcg_temp_free(val);
-}
-
-static void spr_read_mas73(DisasContext *ctx, int gprn, int sprn)
-{
- TCGv mas7 = tcg_temp_new();
- TCGv mas3 = tcg_temp_new();
- gen_load_spr(mas7, SPR_BOOKE_MAS7);
- tcg_gen_shli_tl(mas7, mas7, 32);
- gen_load_spr(mas3, SPR_BOOKE_MAS3);
- tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7);
- tcg_temp_free(mas3);
- tcg_temp_free(mas7);
-}
-
-#endif
-
enum fsl_e500_version {
fsl_e500v1,
fsl_e500v2,
@@ -4921,11 +4077,11 @@ static void init_proc_e500(CPUPPCState *env, int version)
#endif
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/*
* XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
* complain when accessing them.
- * gen_spr_BookE(env, 0x0000000F0000FD7FULL);
+ * register_BookE_sprs(env, 0x0000000F0000FD7FULL);
*/
switch (version) {
case fsl_e500v1:
@@ -4941,8 +4097,8 @@ static void init_proc_e500(CPUPPCState *env, int version)
ivor_mask = 0x000003FF0000FFFFULL;
break;
}
- gen_spr_BookE(env, ivor_mask);
- gen_spr_usprg3(env);
+ register_BookE_sprs(env, ivor_mask);
+ register_usprg3_sprs(env);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4960,17 +4116,17 @@ static void init_proc_e500(CPUPPCState *env, int version)
env->id_tlbs = 0;
switch (version) {
case fsl_e500v1:
- tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
- tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+ tlbncfg[0] = register_tlbncfg(2, 1, 1, 0, 256);
+ tlbncfg[1] = register_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
break;
case fsl_e500v2:
- tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
- tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
+ tlbncfg[0] = register_tlbncfg(4, 1, 1, 0, 512);
+ tlbncfg[1] = register_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
break;
case fsl_e500mc:
case fsl_e5500:
- tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
- tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
+ tlbncfg[0] = register_tlbncfg(4, 1, 1, 0, 512);
+ tlbncfg[1] = register_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
break;
case fsl_e6500:
mmucfg = 0x6510B45;
@@ -5007,7 +4163,7 @@ static void init_proc_e500(CPUPPCState *env, int version)
cpu_abort(env_cpu(env), "Unknown CPU: " TARGET_FMT_lx "\n",
env->spr[SPR_PVR]);
}
- gen_spr_BookE206(env, 0x000000DF, tlbncfg, mmucfg);
+ register_BookE206_sprs(env, 0x000000DF, tlbncfg, mmucfg);
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -5365,9 +4521,9 @@ POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data)
static void init_proc_601(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_601(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_601_sprs(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5481,11 +4637,11 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
static void init_proc_602(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_602(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_602_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5498,8 +4654,8 @@ static void init_proc_602(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_602(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5551,11 +4707,11 @@ POWERPC_FAMILY(602)(ObjectClass *oc, void *data)
static void init_proc_603(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_603(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_603_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5568,8 +4724,8 @@ static void init_proc_603(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_603(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5618,11 +4774,11 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data)
static void init_proc_603E(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_603(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_603_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5635,8 +4791,8 @@ static void init_proc_603E(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_603(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5685,11 +4841,11 @@ POWERPC_FAMILY(603E)(ObjectClass *oc, void *data)
static void init_proc_604(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_604(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_604_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5697,7 +4853,7 @@ static void init_proc_604(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
init_excp_604(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5749,9 +4905,9 @@ POWERPC_FAMILY(604)(ObjectClass *oc, void *data)
static void init_proc_604E(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_604(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_604_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_7XX_MMCR1, "MMCR1",
SPR_NOACCESS, SPR_NOACCESS,
@@ -5768,7 +4924,7 @@ static void init_proc_604E(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5781,7 +4937,7 @@ static void init_proc_604E(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
init_excp_604(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5833,13 +4989,13 @@ POWERPC_FAMILY(604E)(ObjectClass *oc, void *data)
static void init_proc_740(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5852,7 +5008,7 @@ static void init_proc_740(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
init_excp_7x0(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -5904,18 +5060,18 @@ POWERPC_FAMILY(740)(ObjectClass *oc, void *data)
static void init_proc_750(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -5928,7 +5084,7 @@ static void init_proc_750(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
/*
* XXX: high BATs are also present but are known to be bugged on
* die version 1.x
@@ -5984,16 +5140,16 @@ POWERPC_FAMILY(750)(ObjectClass *oc, void *data)
static void init_proc_750cl(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
/* Those registers are fake on 750CL */
spr_register(env, SPR_THRM1, "THRM1",
@@ -6094,9 +5250,9 @@ static void init_proc_750cl(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
/* PowerPC 750cl has 8 DBATs and 8 IBATs */
- gen_high_BATs(env);
+ register_high_BATs(env);
init_excp_750cl(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6187,18 +5343,18 @@ POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data)
static void init_proc_750cx(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* This register is not implemented but is present for compatibility */
spr_register(env, SPR_SDA, "SDA",
SPR_NOACCESS, SPR_NOACCESS,
@@ -6216,9 +5372,9 @@ static void init_proc_750cx(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
/* PowerPC 750cx has 8 DBATs and 8 IBATs */
- gen_high_BATs(env);
+ register_high_BATs(env);
init_excp_750cx(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6270,18 +5426,18 @@ POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data)
static void init_proc_750fx(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_750_THRM4, "THRM4",
SPR_NOACCESS, SPR_NOACCESS,
@@ -6304,9 +5460,9 @@ static void init_proc_750fx(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
/* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
- gen_high_BATs(env);
+ register_high_BATs(env);
init_excp_7x0(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6358,18 +5514,18 @@ POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data)
static void init_proc_750gx(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* XXX : not implemented (XXX: different from 750fx) */
spr_register(env, SPR_L2CR, "L2CR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, spr_access_nop,
0x00000000);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* XXX : not implemented */
spr_register(env, SPR_750_THRM4, "THRM4",
SPR_NOACCESS, SPR_NOACCESS,
@@ -6392,9 +5548,9 @@ static void init_proc_750gx(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
/* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
- gen_high_BATs(env);
+ register_high_BATs(env);
init_excp_7x0(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6446,14 +5602,14 @@ POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data)
static void init_proc_745(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
- gen_spr_G2_755(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
+ register_G2_755_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -6471,9 +5627,9 @@ static void init_proc_745(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_7x5(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6522,12 +5678,12 @@ POWERPC_FAMILY(745)(ObjectClass *oc, void *data)
static void init_proc_755(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
- gen_spr_G2_755(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
+ register_G2_755_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* L2 cache control */
/* XXX : not implemented */
spr_register(env, SPR_L2CR, "L2CR",
@@ -6540,7 +5696,7 @@ static void init_proc_755(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -6558,9 +5714,9 @@ static void init_proc_755(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_6xx_7xx_soft_tlb(env, 64, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_6xx_7xx_soft_tlb(env, 64, 2);
init_excp_7x5(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6609,13 +5765,13 @@ POWERPC_FAMILY(755)(ObjectClass *oc, void *data)
static void init_proc_7400(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
@@ -6629,9 +5785,9 @@ static void init_proc_7400(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
init_excp_7400(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6689,13 +5845,13 @@ POWERPC_FAMILY(7400)(ObjectClass *oc, void *data)
static void init_proc_7410(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
@@ -6703,7 +5859,7 @@ static void init_proc_7410(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Thermal management */
- gen_spr_thrm(env);
+ register_thrm_sprs(env);
/* L2PMCR */
/* XXX : not implemented */
spr_register(env, SPR_L2PMCR, "L2PMCR",
@@ -6717,7 +5873,7 @@ static void init_proc_7410(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
+ register_low_BATs(env);
init_excp_7400(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6775,13 +5931,13 @@ POWERPC_FAMILY(7410)(ObjectClass *oc, void *data)
static void init_proc_7440(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
@@ -6828,8 +5984,8 @@ static void init_proc_7440(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -6884,16 +6040,16 @@ POWERPC_FAMILY(7440)(ObjectClass *oc, void *data)
static void init_proc_7450(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
- gen_l3_ctrl(env);
+ register_l3_ctrl(env);
/* L3ITCR1 */
/* XXX : not implemented */
spr_register(env, SPR_L3ITCR1, "L3ITCR1",
@@ -6963,8 +6119,8 @@ static void init_proc_7450(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -7019,13 +6175,13 @@ POWERPC_FAMILY(7450)(ObjectClass *oc, void *data)
static void init_proc_7445(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* LDSTCR */
/* XXX : not implemented */
@@ -7100,9 +6256,9 @@ static void init_proc_7445(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -7157,16 +6313,16 @@ POWERPC_FAMILY(7445)(ObjectClass *oc, void *data)
static void init_proc_7455(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
- gen_l3_ctrl(env);
+ register_l3_ctrl(env);
/* LDSTCR */
/* XXX : not implemented */
spr_register(env, SPR_LDSTCR, "LDSTCR",
@@ -7240,9 +6396,9 @@ static void init_proc_7455(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -7297,16 +6453,16 @@ POWERPC_FAMILY(7455)(ObjectClass *oc, void *data)
static void init_proc_7457(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* Level 3 cache control */
- gen_l3_ctrl(env);
+ register_l3_ctrl(env);
/* L3ITCR1 */
/* XXX : not implemented */
spr_register(env, SPR_L3ITCR1, "L3ITCR1",
@@ -7404,9 +6560,9 @@ static void init_proc_7457(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -7461,13 +6617,13 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data)
static void init_proc_e600(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_spr_sdr1(env);
- gen_spr_7xx(env);
+ register_ne_601_sprs(env);
+ register_sdr1_sprs(env);
+ register_7xx_sprs(env);
/* Time base */
- gen_tbl(env);
+ register_tbl(env);
/* 74xx specific SPR */
- gen_spr_74xx(env);
+ register_74xx_sprs(env);
vscr_init(env, 0x00010000);
/* XXX : not implemented */
spr_register(env, SPR_UBAMR, "UBAMR",
@@ -7543,9 +6699,9 @@ static void init_proc_e600(CPUPPCState *env)
&spr_read_ureg, SPR_NOACCESS,
0x00000000);
/* Memory management */
- gen_low_BATs(env);
- gen_high_BATs(env);
- gen_74xx_soft_tlb(env, 128, 2);
+ register_low_BATs(env);
+ register_high_BATs(env);
+ register_74xx_soft_tlb(env, 128, 2);
init_excp_7450(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
@@ -7609,58 +6765,6 @@ POWERPC_FAMILY(e600)(ObjectClass *oc, void *data)
#define POWERPC970_HID5_INIT 0x00000000
#endif
-static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
- int bit, int sprn, int cause)
-{
- TCGv_i32 t1 = tcg_const_i32(bit);
- TCGv_i32 t2 = tcg_const_i32(sprn);
- TCGv_i32 t3 = tcg_const_i32(cause);
-
- gen_helper_fscr_facility_check(cpu_env, t1, t2, t3);
-
- tcg_temp_free_i32(t3);
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t1);
-}
-
-static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn,
- int bit, int sprn, int cause)
-{
- TCGv_i32 t1 = tcg_const_i32(bit);
- TCGv_i32 t2 = tcg_const_i32(sprn);
- TCGv_i32 t3 = tcg_const_i32(cause);
-
- gen_helper_msr_facility_check(cpu_env, t1, t2, t3);
-
- tcg_temp_free_i32(t3);
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t1);
-}
-
-static void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn)
-{
- TCGv spr_up = tcg_temp_new();
- TCGv spr = tcg_temp_new();
-
- gen_load_spr(spr, sprn - 1);
- tcg_gen_shri_tl(spr_up, spr, 32);
- tcg_gen_ext32u_tl(cpu_gpr[gprn], spr_up);
-
- tcg_temp_free(spr);
- tcg_temp_free(spr_up);
-}
-
-static void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv spr = tcg_temp_new();
-
- gen_load_spr(spr, sprn - 1);
- tcg_gen_deposit_tl(spr, spr, cpu_gpr[gprn], 32, 32);
- gen_store_spr(sprn - 1, spr);
-
- tcg_temp_free(spr);
-}
-
static int check_pow_970(CPUPPCState *env)
{
if (env->spr[SPR_HID0] & (HID0_DEEPNAP | HID0_DOZE | HID0_NAP)) {
@@ -7670,7 +6774,7 @@ static int check_pow_970(CPUPPCState *env)
return 0;
}
-static void gen_spr_970_hid(CPUPPCState *env)
+static void register_970_hid_sprs(CPUPPCState *env)
{
/* Hardware implementation registers */
/* XXX : not implemented */
@@ -7688,7 +6792,7 @@ static void gen_spr_970_hid(CPUPPCState *env)
POWERPC970_HID5_INIT);
}
-static void gen_spr_970_hior(CPUPPCState *env)
+static void register_970_hior_sprs(CPUPPCState *env)
{
spr_register(env, SPR_HIOR, "SPR_HIOR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7696,7 +6800,7 @@ static void gen_spr_970_hior(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_book3s_ctrl(CPUPPCState *env)
+static void register_book3s_ctrl_sprs(CPUPPCState *env)
{
spr_register(env, SPR_CTRL, "SPR_CTRL",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7708,7 +6812,7 @@ static void gen_spr_book3s_ctrl(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_book3s_altivec(CPUPPCState *env)
+static void register_book3s_altivec_sprs(CPUPPCState *env)
{
if (!(env->insns_flags & PPC_ALTIVEC)) {
return;
@@ -7721,7 +6825,7 @@ static void gen_spr_book3s_altivec(CPUPPCState *env)
}
-static void gen_spr_book3s_dbg(CPUPPCState *env)
+static void register_book3s_dbg_sprs(CPUPPCState *env)
{
/*
* TODO: different specs define different scopes for these,
@@ -7740,7 +6844,7 @@ static void gen_spr_book3s_dbg(CPUPPCState *env)
KVM_REG_PPC_DABRX, 0x00000000);
}
-static void gen_spr_book3s_207_dbg(CPUPPCState *env)
+static void register_book3s_207_dbg_sprs(CPUPPCState *env)
{
spr_register_kvm_hv(env, SPR_DAWR0, "DAWR0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7759,7 +6863,7 @@ static void gen_spr_book3s_207_dbg(CPUPPCState *env)
KVM_REG_PPC_CIABR, 0x00000000);
}
-static void gen_spr_970_dbg(CPUPPCState *env)
+static void register_970_dbg_sprs(CPUPPCState *env)
{
/* Breakpoints */
spr_register(env, SPR_IABR, "IABR",
@@ -7768,7 +6872,7 @@ static void gen_spr_970_dbg(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_book3s_pmu_sup(CPUPPCState *env)
+static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_POWER_MMCR0, "MMCR0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7816,7 +6920,7 @@ static void gen_spr_book3s_pmu_sup(CPUPPCState *env)
KVM_REG_PPC_SDAR, 0x00000000);
}
-static void gen_spr_book3s_pmu_user(CPUPPCState *env)
+static void register_book3s_pmu_user_sprs(CPUPPCState *env)
{
spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
&spr_read_ureg, SPR_NOACCESS,
@@ -7864,7 +6968,7 @@ static void gen_spr_book3s_pmu_user(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_970_pmu_sup(CPUPPCState *env)
+static void register_970_pmu_sup_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_970_PMC7, "PMC7",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7876,7 +6980,7 @@ static void gen_spr_970_pmu_sup(CPUPPCState *env)
KVM_REG_PPC_PMC8, 0x00000000);
}
-static void gen_spr_970_pmu_user(CPUPPCState *env)
+static void register_970_pmu_user_sprs(CPUPPCState *env)
{
spr_register(env, SPR_970_UPMC7, "UPMC7",
&spr_read_ureg, SPR_NOACCESS,
@@ -7888,7 +6992,7 @@ static void gen_spr_970_pmu_user(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_power8_pmu_sup(CPUPPCState *env)
+static void register_power8_pmu_sup_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_POWER_MMCR2, "MMCR2",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7924,7 +7028,7 @@ static void gen_spr_power8_pmu_sup(CPUPPCState *env)
KVM_REG_PPC_CSIGR, 0x00000000);
}
-static void gen_spr_power8_pmu_user(CPUPPCState *env)
+static void register_power8_pmu_user_sprs(CPUPPCState *env)
{
spr_register(env, SPR_POWER_UMMCR2, "UMMCR2",
&spr_read_ureg, SPR_NOACCESS,
@@ -7936,7 +7040,7 @@ static void gen_spr_power8_pmu_user(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_power5p_ear(CPUPPCState *env)
+static void register_power5p_ear_sprs(CPUPPCState *env)
{
/* External access control */
spr_register(env, SPR_EAR, "EAR",
@@ -7945,7 +7049,7 @@ static void gen_spr_power5p_ear(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_power5p_tb(CPUPPCState *env)
+static void register_power5p_tb_sprs(CPUPPCState *env)
{
/* TBU40 (High 40 bits of the Timebase register */
spr_register_hv(env, SPR_TBU40, "TBU40",
@@ -7955,25 +7059,7 @@ static void gen_spr_power5p_tb(CPUPPCState *env)
0x00000000);
}
-#if !defined(CONFIG_USER_ONLY)
-static void spr_write_hmer(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv hmer = tcg_temp_new();
-
- gen_load_spr(hmer, sprn);
- tcg_gen_and_tl(hmer, cpu_gpr[gprn], hmer);
- gen_store_spr(sprn, hmer);
- spr_store_dump_spr(sprn);
- tcg_temp_free(hmer);
-}
-
-static void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
-}
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-static void gen_spr_970_lpar(CPUPPCState *env)
+static void register_970_lpar_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/*
@@ -7990,7 +7076,7 @@ static void gen_spr_970_lpar(CPUPPCState *env)
#endif
}
-static void gen_spr_power5p_lpar(CPUPPCState *env)
+static void register_power5p_lpar_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* Logical partitionning */
@@ -8006,7 +7092,7 @@ static void gen_spr_power5p_lpar(CPUPPCState *env)
#endif
}
-static void gen_spr_book3s_ids(CPUPPCState *env)
+static void register_book3s_ids_sprs(CPUPPCState *env)
{
/* FIXME: Will need to deal with thread vs core only SPRs */
@@ -8098,7 +7184,7 @@ static void gen_spr_book3s_ids(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_rmor(CPUPPCState *env)
+static void register_rmor_sprs(CPUPPCState *env)
{
spr_register_hv(env, SPR_RMOR, "RMOR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -8107,7 +7193,7 @@ static void gen_spr_rmor(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_power8_ids(CPUPPCState *env)
+static void register_power8_ids_sprs(CPUPPCState *env)
{
/* Thread identification */
spr_register(env, SPR_TIR, "TIR",
@@ -8116,7 +7202,7 @@ static void gen_spr_power8_ids(CPUPPCState *env)
0x00000000);
}
-static void gen_spr_book3s_purr(CPUPPCState *env)
+static void register_book3s_purr_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* PURR & SPURR: Hack - treat these as aliases for the TB for now */
@@ -8133,7 +7219,7 @@ static void gen_spr_book3s_purr(CPUPPCState *env)
#endif
}
-static void gen_spr_power6_dbg(CPUPPCState *env)
+static void register_power6_dbg_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register(env, SPR_CFAR, "SPR_CFAR",
@@ -8143,7 +7229,7 @@ static void gen_spr_power6_dbg(CPUPPCState *env)
#endif
}
-static void gen_spr_power5p_common(CPUPPCState *env)
+static void register_power5p_common_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_PPR, "PPR",
&spr_read_generic, &spr_write_generic,
@@ -8151,7 +7237,7 @@ static void gen_spr_power5p_common(CPUPPCState *env)
KVM_REG_PPC_PPR, 0x00000000);
}
-static void gen_spr_power6_common(CPUPPCState *env)
+static void register_power6_common_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register_kvm(env, SPR_DSCR, "SPR_DSCR",
@@ -8170,19 +7256,7 @@ static void gen_spr_power6_common(CPUPPCState *env)
0x00000000);
}
-static void spr_read_tar(DisasContext *ctx, int gprn, int sprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR);
- spr_read_generic(ctx, gprn, sprn);
-}
-
-static void spr_write_tar(DisasContext *ctx, int sprn, int gprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR);
- spr_write_generic(ctx, sprn, gprn);
-}
-
-static void gen_spr_power8_tce_address_control(CPUPPCState *env)
+static void register_power8_tce_address_control_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_TAR, "TAR",
&spr_read_tar, &spr_write_tar,
@@ -8190,31 +7264,7 @@ static void gen_spr_power8_tce_address_control(CPUPPCState *env)
KVM_REG_PPC_TAR, 0x00000000);
}
-static void spr_read_tm(DisasContext *ctx, int gprn, int sprn)
-{
- gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
- spr_read_generic(ctx, gprn, sprn);
-}
-
-static void spr_write_tm(DisasContext *ctx, int sprn, int gprn)
-{
- gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
- spr_write_generic(ctx, sprn, gprn);
-}
-
-static void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn)
-{
- gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
- spr_read_prev_upper32(ctx, gprn, sprn);
-}
-
-static void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn)
-{
- gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
- spr_write_prev_upper32(ctx, sprn, gprn);
-}
-
-static void gen_spr_power8_tm(CPUPPCState *env)
+static void register_power8_tm_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_TFHAR, "TFHAR",
&spr_read_tm, &spr_write_tm,
@@ -8234,31 +7284,7 @@ static void gen_spr_power8_tm(CPUPPCState *env)
0x00000000);
}
-static void spr_read_ebb(DisasContext *ctx, int gprn, int sprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
- spr_read_generic(ctx, gprn, sprn);
-}
-
-static void spr_write_ebb(DisasContext *ctx, int sprn, int gprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
- spr_write_generic(ctx, sprn, gprn);
-}
-
-static void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
- spr_read_prev_upper32(ctx, gprn, sprn);
-}
-
-static void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn)
-{
- gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
- spr_write_prev_upper32(ctx, sprn, gprn);
-}
-
-static void gen_spr_power8_ebb(CPUPPCState *env)
+static void register_power8_ebb_sprs(CPUPPCState *env)
{
spr_register(env, SPR_BESCRS, "BESCRS",
&spr_read_ebb, &spr_write_ebb,
@@ -8291,7 +7317,7 @@ static void gen_spr_power8_ebb(CPUPPCState *env)
}
/* Virtual Time Base */
-static void gen_spr_vtb(CPUPPCState *env)
+static void register_vtb_sprs(CPUPPCState *env)
{
spr_register_kvm_hv(env, SPR_VTB, "VTB",
SPR_NOACCESS, SPR_NOACCESS,
@@ -8300,7 +7326,7 @@ static void gen_spr_vtb(CPUPPCState *env)
KVM_REG_PPC_VTB, 0x00000000);
}
-static void gen_spr_power8_fscr(CPUPPCState *env)
+static void register_power8_fscr_sprs(CPUPPCState *env)
{
#if defined(CONFIG_USER_ONLY)
target_ulong initval = 1ULL << FSCR_TAR;
@@ -8313,7 +7339,7 @@ static void gen_spr_power8_fscr(CPUPPCState *env)
KVM_REG_PPC_FSCR, initval);
}
-static void gen_spr_power8_pspb(CPUPPCState *env)
+static void register_power8_pspb_sprs(CPUPPCState *env)
{
spr_register_kvm(env, SPR_PSPB, "PSPB",
SPR_NOACCESS, SPR_NOACCESS,
@@ -8321,7 +7347,7 @@ static void gen_spr_power8_pspb(CPUPPCState *env)
KVM_REG_PPC_PSPB, 0);
}
-static void gen_spr_power8_dpdes(CPUPPCState *env)
+static void register_power8_dpdes_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* Directed Privileged Door-bell Exception State, used for IPI */
@@ -8333,7 +7359,7 @@ static void gen_spr_power8_dpdes(CPUPPCState *env)
#endif
}
-static void gen_spr_power8_ic(CPUPPCState *env)
+static void register_power8_ic_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register_hv(env, SPR_IC, "IC",
@@ -8344,7 +7370,7 @@ static void gen_spr_power8_ic(CPUPPCState *env)
#endif
}
-static void gen_spr_power8_book4(CPUPPCState *env)
+static void register_power8_book4_sprs(CPUPPCState *env)
{
/* Add a number of P8 book4 registers */
#if !defined(CONFIG_USER_ONLY)
@@ -8363,7 +7389,7 @@ static void gen_spr_power8_book4(CPUPPCState *env)
#endif
}
-static void gen_spr_power7_book4(CPUPPCState *env)
+static void register_power7_book4_sprs(CPUPPCState *env)
{
/* Add a number of P7 book4 registers */
#if !defined(CONFIG_USER_ONLY)
@@ -8378,7 +7404,7 @@ static void gen_spr_power7_book4(CPUPPCState *env)
#endif
}
-static void gen_spr_power8_rpr(CPUPPCState *env)
+static void register_power8_rpr_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
spr_register_hv(env, SPR_RPR, "RPR",
@@ -8389,7 +7415,7 @@ static void gen_spr_power8_rpr(CPUPPCState *env)
#endif
}
-static void gen_spr_power9_mmu(CPUPPCState *env)
+static void register_power9_mmu_sprs(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* Partition Table Control */
@@ -8409,13 +7435,13 @@ static void gen_spr_power9_mmu(CPUPPCState *env)
static void init_proc_book3s_common(CPUPPCState *env)
{
- gen_spr_ne_601(env);
- gen_tbl(env);
- gen_spr_usprg3(env);
- gen_spr_book3s_altivec(env);
- gen_spr_book3s_pmu_sup(env);
- gen_spr_book3s_pmu_user(env);
- gen_spr_book3s_ctrl(env);
+ register_ne_601_sprs(env);
+ register_tbl(env);
+ register_usprg3_sprs(env);
+ register_book3s_altivec_sprs(env);
+ register_book3s_pmu_sup_sprs(env);
+ register_book3s_pmu_user_sprs(env);
+ register_book3s_ctrl_sprs(env);
/*
* Can't find information on what this should be on reset. This
* value is the one used by 74xx processors.
@@ -8427,17 +7453,17 @@ static void init_proc_970(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_sdr1(env);
- gen_spr_book3s_dbg(env);
+ register_sdr1_sprs(env);
+ register_book3s_dbg_sprs(env);
/* 970 Specific Registers */
- gen_spr_970_hid(env);
- gen_spr_970_hior(env);
- gen_low_BATs(env);
- gen_spr_970_pmu_sup(env);
- gen_spr_970_pmu_user(env);
- gen_spr_970_lpar(env);
- gen_spr_970_dbg(env);
+ register_970_hid_sprs(env);
+ register_970_hior_sprs(env);
+ register_low_BATs(env);
+ register_970_pmu_sup_sprs(env);
+ register_970_pmu_user_sprs(env);
+ register_970_lpar_sprs(env);
+ register_970_dbg_sprs(env);
/* env variables */
env->dcache_line_size = 128;
@@ -8500,19 +7526,19 @@ static void init_proc_power5plus(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_sdr1(env);
- gen_spr_book3s_dbg(env);
+ register_sdr1_sprs(env);
+ register_book3s_dbg_sprs(env);
/* POWER5+ Specific Registers */
- gen_spr_970_hid(env);
- gen_spr_970_hior(env);
- gen_low_BATs(env);
- gen_spr_970_pmu_sup(env);
- gen_spr_970_pmu_user(env);
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- gen_spr_power5p_tb(env);
+ register_970_hid_sprs(env);
+ register_970_hior_sprs(env);
+ register_low_BATs(env);
+ register_970_pmu_sup_sprs(env);
+ register_970_pmu_user_sprs(env);
+ register_power5p_common_sprs(env);
+ register_power5p_lpar_sprs(env);
+ register_power5p_ear_sprs(env);
+ register_power5p_tb_sprs(env);
/* env variables */
env->dcache_line_size = 128;
@@ -8579,21 +7605,21 @@ static void init_proc_POWER7(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_sdr1(env);
- gen_spr_book3s_dbg(env);
+ register_sdr1_sprs(env);
+ register_book3s_dbg_sprs(env);
/* POWER7 Specific Registers */
- gen_spr_book3s_ids(env);
- gen_spr_rmor(env);
- gen_spr_amr(env);
- gen_spr_book3s_purr(env);
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- gen_spr_power5p_tb(env);
- gen_spr_power6_common(env);
- gen_spr_power6_dbg(env);
- gen_spr_power7_book4(env);
+ register_book3s_ids_sprs(env);
+ register_rmor_sprs(env);
+ register_amr_sprs(env);
+ register_book3s_purr_sprs(env);
+ register_power5p_common_sprs(env);
+ register_power5p_lpar_sprs(env);
+ register_power5p_ear_sprs(env);
+ register_power5p_tb_sprs(env);
+ register_power6_common_sprs(env);
+ register_power6_dbg_sprs(env);
+ register_power7_book4_sprs(env);
/* env variables */
env->dcache_line_size = 128;
@@ -8725,34 +7751,34 @@ static void init_proc_POWER8(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_sdr1(env);
- gen_spr_book3s_207_dbg(env);
+ register_sdr1_sprs(env);
+ register_book3s_207_dbg_sprs(env);
/* POWER8 Specific Registers */
- gen_spr_book3s_ids(env);
- gen_spr_rmor(env);
- gen_spr_amr(env);
- gen_spr_iamr(env);
- gen_spr_book3s_purr(env);
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- gen_spr_power5p_tb(env);
- gen_spr_power6_common(env);
- gen_spr_power6_dbg(env);
- gen_spr_power8_tce_address_control(env);
- gen_spr_power8_ids(env);
- gen_spr_power8_ebb(env);
- gen_spr_power8_fscr(env);
- gen_spr_power8_pmu_sup(env);
- gen_spr_power8_pmu_user(env);
- gen_spr_power8_tm(env);
- gen_spr_power8_pspb(env);
- gen_spr_power8_dpdes(env);
- gen_spr_vtb(env);
- gen_spr_power8_ic(env);
- gen_spr_power8_book4(env);
- gen_spr_power8_rpr(env);
+ register_book3s_ids_sprs(env);
+ register_rmor_sprs(env);
+ register_amr_sprs(env);
+ register_iamr_sprs(env);
+ register_book3s_purr_sprs(env);
+ register_power5p_common_sprs(env);
+ register_power5p_lpar_sprs(env);
+ register_power5p_ear_sprs(env);
+ register_power5p_tb_sprs(env);
+ register_power6_common_sprs(env);
+ register_power6_dbg_sprs(env);
+ register_power8_tce_address_control_sprs(env);
+ register_power8_ids_sprs(env);
+ register_power8_ebb_sprs(env);
+ register_power8_fscr_sprs(env);
+ register_power8_pmu_sup_sprs(env);
+ register_power8_pmu_user_sprs(env);
+ register_power8_tm_sprs(env);
+ register_power8_pspb_sprs(env);
+ register_power8_dpdes_sprs(env);
+ register_vtb_sprs(env);
+ register_power8_ic_sprs(env);
+ register_power8_book4_sprs(env);
+ register_power8_rpr_sprs(env);
/* env variables */
env->dcache_line_size = 128;
@@ -8922,33 +7948,33 @@ static void init_proc_POWER9(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_book3s_207_dbg(env);
+ register_book3s_207_dbg_sprs(env);
/* POWER8 Specific Registers */
- gen_spr_book3s_ids(env);
- gen_spr_amr(env);
- gen_spr_iamr(env);
- gen_spr_book3s_purr(env);
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- gen_spr_power5p_tb(env);
- gen_spr_power6_common(env);
- gen_spr_power6_dbg(env);
- gen_spr_power8_tce_address_control(env);
- gen_spr_power8_ids(env);
- gen_spr_power8_ebb(env);
- gen_spr_power8_fscr(env);
- gen_spr_power8_pmu_sup(env);
- gen_spr_power8_pmu_user(env);
- gen_spr_power8_tm(env);
- gen_spr_power8_pspb(env);
- gen_spr_power8_dpdes(env);
- gen_spr_vtb(env);
- gen_spr_power8_ic(env);
- gen_spr_power8_book4(env);
- gen_spr_power8_rpr(env);
- gen_spr_power9_mmu(env);
+ register_book3s_ids_sprs(env);
+ register_amr_sprs(env);
+ register_iamr_sprs(env);
+ register_book3s_purr_sprs(env);
+ register_power5p_common_sprs(env);
+ register_power5p_lpar_sprs(env);
+ register_power5p_ear_sprs(env);
+ register_power5p_tb_sprs(env);
+ register_power6_common_sprs(env);
+ register_power6_dbg_sprs(env);
+ register_power8_tce_address_control_sprs(env);
+ register_power8_ids_sprs(env);
+ register_power8_ebb_sprs(env);
+ register_power8_fscr_sprs(env);
+ register_power8_pmu_sup_sprs(env);
+ register_power8_pmu_user_sprs(env);
+ register_power8_tm_sprs(env);
+ register_power8_pspb_sprs(env);
+ register_power8_dpdes_sprs(env);
+ register_vtb_sprs(env);
+ register_power8_ic_sprs(env);
+ register_power8_book4_sprs(env);
+ register_power8_rpr_sprs(env);
+ register_power9_mmu_sprs(env);
/* POWER9 Specific registers */
spr_register_kvm(env, SPR_TIDR, "TIDR", NULL, NULL,
@@ -9140,31 +8166,31 @@ static void init_proc_POWER10(CPUPPCState *env)
{
/* Common Registers */
init_proc_book3s_common(env);
- gen_spr_book3s_207_dbg(env);
+ register_book3s_207_dbg_sprs(env);
/* POWER8 Specific Registers */
- gen_spr_book3s_ids(env);
- gen_spr_amr(env);
- gen_spr_iamr(env);
- gen_spr_book3s_purr(env);
- gen_spr_power5p_common(env);
- gen_spr_power5p_lpar(env);
- gen_spr_power5p_ear(env);
- gen_spr_power6_common(env);
- gen_spr_power6_dbg(env);
- gen_spr_power8_tce_address_control(env);
- gen_spr_power8_ids(env);
- gen_spr_power8_ebb(env);
- gen_spr_power8_fscr(env);
- gen_spr_power8_pmu_sup(env);
- gen_spr_power8_pmu_user(env);
- gen_spr_power8_tm(env);
- gen_spr_power8_pspb(env);
- gen_spr_vtb(env);
- gen_spr_power8_ic(env);
- gen_spr_power8_book4(env);
- gen_spr_power8_rpr(env);
- gen_spr_power9_mmu(env);
+ register_book3s_ids_sprs(env);
+ register_amr_sprs(env);
+ register_iamr_sprs(env);
+ register_book3s_purr_sprs(env);
+ register_power5p_common_sprs(env);
+ register_power5p_lpar_sprs(env);
+ register_power5p_ear_sprs(env);
+ register_power6_common_sprs(env);
+ register_power6_dbg_sprs(env);
+ register_power8_tce_address_control_sprs(env);
+ register_power8_ids_sprs(env);
+ register_power8_ebb_sprs(env);
+ register_power8_fscr_sprs(env);
+ register_power8_pmu_sup_sprs(env);
+ register_power8_pmu_user_sprs(env);
+ register_power8_tm_sprs(env);
+ register_power8_pspb_sprs(env);
+ register_vtb_sprs(env);
+ register_power8_ic_sprs(env);
+ register_power8_book4_sprs(env);
+ register_power8_rpr_sprs(env);
+ register_power9_mmu_sprs(env);
/* FIXME: Filter fields properly based on privilege level */
spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL,
@@ -9369,7 +8395,7 @@ static void init_ppc_proc(PowerPCCPU *cpu)
env->tlb_type = TLB_NONE;
#endif
/* Register SPR common to all PowerPC implementations */
- gen_spr_generic(env);
+ register_generic_sprs(env);
spr_register(env, SPR_PVR, "PVR",
/* Linux permits userspace to read PVR */
#if defined(CONFIG_LINUX_USER)
@@ -10342,4 +9368,186 @@ static void ppc_cpu_register_types(void)
#endif
}
+void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+#define RGPL 4
+#define RFPL 4
+
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ int i;
+
+ qemu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR "
+ TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n",
+ env->nip, env->lr, env->ctr, cpu_read_xer(env),
+ cs->cpu_index);
+ qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
+ "%08x iidx %d didx %d\n",
+ env->msr, env->spr[SPR_HID0], env->hflags,
+ cpu_mmu_index(env, true), cpu_mmu_index(env, false));
+#if !defined(NO_TIMER_DUMP)
+ qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
+#if !defined(CONFIG_USER_ONLY)
+ " DECR " TARGET_FMT_lu
+#endif
+ "\n",
+ cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+ , cpu_ppc_load_decr(env)
+#endif
+ );
+#endif
+ for (i = 0; i < 32; i++) {
+ if ((i & (RGPL - 1)) == 0) {
+ qemu_fprintf(f, "GPR%02d", i);
+ }
+ qemu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i));
+ if ((i & (RGPL - 1)) == (RGPL - 1)) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ qemu_fprintf(f, "CR ");
+ for (i = 0; i < 8; i++)
+ qemu_fprintf(f, "%01x", env->crf[i]);
+ qemu_fprintf(f, " [");
+ for (i = 0; i < 8; i++) {
+ char a = '-';
+ if (env->crf[i] & 0x08) {
+ a = 'L';
+ } else if (env->crf[i] & 0x04) {
+ a = 'G';
+ } else if (env->crf[i] & 0x02) {
+ a = 'E';
+ }
+ qemu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
+ }
+ qemu_fprintf(f, " ] RES " TARGET_FMT_lx "\n",
+ env->reserve_addr);
+
+ if (flags & CPU_DUMP_FPU) {
+ for (i = 0; i < 32; i++) {
+ if ((i & (RFPL - 1)) == 0) {
+ qemu_fprintf(f, "FPR%02d", i);
+ }
+ qemu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i));
+ if ((i & (RFPL - 1)) == (RFPL - 1)) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ qemu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr);
+ }
+
+#if !defined(CONFIG_USER_ONLY)
+ qemu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx
+ " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
+ env->spr[SPR_SRR0], env->spr[SPR_SRR1],
+ env->spr[SPR_PVR], env->spr[SPR_VRSAVE]);
+
+ qemu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx
+ " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n",
+ env->spr[SPR_SPRG0], env->spr[SPR_SPRG1],
+ env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]);
+
+ qemu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx
+ " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n",
+ env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
+ env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
+
+#if defined(TARGET_PPC64)
+ if (env->excp_model == POWERPC_EXCP_POWER7 ||
+ env->excp_model == POWERPC_EXCP_POWER8 ||
+ env->excp_model == POWERPC_EXCP_POWER9 ||
+ env->excp_model == POWERPC_EXCP_POWER10) {
+ qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n",
+ env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
+ }
+#endif
+ if (env->excp_model == POWERPC_EXCP_BOOKE) {
+ qemu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
+ " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
+ env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
+
+ qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
+ " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR],
+ env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
+
+ qemu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx
+ " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR],
+ env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]);
+
+ qemu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx
+ " EPR " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8],
+ env->spr[SPR_BOOKE_EPR]);
+
+ /* FSL-specific */
+ qemu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx
+ " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n",
+ env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1],
+ env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]);
+
+ /*
+ * IVORs are left out as they are large and do not change often --
+ * they can be read with "p $ivor0", "p $ivor1", etc.
+ */
+ }
+
+#if defined(TARGET_PPC64)
+ if (env->flags & POWERPC_FLAG_CFAR) {
+ qemu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar);
+ }
+#endif
+
+ if (env->spr_cb[SPR_LPCR].name) {
+ qemu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
+ }
+
+ switch (env->mmu_model) {
+ case POWERPC_MMU_32B:
+ case POWERPC_MMU_601:
+ case POWERPC_MMU_SOFT_6xx:
+ case POWERPC_MMU_SOFT_74xx:
+#if defined(TARGET_PPC64)
+ case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_03:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_07:
+ case POWERPC_MMU_3_00:
+#endif
+ if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
+ qemu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]);
+ }
+ if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */
+ qemu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]);
+ }
+ qemu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n",
+ env->spr[SPR_DAR], env->spr[SPR_DSISR]);
+ break;
+ case POWERPC_MMU_BOOKE206:
+ qemu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx
+ " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],
+ env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]);
+
+ qemu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx
+ " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n",
+ env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6],
+ env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]);
+
+ qemu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx
+ " TLB1CFG " TARGET_FMT_lx "\n",
+ env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG],
+ env->spr[SPR_BOOKE_TLB1CFG]);
+ break;
+ default:
+ break;
+ }
+#endif
+
+#undef RGPL
+#undef RFPL
+}
type_init(ppc_cpu_register_types)
diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c
index 94a7273ee0..9339e7eafe 100644
--- a/target/ppc/gdbstub.c
+++ b/target/ppc/gdbstub.c
@@ -498,7 +498,7 @@ static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
return 16;
}
if (n == 32) {
- gdb_get_reg32(buf, helper_mfvscr(env));
+ gdb_get_reg32(buf, ppc_get_vscr(env));
mem_buf = gdb_get_reg_ptr(buf, 4);
ppc_maybe_bswap_register(env, mem_buf, 4);
return 4;
@@ -529,7 +529,7 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
}
if (n == 32) {
ppc_maybe_bswap_register(env, mem_buf, 4);
- helper_mtvscr(env, ldl_p(mem_buf));
+ ppc_store_vscr(env, ldl_p(mem_buf));
return 4;
}
if (n == 33) {
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 513066d54d..ea9f2a236c 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -1,5 +1,5 @@
-DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, void, env, i32, i32)
-DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, void, env, i32)
+DEF_HELPER_FLAGS_3(raise_exception_err, TCG_CALL_NO_WG, noreturn, env, i32, i32)
+DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index a44c2d90ea..41f8477d4b 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -462,17 +462,12 @@ SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
void helper_mtvscr(CPUPPCState *env, uint32_t vscr)
{
- env->vscr = vscr & ~(1u << VSCR_SAT);
- /* Which bit we set is completely arbitrary, but clear the rest. */
- env->vscr_sat.u64[0] = vscr & (1u << VSCR_SAT);
- env->vscr_sat.u64[1] = 0;
- set_flush_to_zero((vscr >> VSCR_NJ) & 1, &env->vec_status);
+ ppc_store_vscr(env, vscr);
}
uint32_t helper_mfvscr(CPUPPCState *env)
{
- uint32_t sat = (env->vscr_sat.u64[0] | env->vscr_sat.u64[1]) != 0;
- return env->vscr | (sat << VSCR_SAT);
+ return ppc_get_vscr(env);
}
static inline void set_vscr_sat(CPUPPCState *env)
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 184ba6d6b3..2b4b06eb76 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -228,4 +228,23 @@ void destroy_ppc_opcodes(PowerPCCPU *cpu);
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
gchar *ppc_gdb_arch_name(CPUState *cs);
+/**
+ * prot_for_access_type:
+ * @access_type: Access type
+ *
+ * Return the protection bit required for the given access type.
+ */
+static inline int prot_for_access_type(MMUAccessType access_type)
+{
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ return PAGE_EXEC;
+ case MMU_DATA_LOAD:
+ return PAGE_READ;
+ case MMU_DATA_STORE:
+ return PAGE_WRITE;
+ }
+ g_assert_not_reached();
+}
+
#endif /* PPC_INTERNAL_H */
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index e5bffbe365..93972df58e 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -8,7 +8,6 @@
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "kvm_ppc.h"
-#include "exec/helper-proto.h"
static void post_load_update_msr(CPUPPCState *env)
{
@@ -107,7 +106,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
ppc_store_sdr1(env, sdr1);
}
qemu_get_be32s(f, &vscr);
- helper_mtvscr(env, vscr);
+ ppc_store_vscr(env, vscr);
qemu_get_be64s(f, &env->spe_acc);
qemu_get_be32s(f, &env->spe_fscr);
qemu_get_betls(f, &env->msr_mask);
@@ -456,7 +455,7 @@ static int get_vscr(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field)
{
PowerPCCPU *cpu = opaque;
- helper_mtvscr(&cpu->env, qemu_get_be32(f));
+ ppc_store_vscr(&cpu->env, qemu_get_be32(f));
return 0;
}
@@ -464,7 +463,7 @@ static int put_vscr(QEMUFile *f, void *opaque, size_t size,
const VMStateField *field, JSONWriter *vmdesc)
{
PowerPCCPU *cpu = opaque;
- qemu_put_be32(f, helper_mfvscr(&cpu->env));
+ qemu_put_be32(f, ppc_get_vscr(&cpu->env));
return 0;
}
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index 4079d01ee3..d1aa7d5d39 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -2,6 +2,7 @@ ppc_ss = ss.source_set()
ppc_ss.add(files(
'cpu-models.c',
'cpu.c',
+ 'cpu_init.c',
'dfp_helper.c',
'excp_helper.c',
'fpu_helper.c',
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 002958be26..08a31da289 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -261,6 +261,16 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value)
hreg_store_msr(env, value, 0);
}
+void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
+ /* The gtse bit affects hflags */
+ hreg_compute_hflags(env);
+}
+
/*
* This code is lifted from MacOnLinux. It is called whenever THRM1,2
* or 3 is read an fixes up the values in such a way that will make
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index 178cf090b7..744a763f44 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -24,6 +24,7 @@
#include "exec/helper-proto.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
+#include "internal.h"
#include "mmu-hash32.h"
#include "exec/log.h"
@@ -152,16 +153,17 @@ static int hash32_bat_601_prot(PowerPCCPU *cpu,
return ppc_hash32_pp_prot(key, pp, 0);
}
-static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx,
- int *prot)
+static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
+ MMUAccessType access_type, int *prot)
{
CPUPPCState *env = &cpu->env;
target_ulong *BATlt, *BATut;
+ bool ifetch = access_type == MMU_INST_FETCH;
int i;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- rwx == 2 ? 'I' : 'D', ea);
- if (rwx == 2) {
+ ifetch ? 'I' : 'D', ea);
+ if (ifetch) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
} else {
@@ -180,7 +182,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx,
}
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
+ ifetch ? 'I' : 'D', i, ea, batu, batl);
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
hwaddr raddr = (batl & mask) | (ea & ~mask);
@@ -208,7 +210,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx,
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
TARGET_FMT_lx " " TARGET_FMT_lx "\n",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
+ __func__, ifetch ? 'I' : 'D', i, ea,
*BATu, *BATl, BEPIu, BEPIl, bl);
}
}
@@ -218,7 +220,8 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx,
}
static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
- target_ulong eaddr, int rwx,
+ target_ulong eaddr,
+ MMUAccessType access_type,
hwaddr *raddr, int *prot)
{
CPUState *cs = CPU(cpu);
@@ -239,7 +242,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
return 0;
}
- if (rwx == 2) {
+ if (access_type == MMU_INST_FETCH) {
/* No code fetch is allowed in direct-store areas */
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
@@ -260,7 +263,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
/* lwarx, ldarx or srwcx. */
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x06000000;
} else {
env->spr[SPR_DSISR] = 0x04000000;
@@ -280,7 +283,7 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x06100000;
} else {
env->spr[SPR_DSISR] = 0x04100000;
@@ -290,14 +293,15 @@ static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
cpu_abort(cs, "ERROR: instruction should not need "
"address translation\n");
}
- if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
+ if ((access_type == MMU_DATA_STORE || key != 1) &&
+ (access_type == MMU_DATA_LOAD || key != 0)) {
*raddr = eaddr;
return 0;
} else {
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
@@ -421,13 +425,16 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
hwaddr pte_offset;
ppc_hash_pte32_t pte;
int prot;
- const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
+ int need_prot;
+ MMUAccessType access_type;
hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+ access_type = rwx;
+ need_prot = prot_for_access_type(access_type);
/* 1. Handle real mode accesses */
- if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
+ if (access_type == MMU_INST_FETCH ? !msr_ir : !msr_dr) {
/* Translation is off */
raddr = eaddr;
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
@@ -438,17 +445,17 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
/* 2. Check Block Address Translation entries (BATs) */
if (env->nb_BATs != 0) {
- raddr = ppc_hash32_bat_lookup(cpu, eaddr, rwx, &prot);
+ raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, &prot);
if (raddr != -1) {
- if (need_prot[rwx] & ~prot) {
- if (rwx == 2) {
+ if (need_prot & ~prot) {
+ if (access_type == MMU_INST_FETCH) {
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
@@ -469,7 +476,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
/* 4. Handle direct store segments */
if (sr & SR32_T) {
- if (ppc_hash32_direct_store(cpu, sr, eaddr, rwx,
+ if (ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
&raddr, &prot) == 0) {
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
raddr & TARGET_PAGE_MASK, prot, mmu_idx,
@@ -481,7 +488,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
}
/* 5. Check for segment level no-execute violation */
- if ((rwx == 2) && (sr & SR32_NX)) {
+ if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x10000000;
return 1;
@@ -490,14 +497,14 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
/* 6. Locate the PTE in the hash table */
pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
if (pte_offset == -1) {
- if (rwx == 2) {
+ if (access_type == MMU_INST_FETCH) {
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x40000000;
} else {
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x42000000;
} else {
env->spr[SPR_DSISR] = 0x40000000;
@@ -513,17 +520,17 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
prot = ppc_hash32_pte_prot(cpu, sr, pte);
- if (need_prot[rwx] & ~prot) {
+ if (need_prot & ~prot) {
/* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
- if (rwx == 2) {
+ if (access_type == MMU_INST_FETCH) {
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x08000000;
} else {
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x0a000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
@@ -540,7 +547,7 @@ int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
}
if (!(pte.pte1 & HPTE32_R_C)) {
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
} else {
/*
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index d517a99832..f48b625f48 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -29,6 +29,7 @@
#include "mmu-hash64.h"
#include "exec/log.h"
#include "hw/hw.h"
+#include "internal.h"
#include "mmu-book3s-v3.h"
#include "helper_regs.h"
@@ -876,10 +877,12 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
hwaddr ptex;
ppc_hash_pte64_t pte;
int exec_prot, pp_prot, amr_prot, prot;
- const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
+ MMUAccessType access_type;
+ int need_prot;
hwaddr raddr;
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+ access_type = rwx;
/*
* Note on LPCR usage: 970 uses HID4, but our special variant of
@@ -890,7 +893,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
*/
/* 1. Handle real mode accesses */
- if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
+ if (access_type == MMU_INST_FETCH ? !msr_ir : !msr_dr) {
/*
* Translation is supposedly "off", but in real mode the top 4
* effective address bits are (mostly) ignored
@@ -923,14 +926,19 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
/* Emulated old-style RMO mode, bounds check against RMLS */
if (raddr >= limit) {
- if (rwx == 2) {
+ switch (access_type) {
+ case MMU_INST_FETCH:
ppc_hash64_set_isi(cs, SRR1_PROTFAULT);
- } else {
- int dsisr = DSISR_PROTFAULT;
- if (rwx == 1) {
- dsisr |= DSISR_ISSTORE;
- }
- ppc_hash64_set_dsi(cs, eaddr, dsisr);
+ break;
+ case MMU_DATA_LOAD:
+ ppc_hash64_set_dsi(cs, eaddr, DSISR_PROTFAULT);
+ break;
+ case MMU_DATA_STORE:
+ ppc_hash64_set_dsi(cs, eaddr,
+ DSISR_PROTFAULT | DSISR_ISSTORE);
+ break;
+ default:
+ g_assert_not_reached();
}
return 1;
}
@@ -953,13 +961,19 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
exit(1);
}
/* Segment still not found, generate the appropriate interrupt */
- if (rwx == 2) {
+ switch (access_type) {
+ case MMU_INST_FETCH:
cs->exception_index = POWERPC_EXCP_ISEG;
env->error_code = 0;
- } else {
+ break;
+ case MMU_DATA_LOAD:
+ case MMU_DATA_STORE:
cs->exception_index = POWERPC_EXCP_DSEG;
env->error_code = 0;
env->spr[SPR_DAR] = eaddr;
+ break;
+ default:
+ g_assert_not_reached();
}
return 1;
}
@@ -967,7 +981,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
skip_slb_search:
/* 3. Check for segment level no-execute violation */
- if ((rwx == 2) && (slb->vsid & SLB_VSID_N)) {
+ if (access_type == MMU_INST_FETCH && (slb->vsid & SLB_VSID_N)) {
ppc_hash64_set_isi(cs, SRR1_NOEXEC_GUARD);
return 1;
}
@@ -975,14 +989,18 @@ skip_slb_search:
/* 4. Locate the PTE in the hash table */
ptex = ppc_hash64_htab_lookup(cpu, slb, eaddr, &pte, &apshift);
if (ptex == -1) {
- if (rwx == 2) {
+ switch (access_type) {
+ case MMU_INST_FETCH:
ppc_hash64_set_isi(cs, SRR1_NOPTE);
- } else {
- int dsisr = DSISR_NOPTE;
- if (rwx == 1) {
- dsisr |= DSISR_ISSTORE;
- }
- ppc_hash64_set_dsi(cs, eaddr, dsisr);
+ break;
+ case MMU_DATA_LOAD:
+ ppc_hash64_set_dsi(cs, eaddr, DSISR_NOPTE);
+ break;
+ case MMU_DATA_STORE:
+ ppc_hash64_set_dsi(cs, eaddr, DSISR_NOPTE | DSISR_ISSTORE);
+ break;
+ default:
+ g_assert_not_reached();
}
return 1;
}
@@ -996,10 +1014,11 @@ skip_slb_search:
amr_prot = ppc_hash64_amr_prot(cpu, pte);
prot = exec_prot & pp_prot & amr_prot;
- if ((need_prot[rwx] & ~prot) != 0) {
+ need_prot = prot_for_access_type(access_type);
+ if (need_prot & ~prot) {
/* Access right violation */
qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
- if (rwx == 2) {
+ if (access_type == MMU_INST_FETCH) {
int srr1 = 0;
if (PAGE_EXEC & ~exec_prot) {
srr1 |= SRR1_NOEXEC_GUARD; /* Access violates noexec or guard */
@@ -1012,13 +1031,13 @@ skip_slb_search:
ppc_hash64_set_isi(cs, srr1);
} else {
int dsisr = 0;
- if (need_prot[rwx] & ~pp_prot) {
+ if (need_prot & ~pp_prot) {
dsisr |= DSISR_PROTFAULT;
}
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
dsisr |= DSISR_ISSTORE;
}
- if (need_prot[rwx] & ~amr_prot) {
+ if (need_prot & ~amr_prot) {
dsisr |= DSISR_AMR;
}
ppc_hash64_set_dsi(cs, eaddr, dsisr);
@@ -1034,7 +1053,7 @@ skip_slb_search:
ppc_hash64_set_r(cpu, ptex, pte.pte1);
}
if (!(pte.pte1 & HPTE64_R_C)) {
- if (rwx == 1) {
+ if (access_type == MMU_DATA_STORE) {
ppc_hash64_set_c(cpu, ptex, pte.pte1);
} else {
/*
@@ -1120,16 +1139,6 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
}
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
-{
- PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
- CPUPPCState *env = &cpu->env;
-
- env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
- /* The gtse bit affects hflags */
- hreg_compute_hflags(env);
-}
-
void helper_store_lpcr(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = env_archcpu(env);
@@ -1200,61 +1209,4 @@ const PPCHash64Options ppc_hash64_opts_POWER7 = {
}
};
-void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu,
- bool (*cb)(void *, uint32_t, uint32_t),
- void *opaque)
-{
- PPCHash64Options *opts = cpu->hash64_opts;
- int i;
- int n = 0;
- bool ci_largepage = false;
-
- assert(opts);
-
- n = 0;
- for (i = 0; i < ARRAY_SIZE(opts->sps); i++) {
- PPCHash64SegmentPageSizes *sps = &opts->sps[i];
- int j;
- int m = 0;
- assert(n <= i);
-
- if (!sps->page_shift) {
- break;
- }
-
- for (j = 0; j < ARRAY_SIZE(sps->enc); j++) {
- PPCHash64PageSize *ps = &sps->enc[j];
-
- assert(m <= j);
- if (!ps->page_shift) {
- break;
- }
-
- if (cb(opaque, sps->page_shift, ps->page_shift)) {
- if (ps->page_shift >= 16) {
- ci_largepage = true;
- }
- sps->enc[m++] = *ps;
- }
- }
-
- /* Clear rest of the row */
- for (j = m; j < ARRAY_SIZE(sps->enc); j++) {
- memset(&sps->enc[j], 0, sizeof(sps->enc[j]));
- }
-
- if (m) {
- n++;
- }
- }
-
- /* Clear the rest of the table */
- for (i = n; i < ARRAY_SIZE(opts->sps); i++) {
- memset(&opts->sps[i], 0, sizeof(opts->sps[i]));
- }
-
- if (!ci_largepage) {
- opts->flags &= ~PPC_HASH64_CI_LARGEPAGE;
- }
-}
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index 87729d48b3..4b8b8e7950 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -15,12 +15,8 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu,
target_ulong pte0, target_ulong pte1);
unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
uint64_t pte0, uint64_t pte1);
-void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val);
void ppc_hash64_init(PowerPCCPU *cpu);
void ppc_hash64_finalize(PowerPCCPU *cpu);
-void ppc_hash64_filter_pagesizes(PowerPCCPU *cpu,
- bool (*cb)(void *, uint32_t, uint32_t),
- void *opaque);
#endif
/*
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 30fcfcf11f..7972153f23 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -25,6 +25,7 @@
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "exec/log.h"
+#include "internal.h"
#include "mmu-radix64.h"
#include "mmu-book3s-v3.h"
@@ -74,71 +75,94 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
return true;
}
-static void ppc_radix64_raise_segi(PowerPCCPU *cpu, int rwx, vaddr eaddr)
+static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
+ vaddr eaddr)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- if (rwx == 2) { /* Instruction Segment Interrupt */
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ /* Instruction Segment Interrupt */
cs->exception_index = POWERPC_EXCP_ISEG;
- } else { /* Data Segment Interrupt */
+ break;
+ case MMU_DATA_STORE:
+ case MMU_DATA_LOAD:
+ /* Data Segment Interrupt */
cs->exception_index = POWERPC_EXCP_DSEG;
env->spr[SPR_DAR] = eaddr;
+ break;
+ default:
+ g_assert_not_reached();
}
env->error_code = 0;
}
-static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
- uint32_t cause)
+static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
+ vaddr eaddr, uint32_t cause)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- if (rwx == 2) { /* Instruction Storage Interrupt */
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ /* Instruction Storage Interrupt */
cs->exception_index = POWERPC_EXCP_ISI;
env->error_code = cause;
- } else { /* Data Storage Interrupt */
+ break;
+ case MMU_DATA_STORE:
+ cause |= DSISR_ISSTORE;
+ /* fall through */
+ case MMU_DATA_LOAD:
+ /* Data Storage Interrupt */
cs->exception_index = POWERPC_EXCP_DSI;
- if (rwx == 1) { /* Write -> Store */
- cause |= DSISR_ISSTORE;
- }
env->spr[SPR_DSISR] = cause;
env->spr[SPR_DAR] = eaddr;
env->error_code = 0;
+ break;
+ default:
+ g_assert_not_reached();
}
}
-static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr,
- hwaddr g_raddr, uint32_t cause)
+static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
+ vaddr eaddr, hwaddr g_raddr, uint32_t cause)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- if (rwx == 2) { /* H Instruction Storage Interrupt */
+ switch (access_type) {
+ case MMU_INST_FETCH:
+ /* H Instruction Storage Interrupt */
cs->exception_index = POWERPC_EXCP_HISI;
env->spr[SPR_ASDR] = g_raddr;
env->error_code = cause;
- } else { /* H Data Storage Interrupt */
+ break;
+ case MMU_DATA_STORE:
+ cause |= DSISR_ISSTORE;
+ /* fall through */
+ case MMU_DATA_LOAD:
+ /* H Data Storage Interrupt */
cs->exception_index = POWERPC_EXCP_HDSI;
- if (rwx == 1) { /* Write -> Store */
- cause |= DSISR_ISSTORE;
- }
env->spr[SPR_HDSISR] = cause;
env->spr[SPR_HDAR] = eaddr;
env->spr[SPR_ASDR] = g_raddr;
env->error_code = 0;
+ break;
+ default:
+ g_assert_not_reached();
}
}
-static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
- int *fault_cause, int *prot,
+static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
+ uint64_t pte, int *fault_cause, int *prot,
bool partition_scoped)
{
CPUPPCState *env = &cpu->env;
- const int need_prot[] = { PAGE_READ, PAGE_WRITE, PAGE_EXEC };
+ int need_prot;
/* Check Page Attributes (pte58:59) */
- if (((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO) && (rwx == 2)) {
+ if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
/*
* Radix PTE entries with the non-idempotent I/O attribute are treated
* as guarded storage
@@ -158,7 +182,8 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
}
/* Check if requested access type is allowed */
- if (need_prot[rwx] & ~(*prot)) { /* Page Protected for that Access */
+ need_prot = prot_for_access_type(access_type);
+ if (need_prot & ~*prot) { /* Page Protected for that Access */
*fault_cause |= DSISR_PROTFAULT;
return true;
}
@@ -166,15 +191,15 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
return false;
}
-static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte,
- hwaddr pte_addr, int *prot)
+static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
+ uint64_t pte, hwaddr pte_addr, int *prot)
{
CPUState *cs = CPU(cpu);
uint64_t npte;
npte = pte | R_PTE_R; /* Always set reference bit */
- if (rwx == 1) { /* Store/Write */
+ if (access_type == MMU_DATA_STORE) { /* Store/Write */
npte |= R_PTE_C; /* Set change bit */
} else {
/*
@@ -269,7 +294,8 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
return true;
}
-static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
+static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
+ MMUAccessType access_type,
vaddr eaddr, hwaddr g_raddr,
ppc_v3_pate_t pate,
hwaddr *h_raddr, int *h_prot,
@@ -285,24 +311,25 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
&pte, &fault_cause, &pte_addr) ||
- ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
+ ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, h_prot, true)) {
if (pde_addr) { /* address being translated was that of a guest pde */
fault_cause |= DSISR_PRTABLE_FAULT;
}
if (guest_visible) {
- ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
+ ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
}
return 1;
}
if (guest_visible) {
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
+ ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
}
return 0;
}
-static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
+static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
+ MMUAccessType access_type,
vaddr eaddr, uint64_t pid,
ppc_v3_pate_t pate, hwaddr *g_raddr,
int *g_prot, int *g_page_size,
@@ -321,7 +348,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (offset >= size) {
/* offset exceeds size of the process table */
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
}
return 1;
}
@@ -362,7 +389,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (ret) {
/* No valid PTE */
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
}
return ret;
}
@@ -391,7 +418,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
if (ret) {
/* No valid pte */
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
}
return ret;
}
@@ -405,16 +432,16 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
*g_raddr = (rpn & ~mask) | (eaddr & mask);
}
- if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
+ if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, g_prot, false)) {
/* Access denied due to protection */
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
}
return 1;
}
if (guest_visible) {
- ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
+ ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
}
return 0;
@@ -437,7 +464,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
* | = On | Process Scoped | Scoped |
* +-------------+----------------+---------------+
*/
-static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
+static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr,
+ MMUAccessType access_type,
bool relocation,
hwaddr *raddr, int *psizep, int *protp,
bool guest_visible)
@@ -451,7 +479,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
/* Virtual Mode Access - get the fully qualified address */
if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
if (guest_visible) {
- ppc_radix64_raise_segi(cpu, rwx, eaddr);
+ ppc_radix64_raise_segi(cpu, access_type, eaddr);
}
return 1;
}
@@ -464,13 +492,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
} else {
if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
}
return 1;
}
if (!validate_pate(cpu, lpid, &pate)) {
if (guest_visible) {
- ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
+ ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
}
return 1;
}
@@ -488,7 +516,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
* - Translates an effective address to a guest real address.
*/
if (relocation) {
- int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
+ int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
pate, &g_raddr, &prot,
&psize, guest_visible);
if (ret) {
@@ -511,9 +539,10 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
if (lpid || !msr_hv) {
int ret;
- ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
- pate, raddr, &prot, &psize,
- false, guest_visible);
+ ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
+ g_raddr, pate, raddr,
+ &prot, &psize, false,
+ guest_visible);
if (ret) {
return ret;
}
@@ -534,12 +563,14 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
CPUPPCState *env = &cpu->env;
int page_size, prot;
bool relocation;
+ MMUAccessType access_type;
hwaddr raddr;
assert(!(msr_hv && cpu->vhyp));
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
+ access_type = rwx;
- relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1));
+ relocation = (access_type == MMU_INST_FETCH ? msr_ir : msr_dr);
/* HV or virtual hypervisor Real Mode Access */
if (!relocation && (msr_hv || cpu->vhyp)) {
/* In real mode top 4 effective addr bits (mostly) ignored */
@@ -568,7 +599,7 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
}
/* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
- if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr,
+ if (ppc_radix64_xlate(cpu, eaddr, access_type, relocation, &raddr,
&page_size, &prot, true)) {
return 1;
}
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index ca88658cba..37986c59ba 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -32,6 +32,7 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/qemu-print.h"
+#include "internal.h"
#include "mmu-book3s-v3.h"
#include "mmu-radix64.h"
@@ -126,36 +127,14 @@ static int pp_check(int key, int pp, int nx)
return access;
}
-static int check_prot(int prot, int rw, int access_type)
+static int check_prot(int prot, MMUAccessType access_type)
{
- int ret;
-
- if (access_type == ACCESS_CODE) {
- if (prot & PAGE_EXEC) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else if (rw) {
- if (prot & PAGE_WRITE) {
- ret = 0;
- } else {
- ret = -2;
- }
- } else {
- if (prot & PAGE_READ) {
- ret = 0;
- } else {
- ret = -2;
- }
- }
-
- return ret;
+ return prot & prot_for_access_type(access_type) ? 0 : -2;
}
-static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
- target_ulong pte1, int h,
- int rw, int type)
+static int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
+ target_ulong pte1, int h,
+ MMUAccessType access_type)
{
target_ulong ptem, mmask;
int access, ret, pteh, ptev, pp;
@@ -182,7 +161,7 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
/* Keep the matching PTE information */
ctx->raddr = pte1;
ctx->prot = access;
- ret = check_prot(ctx->prot, rw, type);
+ ret = check_prot(ctx->prot, access_type);
if (ret == 0) {
/* Access granted */
qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
@@ -197,7 +176,7 @@ static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
}
static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, int rw)
+ int ret, MMUAccessType access_type)
{
int store = 0;
@@ -208,7 +187,7 @@ static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
store = 1;
}
if (!(*pte1p & 0x00000080)) {
- if (rw == 1 && ret == 0) {
+ if (access_type == MMU_DATA_STORE && ret == 0) {
/* Update changed flag */
*pte1p |= 0x00000080;
store = 1;
@@ -308,8 +287,8 @@ static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
env->last_way = way;
}
-static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
+static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, MMUAccessType access_type)
{
ppc6xx_tlb_t *tlb;
int nr, best, way;
@@ -318,8 +297,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
best = -1;
ret = -1; /* No TLB found */
for (way = 0; way < env->nb_ways; way++) {
- nr = ppc6xx_tlb_getnum(env, eaddr, way,
- access_type == ACCESS_CODE ? 1 : 0);
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
tlb = &env->tlb.tlb6[nr];
/* This test "emulates" the PTE index match for hardware TLBs */
if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
@@ -333,9 +311,10 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
pte_is_valid(tlb->pte0) ? "valid" : "inval",
tlb->EPN, eaddr, tlb->pte1,
- rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+ access_type == MMU_DATA_STORE ? 'S' : 'L',
+ access_type == MMU_INST_FETCH ? 'I' : 'D');
switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
- 0, rw, access_type)) {
+ 0, access_type)) {
case -3:
/* TLB inconsistency */
return -1;
@@ -366,7 +345,7 @@ static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
/* Update page flags */
- pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
+ pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
}
return ret;
@@ -400,24 +379,22 @@ static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
}
static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, int rw, int type)
+ target_ulong virtual, MMUAccessType access_type)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
int i, valid, prot;
int ret = -1;
+ bool ifetch = access_type == MMU_INST_FETCH;
LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
- switch (type) {
- case ACCESS_CODE:
+ ifetch ? 'I' : 'D', virtual);
+ if (ifetch) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
- break;
- default:
+ } else {
BATlt = env->DBAT[1];
BATut = env->DBAT[0];
- break;
}
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
@@ -427,7 +404,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
+ ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
if ((virtual & 0xF0000000) == BEPIu &&
((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
/* BAT matches */
@@ -438,7 +415,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
(virtual & 0x0001F000);
/* Compute access rights */
ctx->prot = prot;
- ret = check_prot(ctx->prot, rw, type);
+ ret = check_prot(ctx->prot, access_type);
if (ret == 0) {
LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
@@ -461,7 +438,7 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
TARGET_FMT_lx " " TARGET_FMT_lx "\n",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+ __func__, ifetch ? 'I' : 'D', i, virtual,
*BATu, *BATl, BEPIu, BEPIl, bl);
}
}
@@ -472,8 +449,9 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
}
/* Perform segment based translation */
-static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int type)
+static int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, MMUAccessType access_type,
+ int type)
{
PowerPCCPU *cpu = env_archcpu(env);
hwaddr hash;
@@ -497,7 +475,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
" nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
" ir=%d dr=%d pr=%d %d t=%d\n",
eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
- (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+ (int)msr_dr, pr != 0 ? 1 : 0, access_type == MMU_DATA_STORE, type);
pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
hash = vsid ^ pgidx;
ctx->ptem = (vsid << 7) | (pgidx >> 10);
@@ -520,7 +498,7 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
/* Initialize real address with an invalid value */
ctx->raddr = (hwaddr)-1ULL;
/* Software TLB search */
- ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+ ret = ppc6xx_tlb_check(env, ctx, eaddr, access_type);
#if defined(DUMP_PAGE_TABLES)
if (qemu_loglevel_mask(CPU_LOG_MMU)) {
CPUState *cs = env_cpu(env);
@@ -603,7 +581,8 @@ static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
"address translation\n");
return -4;
}
- if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
+ (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
ctx->raddr = eaddr;
ret = 2;
} else {
@@ -682,8 +661,8 @@ static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
}
static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
+ target_ulong address,
+ MMUAccessType access_type)
{
ppcemb_tlb_t *tlb;
hwaddr raddr;
@@ -700,8 +679,8 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
}
zsel = (tlb->attr >> 4) & 0xF;
zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
- LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
- __func__, i, zsel, zpr, rw, tlb->attr);
+ LOG_SWTLB("%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
+ __func__, i, zsel, zpr, access_type, tlb->attr);
/* Check execute enable bit */
switch (zpr) {
case 0x2:
@@ -727,7 +706,7 @@ static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
check_perms:
/* Check from TLB entry */
ctx->prot = tlb->prot;
- ret = check_prot(ctx->prot, rw, access_type);
+ ret = check_prot(ctx->prot, access_type);
if (ret == -2) {
env->spr[SPR_40x_ESR] = 0;
}
@@ -757,12 +736,11 @@ void store_40x_sler(CPUPPCState *env, uint32_t val)
env->spr[SPR_405_SLER] = val;
}
-static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
- hwaddr *raddr, int *prot,
- target_ulong address, int rw,
- int access_type, int i)
+static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
+ hwaddr *raddr, int *prot, target_ulong address,
+ MMUAccessType access_type, int i)
{
- int ret, prot2;
+ int prot2;
if (ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID],
@@ -794,42 +772,24 @@ found_tlb:
}
/* Check the address space */
- if (access_type == ACCESS_CODE) {
- if (msr_ir != (tlb->attr & 1)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if (prot2 & PAGE_EXEC) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
- ret = -3;
- } else {
- if (msr_dr != (tlb->attr & 1)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
- LOG_SWTLB("%s: found TLB!\n", __func__);
- return 0;
- }
+ if ((access_type == MMU_INST_FETCH ? msr_ir : msr_dr) != (tlb->attr & 1)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
- ret = -2;
+ *prot = prot2;
+ if (prot2 & prot_for_access_type(access_type)) {
+ LOG_SWTLB("%s: good TLB!\n", __func__);
+ return 0;
}
- return ret;
+ LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2);
+ return access_type == MMU_INST_FETCH ? -3 : -2;
}
static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type)
+ target_ulong address,
+ MMUAccessType access_type)
{
ppcemb_tlb_t *tlb;
hwaddr raddr;
@@ -839,7 +799,7 @@ static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
raddr = (hwaddr)-1ULL;
for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb.tlbe[i];
- ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
+ ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address,
access_type, i);
if (ret != -1) {
break;
@@ -938,10 +898,10 @@ static bool is_epid_mmu(int mmu_idx)
return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
}
-static uint32_t mmubooke206_esr(int mmu_idx, bool rw)
+static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
{
uint32_t esr = 0;
- if (rw) {
+ if (access_type == MMU_DATA_STORE) {
esr |= ESR_ST;
}
if (is_epid_mmu(mmu_idx)) {
@@ -983,10 +943,9 @@ static bool mmubooke206_get_as(CPUPPCState *env,
/* Check if the tlb found by hashing really matches */
static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
hwaddr *raddr, int *prot,
- target_ulong address, int rw,
- int access_type, int mmu_idx)
+ target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
{
- int ret;
int prot2 = 0;
uint32_t epid;
bool as, pr;
@@ -1043,44 +1002,31 @@ found_tlb:
}
/* Check the address space and permissions */
- if (access_type == ACCESS_CODE) {
+ if (access_type == MMU_INST_FETCH) {
/* There is no way to fetch code using epid load */
assert(!use_epid);
- if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
-
- *prot = prot2;
- if (prot2 & PAGE_EXEC) {
- LOG_SWTLB("%s: good TLB!\n", __func__);
- return 0;
- }
-
- LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
- ret = -3;
- } else {
- if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
- LOG_SWTLB("%s: AS doesn't match\n", __func__);
- return -1;
- }
+ as = msr_ir;
+ }
- *prot = prot2;
- if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
- LOG_SWTLB("%s: found TLB!\n", __func__);
- return 0;
- }
+ if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
+ LOG_SWTLB("%s: AS doesn't match\n", __func__);
+ return -1;
+ }
- LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
- ret = -2;
+ *prot = prot2;
+ if (prot2 & prot_for_access_type(access_type)) {
+ LOG_SWTLB("%s: good TLB!\n", __func__);
+ return 0;
}
- return ret;
+ LOG_SWTLB("%s: no prot match: %x\n", __func__, prot2);
+ return access_type == MMU_INST_FETCH ? -3 : -2;
}
static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong address, int rw,
- int access_type, int mmu_idx)
+ target_ulong address,
+ MMUAccessType access_type,
+ int mmu_idx)
{
ppcmas_tlb_t *tlb;
hwaddr raddr;
@@ -1098,7 +1044,7 @@ static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
continue;
}
ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
- rw, access_type, mmu_idx);
+ access_type, mmu_idx);
if (ret != -1) {
goto found_tlb;
}
@@ -1361,8 +1307,8 @@ void dump_mmu(CPUPPCState *env)
}
}
-static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw)
+static int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+ MMUAccessType access_type)
{
int in_plb, ret;
@@ -1393,7 +1339,7 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
if (in_plb ^ msr_px) {
/* Access in protected area */
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
/* Access is not allowed */
ret = -2;
}
@@ -1413,28 +1359,28 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static int get_physical_address_wtlb(
- CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type,
- int mmu_idx)
+static int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr,
+ MMUAccessType access_type, int type,
+ int mmu_idx)
{
int ret = -1;
- bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
- || (access_type != ACCESS_CODE && msr_dr == 0);
+ bool real_mode = (type == ACCESS_CODE && msr_ir == 0)
+ || (type != ACCESS_CODE && msr_dr == 0);
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
case POWERPC_MMU_SOFT_74xx:
if (real_mode) {
- ret = check_physical(env, ctx, eaddr, rw);
+ ret = check_physical(env, ctx, eaddr, access_type);
} else {
/* Try to find a BAT */
if (env->nb_BATs != 0) {
- ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
+ ret = get_bat_6xx_tlb(env, ctx, eaddr, access_type);
}
if (ret < 0) {
/* We didn't match any BAT entry or don't have BATs */
- ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
+ ret = get_segment_6xx_tlb(env, ctx, eaddr, access_type, type);
}
}
break;
@@ -1442,19 +1388,17 @@ static int get_physical_address_wtlb(
case POWERPC_MMU_SOFT_4xx:
case POWERPC_MMU_SOFT_4xx_Z:
if (real_mode) {
- ret = check_physical(env, ctx, eaddr, rw);
+ ret = check_physical(env, ctx, eaddr, access_type);
} else {
- ret = mmu40x_get_physical_address(env, ctx, eaddr,
- rw, access_type);
+ ret = mmu40x_get_physical_address(env, ctx, eaddr, access_type);
}
break;
case POWERPC_MMU_BOOKE:
- ret = mmubooke_get_physical_address(env, ctx, eaddr,
- rw, access_type);
+ ret = mmubooke_get_physical_address(env, ctx, eaddr, access_type);
break;
case POWERPC_MMU_BOOKE206:
- ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
- access_type, mmu_idx);
+ ret = mmubooke206_get_physical_address(env, ctx, eaddr, access_type,
+ mmu_idx);
break;
case POWERPC_MMU_MPC8xx:
/* XXX: TODO */
@@ -1462,7 +1406,7 @@ static int get_physical_address_wtlb(
break;
case POWERPC_MMU_REAL:
if (real_mode) {
- ret = check_physical(env, ctx, eaddr, rw);
+ ret = check_physical(env, ctx, eaddr, access_type);
} else {
cpu_abort(env_cpu(env),
"PowerPC in real mode do not do any translation\n");
@@ -1476,11 +1420,11 @@ static int get_physical_address_wtlb(
return ret;
}
-static int get_physical_address(
- CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, int rw, int access_type)
+static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, MMUAccessType access_type,
+ int type)
{
- return get_physical_address_wtlb(env, ctx, eaddr, rw, access_type, 0);
+ return get_physical_address_wtlb(env, ctx, eaddr, access_type, type, 0);
}
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -1508,14 +1452,15 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
;
}
- if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
+ if (unlikely(get_physical_address(env, &ctx, addr, MMU_DATA_LOAD,
+ ACCESS_INT) != 0)) {
/*
* Some MMUs have separate TLBs for code and data. If we only
* try an ACCESS_INT, we may not be able to read instructions
* mapped by code TLBs, so we also try a ACCESS_CODE.
*/
- if (unlikely(get_physical_address(env, &ctx, addr, 0,
+ if (unlikely(get_physical_address(env, &ctx, addr, MMU_INST_FETCH,
ACCESS_CODE) != 0)) {
return -1;
}
@@ -1525,13 +1470,14 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
}
static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
- int rw, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx)
{
uint32_t epid;
bool as, pr;
uint32_t missed_tid = 0;
bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
- if (rw == 2) {
+
+ if (access_type == MMU_INST_FETCH) {
as = msr_ir;
}
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
@@ -1579,24 +1525,23 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
/* Perform address translation */
static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
- int rw, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx)
{
CPUState *cs = env_cpu(env);
PowerPCCPU *cpu = POWERPC_CPU(cs);
mmu_ctx_t ctx;
- int access_type;
+ int type;
int ret = 0;
- if (rw == 2) {
+ if (access_type == MMU_INST_FETCH) {
/* code access */
- rw = 0;
- access_type = ACCESS_CODE;
+ type = ACCESS_CODE;
} else {
/* data access */
- access_type = env->access_type;
+ type = env->access_type;
}
- ret = get_physical_address_wtlb(env, &ctx, address, rw,
- access_type, mmu_idx);
+ ret = get_physical_address_wtlb(env, &ctx, address, access_type,
+ type, mmu_idx);
if (ret == 0) {
tlb_set_page(cs, address & TARGET_PAGE_MASK,
ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
@@ -1604,7 +1549,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
ret = 0;
} else if (ret < 0) {
LOG_MMU_STATE(cs);
- if (access_type == ACCESS_CODE) {
+ if (type == ACCESS_CODE) {
switch (ret) {
case -1:
/* No matches in page tables or TLB */
@@ -1632,7 +1577,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
cs->exception_index = POWERPC_EXCP_ITLB;
env->error_code = 0;
env->spr[SPR_BOOKE_DEAR] = address;
- env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 0);
+ env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, MMU_DATA_LOAD);
return -1;
case POWERPC_MMU_MPC8xx:
/* XXX: TODO */
@@ -1674,7 +1619,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
/* No matches in page tables or TLB */
switch (env->mmu_model) {
case POWERPC_MMU_SOFT_6xx:
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
cs->exception_index = POWERPC_EXCP_DSTLB;
env->error_code = 1 << 16;
} else {
@@ -1691,7 +1636,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
get_pteg_offset32(cpu, ctx.hash[1]);
break;
case POWERPC_MMU_SOFT_74xx:
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
cs->exception_index = POWERPC_EXCP_DSTLB;
} else {
cs->exception_index = POWERPC_EXCP_DLTLB;
@@ -1708,7 +1653,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
cs->exception_index = POWERPC_EXCP_DTLB;
env->error_code = 0;
env->spr[SPR_40x_DEAR] = address;
- if (rw) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_40x_ESR] = 0x00800000;
} else {
env->spr[SPR_40x_ESR] = 0x00000000;
@@ -1719,13 +1664,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
break;
case POWERPC_MMU_BOOKE206:
- booke206_update_mas_tlb_miss(env, address, rw, mmu_idx);
+ booke206_update_mas_tlb_miss(env, address, access_type, mmu_idx);
/* fall through */
case POWERPC_MMU_BOOKE:
cs->exception_index = POWERPC_EXCP_DTLB;
env->error_code = 0;
env->spr[SPR_BOOKE_DEAR] = address;
- env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw);
+ env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
return -1;
case POWERPC_MMU_REAL:
cpu_abort(cs, "PowerPC in real mode should never raise "
@@ -1743,16 +1688,16 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
if (env->mmu_model == POWERPC_MMU_SOFT_4xx
|| env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
env->spr[SPR_40x_DEAR] = address;
- if (rw) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_40x_ESR] |= 0x00800000;
}
} else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->spr[SPR_BOOKE_DEAR] = address;
- env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw);
+ env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
} else {
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x0A000000;
} else {
env->spr[SPR_DSISR] = 0x08000000;
@@ -1761,7 +1706,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
break;
case -4:
/* Direct store exception */
- switch (access_type) {
+ switch (type) {
case ACCESS_FLOAT:
/* Floating point load/store */
cs->exception_index = POWERPC_EXCP_ALIGN;
@@ -1773,7 +1718,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x06000000;
} else {
env->spr[SPR_DSISR] = 0x04000000;
@@ -1784,7 +1729,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
cs->exception_index = POWERPC_EXCP_DSI;
env->error_code = 0;
env->spr[SPR_DAR] = address;
- if (rw == 1) {
+ if (access_type == MMU_DATA_STORE) {
env->spr[SPR_DSISR] = 0x06100000;
} else {
env->spr[SPR_DSISR] = 0x04100000;
@@ -2085,32 +2030,6 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
/*****************************************************************************/
/* Special registers manipulation */
-void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
-{
- PowerPCCPU *cpu = env_archcpu(env);
- qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
- assert(!cpu->vhyp);
-#if defined(TARGET_PPC64)
- if (mmu_is_64bit(env->mmu_model)) {
- target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
- target_ulong htabsize = value & SDR_64_HTABSIZE;
-
- if (value & ~sdr_mask) {
- error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1",
- value & ~sdr_mask);
- value &= sdr_mask;
- }
- if (htabsize > 28) {
- error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
- htabsize);
- return;
- }
- }
-#endif /* defined(TARGET_PPC64) */
- /* FIXME: Should check for valid HTABMASK values in 32-bit case */
- env->spr[SPR_SDR1] = value;
-}
-
#if defined(TARGET_PPC64)
void ppc_store_ptcr(CPUPPCState *env, target_ulong value)
{
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
new file mode 100644
index 0000000000..0be5f347d5
--- /dev/null
+++ b/target/ppc/spr_tcg.h
@@ -0,0 +1,136 @@
+/*
+ * PowerPC emulation for qemu: read/write callbacks for SPRs
+ *
+ * Copyright (C) 2021 Instituto de Pesquisas Eldorado
+ *
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef SPR_TCG_H
+#define SPR_TCG_H
+
+#define SPR_NOACCESS (&spr_noaccess)
+
+/* prototypes for readers and writers for SPRs */
+void spr_noaccess(DisasContext *ctx, int gprn, int sprn);
+void spr_read_generic(DisasContext *ctx, int gprn, int sprn);
+void spr_write_generic(DisasContext *ctx, int sprn, int gprn);
+void spr_read_xer(DisasContext *ctx, int gprn, int sprn);
+void spr_write_xer(DisasContext *ctx, int sprn, int gprn);
+void spr_read_lr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_lr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_ctr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_ctr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_ureg(DisasContext *ctx, int gprn, int sprn);
+void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
+void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
+void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
+void spr_read_atbu(DisasContext *ctx, int gprn, int sprn);
+void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn);
+void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
+void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
+
+#ifndef CONFIG_USER_ONLY
+void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
+void spr_write_clear(DisasContext *ctx, int sprn, int gprn);
+void spr_access_nop(DisasContext *ctx, int sprn, int gprn);
+void spr_read_decr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_decr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_tbl(DisasContext *ctx, int sprn, int gprn);
+void spr_write_tbu(DisasContext *ctx, int sprn, int gprn);
+void spr_write_atbl(DisasContext *ctx, int sprn, int gprn);
+void spr_write_atbu(DisasContext *ctx, int sprn, int gprn);
+void spr_read_ibat(DisasContext *ctx, int gprn, int sprn);
+void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn);
+void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn);
+void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn);
+void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn);
+void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn);
+void spr_read_dbat(DisasContext *ctx, int gprn, int sprn);
+void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn);
+void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn);
+void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn);
+void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn);
+void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn);
+void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn);
+void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn);
+void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn);
+void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn);
+void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn);
+void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn);
+void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn);
+void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn);
+void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn);
+void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn);
+void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn);
+void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_pir(DisasContext *ctx, int sprn, int gprn);
+void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn);
+void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn);
+void spr_read_thrm(DisasContext *ctx, int gprn, int sprn);
+void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn);
+void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn);
+void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn);
+void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn);
+void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn);
+void spr_write_eplc(DisasContext *ctx, int sprn, int gprn);
+void spr_write_epsc(DisasContext *ctx, int sprn, int gprn);
+void spr_write_mas73(DisasContext *ctx, int sprn, int gprn);
+void spr_read_mas73(DisasContext *ctx, int gprn, int sprn);
+#ifdef TARGET_PPC64
+void spr_read_cfar(DisasContext *ctx, int gprn, int sprn);
+void spr_write_cfar(DisasContext *ctx, int sprn, int gprn);
+void spr_write_ureg(DisasContext *ctx, int sprn, int gprn);
+void spr_read_purr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_purr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn);
+void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_vtb(DisasContext *ctx, int gprn, int sprn);
+void spr_write_vtb(DisasContext *ctx, int sprn, int gprn);
+void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn);
+void spr_write_pidr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_hior(DisasContext *ctx, int gprn, int sprn);
+void spr_write_hior(DisasContext *ctx, int sprn, int gprn);
+void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_pcr(DisasContext *ctx, int sprn, int gprn);
+void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn);
+void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn);
+void spr_write_amr(DisasContext *ctx, int sprn, int gprn);
+void spr_write_uamor(DisasContext *ctx, int sprn, int gprn);
+void spr_write_iamr(DisasContext *ctx, int sprn, int gprn);
+#endif
+#endif
+
+#ifdef TARGET_PPC64
+void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn);
+void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn);
+void spr_read_tar(DisasContext *ctx, int gprn, int sprn);
+void spr_write_tar(DisasContext *ctx, int sprn, int gprn);
+void spr_read_tm(DisasContext *ctx, int gprn, int sprn);
+void spr_write_tm(DisasContext *ctx, int sprn, int gprn);
+void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn);
+void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn);
+void spr_read_ebb(DisasContext *ctx, int gprn, int sprn);
+void spr_write_ebb(DisasContext *ctx, int sprn, int gprn);
+void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn);
+void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn);
+void spr_write_hmer(DisasContext *ctx, int sprn, int gprn);
+void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn);
+#endif
+
+#endif
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index a6381208a5..ea200f9637 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -36,7 +36,10 @@
#include "exec/translator.h"
#include "exec/log.h"
#include "qemu/atomic128.h"
+#include "spr_tcg.h"
+#include "qemu/qemu-print.h"
+#include "qapi/error.h"
#define CPU_SINGLE_STEP 0x1
#define CPU_BRANCH_STEP 0x2
@@ -154,8 +157,8 @@ void ppc_translate_init(void)
/* internal defines */
struct DisasContext {
DisasContextBase base;
+ target_ulong cia; /* current instruction address */
uint32_t opcode;
- uint32_t exception;
/* Routine used to access memory */
bool pr, hv, dr, le_mode;
bool lazy_tlb_flush;
@@ -181,6 +184,11 @@ struct DisasContext {
uint64_t insns_flags2;
};
+#define DISAS_EXIT DISAS_TARGET_0 /* exit to main loop, pc updated */
+#define DISAS_EXIT_UPDATE DISAS_TARGET_1 /* exit to main loop, pc stale */
+#define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */
+#define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */
+
/* Return true iff byteswap is needed in a scalar memop */
static inline bool need_byteswap(const DisasContext *ctx)
{
@@ -252,15 +260,13 @@ static void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)
* These are all synchronous exceptions, we set the PC back to the
* faulting instruction
*/
- if (ctx->exception == POWERPC_EXCP_NONE) {
- gen_update_nip(ctx, ctx->base.pc_next - 4);
- }
+ gen_update_nip(ctx, ctx->cia);
t0 = tcg_const_i32(excp);
t1 = tcg_const_i32(error);
gen_helper_raise_exception_err(cpu_env, t0, t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
- ctx->exception = (excp);
+ ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception(DisasContext *ctx, uint32_t excp)
@@ -271,13 +277,11 @@ static void gen_exception(DisasContext *ctx, uint32_t excp)
* These are all synchronous exceptions, we set the PC back to the
* faulting instruction
*/
- if (ctx->exception == POWERPC_EXCP_NONE) {
- gen_update_nip(ctx, ctx->base.pc_next - 4);
- }
+ gen_update_nip(ctx, ctx->cia);
t0 = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
- ctx->exception = (excp);
+ ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
@@ -289,7 +293,21 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
t0 = tcg_const_i32(excp);
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
- ctx->exception = (excp);
+ ctx->base.is_jmp = DISAS_NORETURN;
+}
+
+static void gen_icount_io_start(DisasContext *ctx)
+{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ /*
+ * An I/O instruction must be last in the TB.
+ * Chain to the next TB, and let the code from gen_tb_start
+ * decide if we need to return to the main loop.
+ * Doing this first also allows this value to be overridden.
+ */
+ ctx->base.is_jmp = DISAS_TOO_MANY;
+ }
}
/*
@@ -322,19 +340,8 @@ static uint32_t gen_prep_dbgex(DisasContext *ctx)
static void gen_debug_exception(DisasContext *ctx)
{
- TCGv_i32 t0;
-
- /*
- * These are all synchronous exceptions, we set the PC back to the
- * faulting instruction
- */
- if ((ctx->exception != POWERPC_EXCP_BRANCH) &&
- (ctx->exception != POWERPC_EXCP_SYNC)) {
- gen_update_nip(ctx, ctx->base.pc_next);
- }
- t0 = tcg_const_i32(EXCP_DEBUG);
- gen_helper_raise_exception(cpu_env, t0);
- tcg_temp_free_i32(t0);
+ gen_helper_raise_exception(cpu_env, tcg_constant_i32(EXCP_DEBUG));
+ ctx->base.is_jmp = DISAS_NORETURN;
}
static inline void gen_inval_exception(DisasContext *ctx, uint32_t error)
@@ -354,18 +361,924 @@ static inline void gen_hvpriv_exception(DisasContext *ctx, uint32_t error)
gen_exception_err(ctx, POWERPC_EXCP_HV_EMU, POWERPC_EXCP_PRIV | error);
}
-/* Stop translation */
-static inline void gen_stop_exception(DisasContext *ctx)
+/*****************************************************************************/
+/* SPR READ/WRITE CALLBACKS */
+
+void spr_noaccess(DisasContext *ctx, int gprn, int sprn)
{
- gen_update_nip(ctx, ctx->base.pc_next);
- ctx->exception = POWERPC_EXCP_STOP;
+#if 0
+ sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+ printf("ERROR: try to access SPR %d !\n", sprn);
+#endif
+}
+
+/* #define PPC_DUMP_SPR_ACCESSES */
+
+/*
+ * Generic callbacks:
+ * do nothing but store/retrieve spr value
+ */
+static void spr_load_dump_spr(int sprn)
+{
+#ifdef PPC_DUMP_SPR_ACCESSES
+ TCGv_i32 t0 = tcg_const_i32(sprn);
+ gen_helper_load_dump_spr(cpu_env, t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+void spr_read_generic(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_load_spr(cpu_gpr[gprn], sprn);
+ spr_load_dump_spr(sprn);
+}
+
+static void spr_store_dump_spr(int sprn)
+{
+#ifdef PPC_DUMP_SPR_ACCESSES
+ TCGv_i32 t0 = tcg_const_i32(sprn);
+ gen_helper_store_dump_spr(cpu_env, t0);
+ tcg_temp_free_i32(t0);
+#endif
+}
+
+void spr_write_generic(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_store_spr(sprn, cpu_gpr[gprn]);
+ spr_store_dump_spr(sprn);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_generic32(DisasContext *ctx, int sprn, int gprn)
+{
+#ifdef TARGET_PPC64
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ext32u_tl(t0, cpu_gpr[gprn]);
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+ spr_store_dump_spr(sprn);
+#else
+ spr_write_generic(ctx, sprn, gprn);
+#endif
+}
+
+void spr_write_clear(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ gen_load_spr(t0, sprn);
+ tcg_gen_neg_tl(t1, cpu_gpr[gprn]);
+ tcg_gen_and_tl(t0, t0, t1);
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+void spr_access_nop(DisasContext *ctx, int sprn, int gprn)
+{
+}
+
+#endif
+
+/* SPR common to all PowerPC */
+/* XER */
+void spr_read_xer(DisasContext *ctx, int gprn, int sprn)
+{
+ TCGv dst = cpu_gpr[gprn];
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+ tcg_gen_mov_tl(dst, cpu_xer);
+ tcg_gen_shli_tl(t0, cpu_so, XER_SO);
+ tcg_gen_shli_tl(t1, cpu_ov, XER_OV);
+ tcg_gen_shli_tl(t2, cpu_ca, XER_CA);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_or_tl(dst, dst, t2);
+ tcg_gen_or_tl(dst, dst, t0);
+ if (is_isa300(ctx)) {
+ tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32);
+ tcg_gen_or_tl(dst, dst, t0);
+ tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32);
+ tcg_gen_or_tl(dst, dst, t0);
+ }
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+}
+
+void spr_write_xer(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv src = cpu_gpr[gprn];
+ /* Write all flags, while reading back check for isa300 */
+ tcg_gen_andi_tl(cpu_xer, src,
+ ~((1u << XER_SO) |
+ (1u << XER_OV) | (1u << XER_OV32) |
+ (1u << XER_CA) | (1u << XER_CA32)));
+ tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1);
+ tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1);
+ tcg_gen_extract_tl(cpu_so, src, XER_SO, 1);
+ tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1);
+ tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
+}
+
+/* LR */
+void spr_read_lr(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_mov_tl(cpu_gpr[gprn], cpu_lr);
+}
+
+void spr_write_lr(DisasContext *ctx, int sprn, int gprn)
+{
+ tcg_gen_mov_tl(cpu_lr, cpu_gpr[gprn]);
+}
+
+/* CFAR */
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+void spr_read_cfar(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_mov_tl(cpu_gpr[gprn], cpu_cfar);
+}
+
+void spr_write_cfar(DisasContext *ctx, int sprn, int gprn)
+{
+ tcg_gen_mov_tl(cpu_cfar, cpu_gpr[gprn]);
+}
+#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
+
+/* CTR */
+void spr_read_ctr(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_mov_tl(cpu_gpr[gprn], cpu_ctr);
+}
+
+void spr_write_ctr(DisasContext *ctx, int sprn, int gprn)
+{
+ tcg_gen_mov_tl(cpu_ctr, cpu_gpr[gprn]);
+}
+
+/* User read access to SPR */
+/* USPRx */
+/* UMMCRx */
+/* UPMCx */
+/* USIA */
+/* UDECR */
+void spr_read_ureg(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_load_spr(cpu_gpr[gprn], sprn + 0x10);
+}
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+void spr_write_ureg(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_store_spr(sprn + 0x10, cpu_gpr[gprn]);
+}
+#endif
+
+/* SPR common to all non-embedded PowerPC */
+/* DECR */
+#if !defined(CONFIG_USER_ONLY)
+void spr_read_decr(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_decr(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_decr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_decr(cpu_env, cpu_gpr[gprn]);
+}
+#endif
+
+/* SPR common to all non-embedded PowerPC, except 601 */
+/* Time base */
+void spr_read_tbl(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_tbl(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_read_tbu(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_tbu(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_read_atbl(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_atbl(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_read_atbu(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_atbu(cpu_gpr[gprn], cpu_env);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_tbl(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_tbl(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_tbu(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_tbu(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_atbl(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_atbl(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_atbu(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_atbu(cpu_env, cpu_gpr[gprn]);
+}
+
+#if defined(TARGET_PPC64)
+void spr_read_purr(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_purr(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_purr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_purr(cpu_env, cpu_gpr[gprn]);
+}
+
+/* HDECR */
+void spr_read_hdecr(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_hdecr(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_hdecr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_hdecr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_read_vtb(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_vtb(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_vtb(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_vtb(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_tbu40(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_tbu40(cpu_env, cpu_gpr[gprn]);
+}
+
+#endif
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* IBAT0U...IBAT0U */
+/* IBAT0L...IBAT7L */
+void spr_read_ibat(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState,
+ IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
+}
+
+void spr_read_ibat_h(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState,
+ IBAT[sprn & 1][((sprn - SPR_IBAT4U) / 2) + 4]));
+}
+
+void spr_write_ibatu(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+ gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_ibatu_h(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4U) / 2) + 4);
+ gen_helper_store_ibatu(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_ibatl(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0L) / 2);
+ gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_ibatl_h(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_IBAT4L) / 2) + 4);
+ gen_helper_store_ibatl(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+/* DBAT0U...DBAT7U */
+/* DBAT0L...DBAT7L */
+void spr_read_dbat(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState,
+ DBAT[sprn & 1][(sprn - SPR_DBAT0U) / 2]));
+}
+
+void spr_read_dbat_h(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState,
+ DBAT[sprn & 1][((sprn - SPR_DBAT4U) / 2) + 4]));
+}
+
+void spr_write_dbatu(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0U) / 2);
+ gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_dbatu_h(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4U) / 2) + 4);
+ gen_helper_store_dbatu(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_DBAT0L) / 2);
+ gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(((sprn - SPR_DBAT4L) / 2) + 4);
+ gen_helper_store_dbatl(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+/* SDR1 */
+void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_sdr1(cpu_env, cpu_gpr[gprn]);
+}
+
+#if defined(TARGET_PPC64)
+/* 64 bits PowerPC specific SPRs */
+/* PIDR */
+void spr_write_pidr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_pidr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_lpidr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_lpidr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_read_hior(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUPPCState, excp_prefix));
+}
+
+void spr_write_hior(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0x3FFFFF00000ULL);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
+ tcg_temp_free(t0);
+}
+void spr_write_ptcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_ptcr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_pcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_pcr(cpu_env, cpu_gpr[gprn]);
+}
+
+/* DPDES */
+void spr_read_dpdes(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_dpdes(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_dpdes(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_dpdes(cpu_env, cpu_gpr[gprn]);
+}
+#endif
+#endif
+
+/* PowerPC 601 specific registers */
+/* RTC */
+void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
+ /* Must stop the translation as endianness may have changed */
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState,
+ IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
+}
+
+void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+ gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
+ gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env);
+}
+
+void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_store_spr(sprn, cpu_gpr[gprn]);
+ gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
+ /* We must stop translation as we may have rebooted */
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
+}
+
+void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_icount_io_start(ctx);
+ gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]);
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+void spr_read_403_pbr(DisasContext *ctx, int gprn, int sprn)
+{
+ tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
+ offsetof(CPUPPCState, pb[sprn - SPR_403_PBL1]));
+}
+
+void spr_write_403_pbr(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(sprn - SPR_403_PBL1);
+ gen_helper_store_403_pbr(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_pir(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn], 0xF);
+ gen_store_spr(SPR_PIR, t0);
+ tcg_temp_free(t0);
+}
+#endif
+
+/* SPE specific registers */
+void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn)
+{
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
+ tcg_gen_extu_i32_tl(cpu_gpr[gprn], t0);
+ tcg_temp_free_i32(t0);
+}
+
+void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_temp_new_i32();
+ tcg_gen_trunc_tl_i32(t0, cpu_gpr[gprn]);
+ tcg_gen_st_i32(t0, cpu_env, offsetof(CPUPPCState, spe_fscr));
+ tcg_temp_free_i32(t0);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Callback used to write the exception vector base */
+void spr_write_excp_prefix(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivpr_mask));
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_prefix));
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+}
+
+void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
+{
+ int sprn_offs;
+
+ if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
+ sprn_offs = sprn - SPR_BOOKE_IVOR0;
+ } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
+ sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
+ } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
+ sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
+ } else {
+ printf("Trying to write an unknown exception vector %d %03x\n",
+ sprn, sprn);
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ return;
+ }
+
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+}
+#endif
+
+#ifdef TARGET_PPC64
+#ifndef CONFIG_USER_ONLY
+void spr_write_amr(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ /*
+ * Note, the HV=1 PR=0 case is handled earlier by simply using
+ * spr_write_generic for HV mode in the SPR table
+ */
+
+ /* Build insertion mask into t1 based on context */
+ if (ctx->pr) {
+ gen_load_spr(t1, SPR_UAMOR);
+ } else {
+ gen_load_spr(t1, SPR_AMOR);
+ }
+
+ /* Mask new bits into t2 */
+ tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+ /* Load AMR and clear new bits in t0 */
+ gen_load_spr(t0, SPR_AMR);
+ tcg_gen_andc_tl(t0, t0, t1);
+
+ /* Or'in new bits and write it out */
+ tcg_gen_or_tl(t0, t0, t2);
+ gen_store_spr(SPR_AMR, t0);
+ spr_store_dump_spr(SPR_AMR);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
}
+void spr_write_uamor(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ /*
+ * Note, the HV=1 case is handled earlier by simply using
+ * spr_write_generic for HV mode in the SPR table
+ */
+
+ /* Build insertion mask into t1 based on context */
+ gen_load_spr(t1, SPR_AMOR);
+
+ /* Mask new bits into t2 */
+ tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+ /* Load AMR and clear new bits in t0 */
+ gen_load_spr(t0, SPR_UAMOR);
+ tcg_gen_andc_tl(t0, t0, t1);
+
+ /* Or'in new bits and write it out */
+ tcg_gen_or_tl(t0, t0, t2);
+ gen_store_spr(SPR_UAMOR, t0);
+ spr_store_dump_spr(SPR_UAMOR);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+}
+
+void spr_write_iamr(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ /*
+ * Note, the HV=1 case is handled earlier by simply using
+ * spr_write_generic for HV mode in the SPR table
+ */
+
+ /* Build insertion mask into t1 based on context */
+ gen_load_spr(t1, SPR_AMOR);
+
+ /* Mask new bits into t2 */
+ tcg_gen_and_tl(t2, t1, cpu_gpr[gprn]);
+
+ /* Load AMR and clear new bits in t0 */
+ gen_load_spr(t0, SPR_IAMR);
+ tcg_gen_andc_tl(t0, t0, t1);
+
+ /* Or'in new bits and write it out */
+ tcg_gen_or_tl(t0, t0, t2);
+ gen_store_spr(SPR_IAMR, t0);
+ spr_store_dump_spr(SPR_IAMR);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+}
+#endif
+#endif
+
#ifndef CONFIG_USER_ONLY
-/* No need to update nip here, as execution flow will change */
-static inline void gen_sync_exception(DisasContext *ctx)
+void spr_read_thrm(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_helper_fixup_thrm(cpu_env);
+ gen_load_spr(cpu_gpr[gprn], sprn);
+ spr_load_dump_spr(sprn);
+}
+#endif /* !CONFIG_USER_ONLY */
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_e500_l1csr0(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR0_DCE | L1CSR0_CPE);
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+}
+
+void spr_write_e500_l1csr1(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn], L1CSR1_ICE | L1CSR1_CPE);
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+}
+
+void spr_write_e500_l2csr0(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv t0 = tcg_temp_new();
+
+ tcg_gen_andi_tl(t0, cpu_gpr[gprn],
+ ~(E500_L2CSR0_L2FI | E500_L2CSR0_L2FL | E500_L2CSR0_L2LFC));
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
+}
+
+void spr_write_booke206_mmucsr0(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_booke206_tlbflush(cpu_env, cpu_gpr[gprn]);
+}
+
+void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv_i32 t0 = tcg_const_i32(sprn);
+ gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]);
+ tcg_temp_free_i32(t0);
+}
+void spr_write_eplc(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]);
+}
+void spr_write_epsc(DisasContext *ctx, int sprn, int gprn)
{
- ctx->exception = POWERPC_EXCP_SYNC;
+ gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]);
+}
+
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_mas73(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv val = tcg_temp_new();
+ tcg_gen_ext32u_tl(val, cpu_gpr[gprn]);
+ gen_store_spr(SPR_BOOKE_MAS3, val);
+ tcg_gen_shri_tl(val, cpu_gpr[gprn], 32);
+ gen_store_spr(SPR_BOOKE_MAS7, val);
+ tcg_temp_free(val);
+}
+
+void spr_read_mas73(DisasContext *ctx, int gprn, int sprn)
+{
+ TCGv mas7 = tcg_temp_new();
+ TCGv mas3 = tcg_temp_new();
+ gen_load_spr(mas7, SPR_BOOKE_MAS7);
+ tcg_gen_shli_tl(mas7, mas7, 32);
+ gen_load_spr(mas3, SPR_BOOKE_MAS3);
+ tcg_gen_or_tl(cpu_gpr[gprn], mas3, mas7);
+ tcg_temp_free(mas3);
+ tcg_temp_free(mas7);
+}
+
+#endif
+
+#ifdef TARGET_PPC64
+static void gen_fscr_facility_check(DisasContext *ctx, int facility_sprn,
+ int bit, int sprn, int cause)
+{
+ TCGv_i32 t1 = tcg_const_i32(bit);
+ TCGv_i32 t2 = tcg_const_i32(sprn);
+ TCGv_i32 t3 = tcg_const_i32(cause);
+
+ gen_helper_fscr_facility_check(cpu_env, t1, t2, t3);
+
+ tcg_temp_free_i32(t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+static void gen_msr_facility_check(DisasContext *ctx, int facility_sprn,
+ int bit, int sprn, int cause)
+{
+ TCGv_i32 t1 = tcg_const_i32(bit);
+ TCGv_i32 t2 = tcg_const_i32(sprn);
+ TCGv_i32 t3 = tcg_const_i32(cause);
+
+ gen_helper_msr_facility_check(cpu_env, t1, t2, t3);
+
+ tcg_temp_free_i32(t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+void spr_read_prev_upper32(DisasContext *ctx, int gprn, int sprn)
+{
+ TCGv spr_up = tcg_temp_new();
+ TCGv spr = tcg_temp_new();
+
+ gen_load_spr(spr, sprn - 1);
+ tcg_gen_shri_tl(spr_up, spr, 32);
+ tcg_gen_ext32u_tl(cpu_gpr[gprn], spr_up);
+
+ tcg_temp_free(spr);
+ tcg_temp_free(spr_up);
+}
+
+void spr_write_prev_upper32(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv spr = tcg_temp_new();
+
+ gen_load_spr(spr, sprn - 1);
+ tcg_gen_deposit_tl(spr, spr, cpu_gpr[gprn], 32, 32);
+ gen_store_spr(sprn - 1, spr);
+
+ tcg_temp_free(spr);
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void spr_write_hmer(DisasContext *ctx, int sprn, int gprn)
+{
+ TCGv hmer = tcg_temp_new();
+
+ gen_load_spr(hmer, sprn);
+ tcg_gen_and_tl(hmer, cpu_gpr[gprn], hmer);
+ gen_store_spr(sprn, hmer);
+ spr_store_dump_spr(sprn);
+ tcg_temp_free(hmer);
+}
+
+void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+void spr_read_tar(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR);
+ spr_read_generic(ctx, gprn, sprn);
+}
+
+void spr_write_tar(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_TAR, sprn, FSCR_IC_TAR);
+ spr_write_generic(ctx, sprn, gprn);
+}
+
+void spr_read_tm(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
+ spr_read_generic(ctx, gprn, sprn);
+}
+
+void spr_write_tm(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
+ spr_write_generic(ctx, sprn, gprn);
+}
+
+void spr_read_tm_upper32(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
+ spr_read_prev_upper32(ctx, gprn, sprn);
+}
+
+void spr_write_tm_upper32(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_msr_facility_check(ctx, SPR_FSCR, MSR_TM, sprn, FSCR_IC_TM);
+ spr_write_prev_upper32(ctx, sprn, gprn);
+}
+
+void spr_read_ebb(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
+ spr_read_generic(ctx, gprn, sprn);
+}
+
+void spr_write_ebb(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
+ spr_write_generic(ctx, sprn, gprn);
+}
+
+void spr_read_ebb_upper32(DisasContext *ctx, int gprn, int sprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
+ spr_read_prev_upper32(ctx, gprn, sprn);
+}
+
+void spr_write_ebb_upper32(DisasContext *ctx, int sprn, int gprn)
+{
+ gen_fscr_facility_check(ctx, SPR_FSCR, FSCR_EBB, sprn, FSCR_IC_EBB);
+ spr_write_prev_upper32(ctx, sprn, gprn);
}
#endif
@@ -1851,18 +2764,13 @@ static void gen_darn(DisasContext *ctx)
if (l > 2) {
tcg_gen_movi_i64(cpu_gpr[rD(ctx->opcode)], -1);
} else {
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
+ gen_icount_io_start(ctx);
if (l == 0) {
gen_helper_darn32(cpu_gpr[rD(ctx->opcode)]);
} else {
/* Return 64-bit random for both CRN and RRN */
gen_helper_darn64(cpu_gpr[rD(ctx->opcode)]);
}
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_stop_exception(ctx);
- }
}
}
#endif
@@ -3112,7 +4020,7 @@ static void gen_eieio(DisasContext *ctx)
*/
if (!(ctx->insns_flags2 & PPC2_ISA300)) {
qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @"
- TARGET_FMT_lx "\n", ctx->base.pc_next - 4);
+ TARGET_FMT_lx "\n", ctx->cia);
} else {
bar = TCG_MO_ST_LD;
}
@@ -3157,7 +4065,7 @@ static void gen_isync(DisasContext *ctx)
gen_check_tlb_flush(ctx, false);
}
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
- gen_stop_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
}
#define MEMOP_GET_SIZE(x) (1 << ((x) & MO_SIZE))
@@ -3740,8 +4648,9 @@ static void gen_lookup_and_goto_ptr(DisasContext *ctx)
} else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) {
uint32_t excp = gen_prep_dbgex(ctx);
gen_exception(ctx, excp);
+ } else {
+ tcg_gen_exit_tb(NULL, 0);
}
- tcg_gen_exit_tb(NULL, 0);
} else {
tcg_gen_lookup_and_goto_ptr();
}
@@ -3776,20 +4685,20 @@ static void gen_b(DisasContext *ctx)
{
target_ulong li, target;
- ctx->exception = POWERPC_EXCP_BRANCH;
/* sign extend LI */
li = LI(ctx->opcode);
li = (li ^ 0x02000000) - 0x02000000;
if (likely(AA(ctx->opcode) == 0)) {
- target = ctx->base.pc_next + li - 4;
+ target = ctx->cia + li;
} else {
target = li;
}
if (LK(ctx->opcode)) {
gen_setlr(ctx, ctx->base.pc_next);
}
- gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_update_cfar(ctx, ctx->cia);
gen_goto_tb(ctx, 0, target);
+ ctx->base.is_jmp = DISAS_NORETURN;
}
#define BCOND_IM 0
@@ -3802,7 +4711,6 @@ static void gen_bcond(DisasContext *ctx, int type)
uint32_t bo = BO(ctx->opcode);
TCGLabel *l1;
TCGv target;
- ctx->exception = POWERPC_EXCP_BRANCH;
if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
target = tcg_temp_local_new();
@@ -3887,11 +4795,11 @@ static void gen_bcond(DisasContext *ctx, int type)
}
tcg_temp_free_i32(temp);
}
- gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_update_cfar(ctx, ctx->cia);
if (type == BCOND_IM) {
target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
if (likely(AA(ctx->opcode) == 0)) {
- gen_goto_tb(ctx, 0, ctx->base.pc_next + li - 4);
+ gen_goto_tb(ctx, 0, ctx->cia + li);
} else {
gen_goto_tb(ctx, 0, li);
}
@@ -3909,6 +4817,7 @@ static void gen_bcond(DisasContext *ctx, int type)
gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->base.pc_next);
}
+ ctx->base.is_jmp = DISAS_NORETURN;
}
static void gen_bc(DisasContext *ctx)
@@ -4004,12 +4913,10 @@ static void gen_rfi(DisasContext *ctx)
}
/* Restore CPU state */
CHK_SV;
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_icount_io_start(ctx);
+ gen_update_cfar(ctx, ctx->cia);
gen_helper_rfi(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif
}
@@ -4021,12 +4928,10 @@ static void gen_rfid(DisasContext *ctx)
#else
/* Restore CPU state */
CHK_SV;
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_icount_io_start(ctx);
+ gen_update_cfar(ctx, ctx->cia);
gen_helper_rfid(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif
}
@@ -4038,12 +4943,10 @@ static void gen_rfscv(DisasContext *ctx)
#else
/* Restore CPU state */
CHK_SV;
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_update_cfar(ctx, ctx->base.pc_next - 4);
+ gen_icount_io_start(ctx);
+ gen_update_cfar(ctx, ctx->cia);
gen_helper_rfscv(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif
}
#endif
@@ -4056,7 +4959,7 @@ static void gen_hrfid(DisasContext *ctx)
/* Restore CPU state */
CHK_HV;
gen_helper_hrfid(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif
}
#endif
@@ -4083,13 +4986,10 @@ static void gen_scv(DisasContext *ctx)
uint32_t lev = (ctx->opcode >> 5) & 0x7F;
/* Set the PC back to the faulting instruction. */
- if (ctx->exception == POWERPC_EXCP_NONE) {
- gen_update_nip(ctx, ctx->base.pc_next - 4);
- }
+ gen_update_nip(ctx, ctx->cia);
gen_helper_scv(cpu_env, tcg_constant_i32(lev));
- /* This need not be exact, just not POWERPC_EXCP_NONE */
- ctx->exception = POWERPC_SYSCALL_VECTORED;
+ ctx->base.is_jmp = DISAS_NORETURN;
}
#endif
#endif
@@ -4175,43 +5075,6 @@ static void gen_tdi(DisasContext *ctx)
/*** Processor control ***/
-static void gen_read_xer(DisasContext *ctx, TCGv dst)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- tcg_gen_mov_tl(dst, cpu_xer);
- tcg_gen_shli_tl(t0, cpu_so, XER_SO);
- tcg_gen_shli_tl(t1, cpu_ov, XER_OV);
- tcg_gen_shli_tl(t2, cpu_ca, XER_CA);
- tcg_gen_or_tl(t0, t0, t1);
- tcg_gen_or_tl(dst, dst, t2);
- tcg_gen_or_tl(dst, dst, t0);
- if (is_isa300(ctx)) {
- tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32);
- tcg_gen_or_tl(dst, dst, t0);
- tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32);
- tcg_gen_or_tl(dst, dst, t0);
- }
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
-}
-
-static void gen_write_xer(TCGv src)
-{
- /* Write all flags, while reading back check for isa300 */
- tcg_gen_andi_tl(cpu_xer, src,
- ~((1u << XER_SO) |
- (1u << XER_OV) | (1u << XER_OV32) |
- (1u << XER_CA) | (1u << XER_CA32)));
- tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1);
- tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1);
- tcg_gen_extract_tl(cpu_so, src, XER_SO, 1);
- tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1);
- tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
-}
-
/* mcrxr */
static void gen_mcrxr(DisasContext *ctx)
{
@@ -4299,15 +5162,6 @@ static void gen_mfmsr(DisasContext *ctx)
tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr);
}
-static void spr_noaccess(DisasContext *ctx, int gprn, int sprn)
-{
-#if 0
- sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
- printf("ERROR: try to access SPR %d !\n", sprn);
-#endif
-}
-#define SPR_NOACCESS (&spr_noaccess)
-
/* mfspr */
static inline void gen_op_mfspr(DisasContext *ctx)
{
@@ -4338,7 +5192,7 @@ static inline void gen_op_mfspr(DisasContext *ctx)
if (sprn != SPR_PVR) {
qemu_log_mask(LOG_GUEST_ERROR, "Trying to read privileged spr "
"%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn,
- ctx->base.pc_next - 4);
+ ctx->cia);
}
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
}
@@ -4352,7 +5206,7 @@ static inline void gen_op_mfspr(DisasContext *ctx)
/* Not defined */
qemu_log_mask(LOG_GUEST_ERROR,
"Trying to read invalid spr %d (0x%03x) at "
- TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4);
+ TARGET_FMT_lx "\n", sprn, sprn, ctx->cia);
/*
* The behaviour depends on MSR:PR and SPR# bit 0x10, it can
@@ -4416,9 +5270,7 @@ static void gen_mtmsrd(DisasContext *ctx)
CHK_SV;
#if !defined(CONFIG_USER_ONLY)
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
+ gen_icount_io_start(ctx);
if (ctx->opcode & 0x00010000) {
/* L=1 form only updates EE and RI */
TCGv t0 = tcg_temp_new();
@@ -4443,7 +5295,7 @@ static void gen_mtmsrd(DisasContext *ctx)
gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]);
}
/* Must stop the translation as machine state (may have) changed */
- gen_stop_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
#endif /* !defined(CONFIG_USER_ONLY) */
}
#endif /* defined(TARGET_PPC64) */
@@ -4453,9 +5305,7 @@ static void gen_mtmsr(DisasContext *ctx)
CHK_SV;
#if !defined(CONFIG_USER_ONLY)
- if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
+ gen_icount_io_start(ctx);
if (ctx->opcode & 0x00010000) {
/* L=1 form only updates EE and RI */
TCGv t0 = tcg_temp_new();
@@ -4488,7 +5338,7 @@ static void gen_mtmsr(DisasContext *ctx)
tcg_temp_free(msr);
}
/* Must stop the translation as machine state (may have) changed */
- gen_stop_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
#endif
}
@@ -4516,7 +5366,7 @@ static void gen_mtspr(DisasContext *ctx)
/* Privilege exception */
qemu_log_mask(LOG_GUEST_ERROR, "Trying to write privileged spr "
"%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn,
- ctx->base.pc_next - 4);
+ ctx->cia);
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG);
}
} else {
@@ -4530,7 +5380,7 @@ static void gen_mtspr(DisasContext *ctx)
/* Not defined */
qemu_log_mask(LOG_GUEST_ERROR,
"Trying to write invalid spr %d (0x%03x) at "
- TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - 4);
+ TARGET_FMT_lx "\n", sprn, sprn, ctx->cia);
/*
@@ -5943,7 +6793,7 @@ static void gen_rfsvc(DisasContext *ctx)
CHK_SV;
gen_helper_rfsvc(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6323,7 +7173,7 @@ static void gen_rfci_40x(DisasContext *ctx)
CHK_SV;
/* Restore CPU state */
gen_helper_40x_rfci(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6335,7 +7185,7 @@ static void gen_rfci(DisasContext *ctx)
CHK_SV;
/* Restore CPU state */
gen_helper_rfci(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6350,7 +7200,7 @@ static void gen_rfdi(DisasContext *ctx)
CHK_SV;
/* Restore CPU state */
gen_helper_rfdi(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6363,7 +7213,7 @@ static void gen_rfmci(DisasContext *ctx)
CHK_SV;
/* Restore CPU state */
gen_helper_rfmci(cpu_env);
- gen_sync_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6625,7 +7475,7 @@ static void gen_wrtee(DisasContext *ctx)
* Stop translation to have a chance to raise an exception if we
* just set msr_ee to 1
*/
- gen_stop_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
#endif /* defined(CONFIG_USER_ONLY) */
}
@@ -6639,7 +7489,7 @@ static void gen_wrteei(DisasContext *ctx)
if (ctx->opcode & 0x00008000) {
tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
/* Stop translation to have a chance to raise an exception */
- gen_stop_exception(ctx);
+ ctx->base.is_jmp = DISAS_EXIT_UPDATE;
} else {
tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
}
@@ -7638,194 +8488,6 @@ GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \
#include "translate/spe-ops.c.inc"
};
-#include "helper_regs.h"
-#include "translate_init.c.inc"
-
-/*****************************************************************************/
-/* Misc PowerPC helpers */
-void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
-#define RGPL 4
-#define RFPL 4
-
- PowerPCCPU *cpu = POWERPC_CPU(cs);
- CPUPPCState *env = &cpu->env;
- int i;
-
- qemu_fprintf(f, "NIP " TARGET_FMT_lx " LR " TARGET_FMT_lx " CTR "
- TARGET_FMT_lx " XER " TARGET_FMT_lx " CPU#%d\n",
- env->nip, env->lr, env->ctr, cpu_read_xer(env),
- cs->cpu_index);
- qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF "
- "%08x iidx %d didx %d\n",
- env->msr, env->spr[SPR_HID0], env->hflags,
- cpu_mmu_index(env, true), cpu_mmu_index(env, false));
-#if !defined(NO_TIMER_DUMP)
- qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
-#if !defined(CONFIG_USER_ONLY)
- " DECR " TARGET_FMT_lu
-#endif
- "\n",
- cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
-#if !defined(CONFIG_USER_ONLY)
- , cpu_ppc_load_decr(env)
-#endif
- );
-#endif
- for (i = 0; i < 32; i++) {
- if ((i & (RGPL - 1)) == 0) {
- qemu_fprintf(f, "GPR%02d", i);
- }
- qemu_fprintf(f, " %016" PRIx64, ppc_dump_gpr(env, i));
- if ((i & (RGPL - 1)) == (RGPL - 1)) {
- qemu_fprintf(f, "\n");
- }
- }
- qemu_fprintf(f, "CR ");
- for (i = 0; i < 8; i++)
- qemu_fprintf(f, "%01x", env->crf[i]);
- qemu_fprintf(f, " [");
- for (i = 0; i < 8; i++) {
- char a = '-';
- if (env->crf[i] & 0x08) {
- a = 'L';
- } else if (env->crf[i] & 0x04) {
- a = 'G';
- } else if (env->crf[i] & 0x02) {
- a = 'E';
- }
- qemu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
- }
- qemu_fprintf(f, " ] RES " TARGET_FMT_lx "\n",
- env->reserve_addr);
-
- if (flags & CPU_DUMP_FPU) {
- for (i = 0; i < 32; i++) {
- if ((i & (RFPL - 1)) == 0) {
- qemu_fprintf(f, "FPR%02d", i);
- }
- qemu_fprintf(f, " %016" PRIx64, *cpu_fpr_ptr(env, i));
- if ((i & (RFPL - 1)) == (RFPL - 1)) {
- qemu_fprintf(f, "\n");
- }
- }
- qemu_fprintf(f, "FPSCR " TARGET_FMT_lx "\n", env->fpscr);
- }
-
-#if !defined(CONFIG_USER_ONLY)
- qemu_fprintf(f, " SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx
- " PVR " TARGET_FMT_lx " VRSAVE " TARGET_FMT_lx "\n",
- env->spr[SPR_SRR0], env->spr[SPR_SRR1],
- env->spr[SPR_PVR], env->spr[SPR_VRSAVE]);
-
- qemu_fprintf(f, "SPRG0 " TARGET_FMT_lx " SPRG1 " TARGET_FMT_lx
- " SPRG2 " TARGET_FMT_lx " SPRG3 " TARGET_FMT_lx "\n",
- env->spr[SPR_SPRG0], env->spr[SPR_SPRG1],
- env->spr[SPR_SPRG2], env->spr[SPR_SPRG3]);
-
- qemu_fprintf(f, "SPRG4 " TARGET_FMT_lx " SPRG5 " TARGET_FMT_lx
- " SPRG6 " TARGET_FMT_lx " SPRG7 " TARGET_FMT_lx "\n",
- env->spr[SPR_SPRG4], env->spr[SPR_SPRG5],
- env->spr[SPR_SPRG6], env->spr[SPR_SPRG7]);
-
-#if defined(TARGET_PPC64)
- if (env->excp_model == POWERPC_EXCP_POWER7 ||
- env->excp_model == POWERPC_EXCP_POWER8 ||
- env->excp_model == POWERPC_EXCP_POWER9 ||
- env->excp_model == POWERPC_EXCP_POWER10) {
- qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n",
- env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]);
- }
-#endif
- if (env->excp_model == POWERPC_EXCP_BOOKE) {
- qemu_fprintf(f, "CSRR0 " TARGET_FMT_lx " CSRR1 " TARGET_FMT_lx
- " MCSRR0 " TARGET_FMT_lx " MCSRR1 " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
- env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1]);
-
- qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx
- " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_TCR], env->spr[SPR_BOOKE_TSR],
- env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
-
- qemu_fprintf(f, " PIR " TARGET_FMT_lx " DECAR " TARGET_FMT_lx
- " IVPR " TARGET_FMT_lx " EPCR " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_PIR], env->spr[SPR_BOOKE_DECAR],
- env->spr[SPR_BOOKE_IVPR], env->spr[SPR_BOOKE_EPCR]);
-
- qemu_fprintf(f, " MCSR " TARGET_FMT_lx " SPRG8 " TARGET_FMT_lx
- " EPR " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_MCSR], env->spr[SPR_BOOKE_SPRG8],
- env->spr[SPR_BOOKE_EPR]);
-
- /* FSL-specific */
- qemu_fprintf(f, " MCAR " TARGET_FMT_lx " PID1 " TARGET_FMT_lx
- " PID2 " TARGET_FMT_lx " SVR " TARGET_FMT_lx "\n",
- env->spr[SPR_Exxx_MCAR], env->spr[SPR_BOOKE_PID1],
- env->spr[SPR_BOOKE_PID2], env->spr[SPR_E500_SVR]);
-
- /*
- * IVORs are left out as they are large and do not change often --
- * they can be read with "p $ivor0", "p $ivor1", etc.
- */
- }
-
-#if defined(TARGET_PPC64)
- if (env->flags & POWERPC_FLAG_CFAR) {
- qemu_fprintf(f, " CFAR " TARGET_FMT_lx"\n", env->cfar);
- }
-#endif
-
- if (env->spr_cb[SPR_LPCR].name) {
- qemu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
- }
-
- switch (env->mmu_model) {
- case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
- case POWERPC_MMU_SOFT_6xx:
- case POWERPC_MMU_SOFT_74xx:
-#if defined(TARGET_PPC64)
- case POWERPC_MMU_64B:
- case POWERPC_MMU_2_03:
- case POWERPC_MMU_2_06:
- case POWERPC_MMU_2_07:
- case POWERPC_MMU_3_00:
-#endif
- if (env->spr_cb[SPR_SDR1].name) { /* SDR1 Exists */
- qemu_fprintf(f, " SDR1 " TARGET_FMT_lx " ", env->spr[SPR_SDR1]);
- }
- if (env->spr_cb[SPR_PTCR].name) { /* PTCR Exists */
- qemu_fprintf(f, " PTCR " TARGET_FMT_lx " ", env->spr[SPR_PTCR]);
- }
- qemu_fprintf(f, " DAR " TARGET_FMT_lx " DSISR " TARGET_FMT_lx "\n",
- env->spr[SPR_DAR], env->spr[SPR_DSISR]);
- break;
- case POWERPC_MMU_BOOKE206:
- qemu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx
- " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],
- env->spr[SPR_BOOKE_MAS2], env->spr[SPR_BOOKE_MAS3]);
-
- qemu_fprintf(f, " MAS4 " TARGET_FMT_lx " MAS6 " TARGET_FMT_lx
- " MAS7 " TARGET_FMT_lx " PID " TARGET_FMT_lx "\n",
- env->spr[SPR_BOOKE_MAS4], env->spr[SPR_BOOKE_MAS6],
- env->spr[SPR_BOOKE_MAS7], env->spr[SPR_BOOKE_PID]);
-
- qemu_fprintf(f, "MMUCFG " TARGET_FMT_lx " TLB0CFG " TARGET_FMT_lx
- " TLB1CFG " TARGET_FMT_lx "\n",
- env->spr[SPR_MMUCFG], env->spr[SPR_BOOKE_TLB0CFG],
- env->spr[SPR_BOOKE_TLB1CFG]);
- break;
- default:
- break;
- }
-#endif
-
-#undef RGPL
-#undef RFPL
-}
-
/*****************************************************************************/
/* Opcode types */
enum {
@@ -8270,14 +8932,68 @@ void ppc_cpu_dump_statistics(CPUState *cs, int flags)
#endif
}
+static bool decode_legacy(PowerPCCPU *cpu, DisasContext *ctx, uint32_t insn)
+{
+ opc_handler_t **table, *handler;
+ uint32_t inval;
+
+ ctx->opcode = insn;
+
+ LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
+ insn, opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+ ctx->le_mode ? "little" : "big");
+
+ table = cpu->opcodes;
+ handler = table[opc1(insn)];
+ if (is_indirect_opcode(handler)) {
+ table = ind_table(handler);
+ handler = table[opc2(insn)];
+ if (is_indirect_opcode(handler)) {
+ table = ind_table(handler);
+ handler = table[opc3(insn)];
+ if (is_indirect_opcode(handler)) {
+ table = ind_table(handler);
+ handler = table[opc4(insn)];
+ }
+ }
+ }
+
+ /* Is opcode *REALLY* valid ? */
+ if (unlikely(handler->handler == &gen_invalid)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
+ "%02x - %02x - %02x - %02x (%08x) "
+ TARGET_FMT_lx "\n",
+ opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+ insn, ctx->cia);
+ return false;
+ }
+
+ if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE)
+ && Rc(insn))) {
+ inval = handler->inval2;
+ } else {
+ inval = handler->inval1;
+ }
+
+ if (unlikely((insn & inval) != 0)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
+ "%02x - %02x - %02x - %02x (%08x) "
+ TARGET_FMT_lx "\n", insn & inval,
+ opc1(insn), opc2(insn), opc3(insn), opc4(insn),
+ insn, ctx->cia);
+ return false;
+ }
+
+ handler->handler(ctx);
+ return true;
+}
+
static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPUPPCState *env = cs->env_ptr;
uint32_t hflags = ctx->base.tb->flags;
- int bound;
- ctx->exception = POWERPC_EXCP_NONE;
ctx->spr_cb = env->spr_cb;
ctx->pr = (hflags >> HFLAGS_PR) & 1;
ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7;
@@ -8316,8 +9032,12 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP;
}
- bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
- ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+ if (ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP)) {
+ ctx->base.max_insns = 1;
+ } else {
+ int bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4;
+ ctx->base.max_insns = MIN(ctx->base.max_insns, bound);
+ }
}
static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs)
@@ -8334,8 +9054,8 @@ static bool ppc_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ gen_update_nip(ctx, ctx->base.pc_next);
gen_debug_exception(ctx);
- dcbase->is_jmp = DISAS_NORETURN;
/*
* The address covered by the breakpoint must be included in
* [tb->pc, tb->pc + tb->size) in order to for it to be properly
@@ -8351,100 +9071,93 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
DisasContext *ctx = container_of(dcbase, DisasContext, base);
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = cs->env_ptr;
- opc_handler_t **table, *handler;
+ uint32_t insn;
+ bool ok;
LOG_DISAS("----------------\n");
LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n",
ctx->base.pc_next, ctx->mem_idx, (int)msr_ir);
- ctx->opcode = translator_ldl_swap(env, ctx->base.pc_next,
- need_byteswap(ctx));
-
- LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
- ctx->opcode, opc1(ctx->opcode), opc2(ctx->opcode),
- opc3(ctx->opcode), opc4(ctx->opcode),
- ctx->le_mode ? "little" : "big");
+ ctx->cia = ctx->base.pc_next;
+ insn = translator_ldl_swap(env, ctx->base.pc_next, need_byteswap(ctx));
ctx->base.pc_next += 4;
- table = cpu->opcodes;
- handler = table[opc1(ctx->opcode)];
- if (is_indirect_opcode(handler)) {
- table = ind_table(handler);
- handler = table[opc2(ctx->opcode)];
- if (is_indirect_opcode(handler)) {
- table = ind_table(handler);
- handler = table[opc3(ctx->opcode)];
- if (is_indirect_opcode(handler)) {
- table = ind_table(handler);
- handler = table[opc4(ctx->opcode)];
- }
- }
- }
- /* Is opcode *REALLY* valid ? */
- if (unlikely(handler->handler == &gen_invalid)) {
- qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
- "%02x - %02x - %02x - %02x (%08x) "
- TARGET_FMT_lx " %d\n",
- opc1(ctx->opcode), opc2(ctx->opcode),
- opc3(ctx->opcode), opc4(ctx->opcode),
- ctx->opcode, ctx->base.pc_next - 4, (int)msr_ir);
- } else {
- uint32_t inval;
- if (unlikely(handler->type & (PPC_SPE | PPC_SPE_SINGLE | PPC_SPE_DOUBLE)
- && Rc(ctx->opcode))) {
- inval = handler->inval2;
- } else {
- inval = handler->inval1;
- }
-
- if (unlikely((ctx->opcode & inval) != 0)) {
- qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
- "%02x - %02x - %02x - %02x (%08x) "
- TARGET_FMT_lx "\n", ctx->opcode & inval,
- opc1(ctx->opcode), opc2(ctx->opcode),
- opc3(ctx->opcode), opc4(ctx->opcode),
- ctx->opcode, ctx->base.pc_next - 4);
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
- ctx->base.is_jmp = DISAS_NORETURN;
- return;
- }
+ ok = decode_legacy(cpu, ctx, insn);
+ if (!ok) {
+ gen_invalid(ctx);
}
- (*(handler->handler))(ctx);
+
#if defined(DO_PPC_STATISTICS)
handler->count++;
#endif
- /* Check trace mode exceptions */
- if (unlikely(ctx->singlestep_enabled & CPU_SINGLE_STEP &&
- (ctx->base.pc_next <= 0x100 || ctx->base.pc_next > 0xF00) &&
- ctx->exception != POWERPC_SYSCALL &&
- ctx->exception != POWERPC_EXCP_TRAP &&
- ctx->exception != POWERPC_EXCP_BRANCH)) {
- uint32_t excp = gen_prep_dbgex(ctx);
- gen_exception_nip(ctx, excp, ctx->base.pc_next);
- }
-
- if (tcg_check_temp_count()) {
- qemu_log("Opcode %02x %02x %02x %02x (%08x) leaked "
- "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode),
- opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode);
- }
- ctx->base.is_jmp = ctx->exception == POWERPC_EXCP_NONE ?
- DISAS_NEXT : DISAS_NORETURN;
+ translator_loop_temp_check(&ctx->base);
}
static void ppc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ DisasJumpType is_jmp = ctx->base.is_jmp;
+ target_ulong nip = ctx->base.pc_next;
+ int sse;
+
+ if (is_jmp == DISAS_NORETURN) {
+ /* We have already exited the TB. */
+ return;
+ }
+
+ /* Honor single stepping. */
+ sse = ctx->singlestep_enabled & (CPU_SINGLE_STEP | GDBSTUB_SINGLE_STEP);
+ if (unlikely(sse)) {
+ switch (is_jmp) {
+ case DISAS_TOO_MANY:
+ case DISAS_EXIT_UPDATE:
+ case DISAS_CHAIN_UPDATE:
+ gen_update_nip(ctx, nip);
+ break;
+ case DISAS_EXIT:
+ case DISAS_CHAIN:
+ break;
+ default:
+ g_assert_not_reached();
+ }
- if (ctx->exception == POWERPC_EXCP_NONE) {
- gen_goto_tb(ctx, 0, ctx->base.pc_next);
- } else if (ctx->exception != POWERPC_EXCP_BRANCH) {
- if (unlikely(ctx->base.singlestep_enabled)) {
+ if (sse & GDBSTUB_SINGLE_STEP) {
gen_debug_exception(ctx);
+ return;
+ }
+ /* else CPU_SINGLE_STEP... */
+ if (nip <= 0x100 || nip > 0xf00) {
+ gen_exception(ctx, gen_prep_dbgex(ctx));
+ return;
}
- /* Generate the return instruction */
+ }
+
+ switch (is_jmp) {
+ case DISAS_TOO_MANY:
+ if (use_goto_tb(ctx, nip)) {
+ tcg_gen_goto_tb(0);
+ gen_update_nip(ctx, nip);
+ tcg_gen_exit_tb(ctx->base.tb, 0);
+ break;
+ }
+ /* fall through */
+ case DISAS_CHAIN_UPDATE:
+ gen_update_nip(ctx, nip);
+ /* fall through */
+ case DISAS_CHAIN:
+ tcg_gen_lookup_and_goto_ptr();
+ break;
+
+ case DISAS_EXIT_UPDATE:
+ gen_update_nip(ctx, nip);
+ /* fall through */
+ case DISAS_EXIT:
tcg_gen_exit_tb(NULL, 0);
+ break;
+
+ default:
+ g_assert_not_reached();
}
}
diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc
index b817d31260..57a7f73bba 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -139,7 +139,7 @@ static void gen_lxvwsx(DisasContext *ctx)
gen_addr_reg_index(ctx, EA);
data = tcg_temp_new_i32();
- tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, MO_TEUL);
+ tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UL));
tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
tcg_temp_free(EA);
@@ -162,7 +162,7 @@ static void gen_lxvdsx(DisasContext *ctx)
gen_addr_reg_index(ctx, EA);
data = tcg_temp_new_i64();
- tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, MO_TEQ);
+ tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_Q));
tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
tcg_temp_free(EA);
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7d6ed80f6b..3191fd0082 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -88,8 +88,8 @@ const char * const riscv_intr_names[] = {
"vs_timer",
"m_timer",
"u_external",
+ "s_external",
"vs_external",
- "h_external",
"m_external",
"reserved",
"reserved",
@@ -137,7 +137,7 @@ static void set_feature(CPURISCVState *env, int feature)
env->features |= (1ULL << feature);
}
-static void set_resetvec(CPURISCVState *env, int resetvec)
+static void set_resetvec(CPURISCVState *env, target_ulong resetvec)
{
#ifndef CONFIG_USER_ONLY
env->resetvec = resetvec;
@@ -147,7 +147,11 @@ static void set_resetvec(CPURISCVState *env, int resetvec)
static void riscv_any_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
- set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+#if defined(TARGET_RISCV32)
+ set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+#elif defined(TARGET_RISCV64)
+ set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
+#endif
set_priv_version(env, PRIV_VERSION_1_11_0);
}
@@ -202,6 +206,7 @@ static void rv32_ibex_cpu_init(Object *obj)
set_misa(env, RV32 | RVI | RVM | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ qdev_prop_set_bit(DEVICE(obj), "x-epmp", true);
}
static void rv32_imafcu_nommu_cpu_init(Object *obj)
@@ -282,7 +287,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause);
}
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval);
- qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->sbadaddr);
+ qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->stval);
if (riscv_has_ext(env, RVH)) {
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "htval ", env->htval);
qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval2 ", env->mtval2);
@@ -358,7 +363,7 @@ static void riscv_cpu_reset(DeviceState *dev)
env->pc = env->resetvec;
env->two_stage_lookup = false;
#endif
- cs->exception_index = EXCP_NONE;
+ cs->exception_index = RISCV_EXCP_NONE;
env->load_res = -1;
set_default_nan_mode(1, &env->fp_status);
}
@@ -412,6 +417,14 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
if (cpu->cfg.pmp) {
set_feature(env, RISCV_FEATURE_PMP);
+
+ /*
+ * Enhanced PMP should only be available
+ * on harts with PMP support
+ */
+ if (cpu->cfg.epmp) {
+ set_feature(env, RISCV_FEATURE_EPMP);
+ }
}
set_resetvec(env, cpu->cfg.resetvec);
@@ -554,6 +567,8 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false),
+
DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
DEFINE_PROP_END_OF_LIST(),
};
@@ -708,6 +723,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init),
#endif
};
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a33d387ba..7e879fb9ca 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -38,6 +38,7 @@
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
#define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex")
+#define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c")
#define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31")
#define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34")
#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
@@ -53,12 +54,6 @@
#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2))
#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2))
-#if defined(TARGET_RISCV32)
-#define RVXLEN RV32
-#elif defined(TARGET_RISCV64)
-#define RVXLEN RV64
-#endif
-
#define RV(x) ((target_ulong)1 << (x - 'A'))
#define RVI RV('I')
@@ -80,6 +75,7 @@
enum {
RISCV_FEATURE_MMU,
RISCV_FEATURE_PMP,
+ RISCV_FEATURE_EPMP,
RISCV_FEATURE_MISA
};
@@ -163,10 +159,8 @@ struct CPURISCVState {
target_ulong mie;
target_ulong mideleg;
- target_ulong sptbr; /* until: priv-1.9.1 */
target_ulong satp; /* since: priv-1.10.0 */
- target_ulong sbadaddr;
- target_ulong mbadaddr;
+ target_ulong stval;
target_ulong medeleg;
target_ulong stvec;
@@ -230,6 +224,7 @@ struct CPURISCVState {
/* physical memory protection */
pmp_table_t pmp_state;
+ target_ulong mseccfg;
/* machine specific rdtime callback */
uint64_t (*rdtime_fn)(uint32_t);
@@ -303,6 +298,7 @@ struct RISCVCPU {
uint16_t elen;
bool mmu;
bool pmp;
+ bool epmp;
uint64_t resetvec;
} cfg;
};
@@ -455,10 +451,13 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
*pflags = flags;
}
-int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask);
-int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask);
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask);
+RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask);
static inline void riscv_csr_write(CPURISCVState *env, int csrno,
target_ulong val)
@@ -473,13 +472,16 @@ static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
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 RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
+ int csrno);
+typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value);
+typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
+ target_ulong new_value);
+typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask);
typedef struct {
const char *name;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf4599207..52640e6856 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -153,12 +153,6 @@
/* 32-bit only */
#define CSR_MSTATUSH 0x310
-/* Legacy Counter Setup (priv v1.9.1) */
-/* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */
-#define CSR_MUCOUNTEREN 0x320
-#define CSR_MSCOUNTEREN 0x321
-#define CSR_MHCOUNTEREN 0x322
-
/* Machine Trap Handling */
#define CSR_MSCRATCH 0x340
#define CSR_MEPC 0x341
@@ -166,9 +160,6 @@
#define CSR_MTVAL 0x343
#define CSR_MIP 0x344
-/* Legacy Machine Trap Handling (priv v1.9.1) */
-#define CSR_MBADADDR 0x343
-
/* Supervisor Trap Setup */
#define CSR_SSTATUS 0x100
#define CSR_SEDELEG 0x102
@@ -184,9 +175,6 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
-/* Legacy Supervisor Trap Handling (priv v1.9.1) */
-#define CSR_SBADADDR 0x143
-
/* Supervisor Protection and Translation */
#define CSR_SPTBR 0x180
#define CSR_SATP 0x180
@@ -207,17 +195,6 @@
#define CSR_HTIMEDELTA 0x605
#define CSR_HTIMEDELTAH 0x615
-#if defined(TARGET_RISCV32)
-#define HGATP_MODE SATP32_MODE
-#define HGATP_VMID SATP32_ASID
-#define HGATP_PPN SATP32_PPN
-#endif
-#if defined(TARGET_RISCV64)
-#define HGATP_MODE SATP64_MODE
-#define HGATP_VMID SATP64_ASID
-#define HGATP_PPN SATP64_PPN
-#endif
-
/* Virtual CSRs */
#define CSR_VSSTATUS 0x200
#define CSR_VSIE 0x204
@@ -232,6 +209,9 @@
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
+/* Enhanced Physical Memory Protection (ePMP) */
+#define CSR_MSECCFG 0x390
+#define CSR_MSECCFGH 0x391
/* Physical Memory Protection */
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
@@ -354,14 +334,6 @@
#define CSR_MHPMCOUNTER30H 0xb9e
#define CSR_MHPMCOUNTER31H 0xb9f
-/* Legacy Machine Protection and Translation (priv v1.9.1) */
-#define CSR_MBASE 0x380
-#define CSR_MBOUND 0x381
-#define CSR_MIBASE 0x382
-#define CSR_MIBOUND 0x383
-#define CSR_MDBASE 0x384
-#define CSR_MDBOUND 0x385
-
/* mstatus CSR bits */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
@@ -375,10 +347,8 @@
#define MSTATUS_FS 0x00006000
#define MSTATUS_XS 0x00018000
#define MSTATUS_MPRV 0x00020000
-#define MSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */
#define MSTATUS_SUM 0x00040000 /* since: priv-1.10 */
#define MSTATUS_MXR 0x00080000
-#define MSTATUS_VM 0x1F000000 /* until: priv-1.9.1 */
#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */
#define MSTATUS_TW 0x00200000 /* since: priv-1.10 */
#define MSTATUS_TSR 0x00400000 /* since: priv-1.10 */
@@ -398,16 +368,6 @@
#define MXL_RV64 2
#define MXL_RV128 3
-#if defined(TARGET_RISCV32)
-#define MSTATUS_SD MSTATUS32_SD
-#define MISA_MXL MISA32_MXL
-#define MXL_VAL MXL_RV32
-#elif defined(TARGET_RISCV64)
-#define MSTATUS_SD MSTATUS64_SD
-#define MISA_MXL MISA64_MXL
-#define MXL_VAL MXL_RV64
-#endif
-
/* sstatus CSR bits */
#define SSTATUS_UIE 0x00000001
#define SSTATUS_SIE 0x00000002
@@ -416,19 +376,12 @@
#define SSTATUS_SPP 0x00000100
#define SSTATUS_FS 0x00006000
#define SSTATUS_XS 0x00018000
-#define SSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */
#define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */
#define SSTATUS_MXR 0x00080000
#define SSTATUS32_SD 0x80000000
#define SSTATUS64_SD 0x8000000000000000ULL
-#if defined(TARGET_RISCV32)
-#define SSTATUS_SD SSTATUS32_SD
-#elif defined(TARGET_RISCV64)
-#define SSTATUS_SD SSTATUS64_SD
-#endif
-
/* hstatus CSR bits */
#define HSTATUS_VSBE 0x00000020
#define HSTATUS_GVA 0x00000040
@@ -443,12 +396,6 @@
#define HSTATUS32_WPRI 0xFF8FF87E
#define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL
-#if defined(TARGET_RISCV32)
-#define HSTATUS_WPRI HSTATUS32_WPRI
-#elif defined(TARGET_RISCV64)
-#define HSTATUS_WPRI HSTATUS64_WPRI
-#endif
-
#define HCOUNTEREN_CY (1 << 0)
#define HCOUNTEREN_TM (1 << 1)
#define HCOUNTEREN_IR (1 << 2)
@@ -479,17 +426,6 @@
#define SATP64_ASID 0x0FFFF00000000000ULL
#define SATP64_PPN 0x00000FFFFFFFFFFFULL
-#if defined(TARGET_RISCV32)
-#define SATP_MODE SATP32_MODE
-#define SATP_ASID SATP32_ASID
-#define SATP_PPN SATP32_PPN
-#endif
-#if defined(TARGET_RISCV64)
-#define SATP_MODE SATP64_MODE
-#define SATP_ASID SATP64_ASID
-#define SATP_PPN SATP64_PPN
-#endif
-
/* VM modes (mstatus.vm) privileged ISA 1.9.1 */
#define VM_1_09_MBARE 0
#define VM_1_09_MBB 1
@@ -527,27 +463,29 @@
#define DEFAULT_RSTVEC 0x1000
/* Exception causes */
-#define EXCP_NONE -1 /* sentinel value */
-#define RISCV_EXCP_INST_ADDR_MIS 0x0
-#define RISCV_EXCP_INST_ACCESS_FAULT 0x1
-#define RISCV_EXCP_ILLEGAL_INST 0x2
-#define RISCV_EXCP_BREAKPOINT 0x3
-#define RISCV_EXCP_LOAD_ADDR_MIS 0x4
-#define RISCV_EXCP_LOAD_ACCESS_FAULT 0x5
-#define RISCV_EXCP_STORE_AMO_ADDR_MIS 0x6
-#define RISCV_EXCP_STORE_AMO_ACCESS_FAULT 0x7
-#define RISCV_EXCP_U_ECALL 0x8
-#define RISCV_EXCP_S_ECALL 0x9
-#define RISCV_EXCP_VS_ECALL 0xa
-#define RISCV_EXCP_M_ECALL 0xb
-#define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */
-#define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */
-#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */
-#define RISCV_EXCP_SEMIHOST 0x10
-#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14
-#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15
-#define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16
-#define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17
+typedef enum RISCVException {
+ RISCV_EXCP_NONE = -1, /* sentinel value */
+ RISCV_EXCP_INST_ADDR_MIS = 0x0,
+ RISCV_EXCP_INST_ACCESS_FAULT = 0x1,
+ RISCV_EXCP_ILLEGAL_INST = 0x2,
+ RISCV_EXCP_BREAKPOINT = 0x3,
+ RISCV_EXCP_LOAD_ADDR_MIS = 0x4,
+ RISCV_EXCP_LOAD_ACCESS_FAULT = 0x5,
+ RISCV_EXCP_STORE_AMO_ADDR_MIS = 0x6,
+ RISCV_EXCP_STORE_AMO_ACCESS_FAULT = 0x7,
+ RISCV_EXCP_U_ECALL = 0x8,
+ RISCV_EXCP_S_ECALL = 0x9,
+ RISCV_EXCP_VS_ECALL = 0xa,
+ RISCV_EXCP_M_ECALL = 0xb,
+ RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */
+ RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */
+ RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */
+ RISCV_EXCP_SEMIHOST = 0x10,
+ RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14,
+ RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15,
+ RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16,
+ RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17,
+} RISCVException;
#define RISCV_EXCP_INT_FLAG 0x80000000
#define RISCV_EXCP_INT_MASK 0x7fffffff
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 21c54ef561..968cb8046f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -72,7 +72,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
if (irqs) {
return ctz64(irqs); /* since non-zero */
} else {
- return EXCP_NONE; /* indicates no pending interrupt */
+ return RISCV_EXCP_NONE; /* indicates no pending interrupt */
}
}
#endif
@@ -136,8 +136,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
env->vscause = env->scause;
env->scause = env->scause_hs;
- env->vstval = env->sbadaddr;
- env->sbadaddr = env->stval_hs;
+ env->vstval = env->stval;
+ env->stval = env->stval_hs;
env->vsatp = env->satp;
env->satp = env->satp_hs;
@@ -159,8 +159,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
env->scause_hs = env->scause;
env->scause = env->vscause;
- env->stval_hs = env->sbadaddr;
- env->sbadaddr = env->vstval;
+ env->stval_hs = env->stval;
+ env->stval = env->vstval;
env->satp_hs = env->satp;
env->satp = env->vsatp;
@@ -342,12 +342,14 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot,
* @first_stage: Are we in first stage translation?
* Second stage is used for hypervisor guest translation
* @two_stage: Are we going to perform two stage translation
+ * @is_debug: Is this access from a debugger or the monitor?
*/
static int get_physical_address(CPURISCVState *env, hwaddr *physical,
int *prot, target_ulong addr,
target_ulong *fault_pte_addr,
int access_type, int mmu_idx,
- bool first_stage, bool two_stage)
+ bool first_stage, bool two_stage,
+ bool is_debug)
{
/* NOTE: the env->pc value visible here will not be
* correct, but the value visible to the exception handler
@@ -403,20 +405,35 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
if (first_stage == true) {
if (use_background) {
- base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT;
- vm = get_field(env->vsatp, SATP_MODE);
+ if (riscv_cpu_is_32bit(env)) {
+ base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP64_MODE);
+ }
} else {
- base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
- vm = get_field(env->satp, SATP_MODE);
+ if (riscv_cpu_is_32bit(env)) {
+ base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP64_MODE);
+ }
}
widened = 0;
} else {
- base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
- vm = get_field(env->hgatp, HGATP_MODE);
+ if (riscv_cpu_is_32bit(env)) {
+ base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, SATP64_MODE);
+ }
widened = 2;
}
/* status.SUM will be ignored if execute on background */
- sum = get_field(env->mstatus, MSTATUS_SUM) || use_background;
+ sum = get_field(env->mstatus, MSTATUS_SUM) || use_background || is_debug;
switch (vm) {
case VM_1_10_SV32:
levels = 2; ptidxbits = 10; ptesize = 4; break;
@@ -475,7 +492,8 @@ restart:
/* Do the second stage translation on the base PTE address. */
int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
base, NULL, MMU_DATA_LOAD,
- mmu_idx, false, true);
+ mmu_idx, false, true,
+ is_debug);
if (vbase_ret != TRANSLATE_SUCCESS) {
if (fault_pte_addr) {
@@ -615,16 +633,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
bool first_stage, bool two_stage)
{
CPUState *cs = env_cpu(env);
- int page_fault_exceptions;
+ int page_fault_exceptions, vm;
+ uint64_t stap_mode;
+
+ if (riscv_cpu_is_32bit(env)) {
+ stap_mode = SATP32_MODE;
+ } else {
+ stap_mode = SATP64_MODE;
+ }
+
if (first_stage) {
- page_fault_exceptions =
- get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
- !pmp_violation;
+ vm = get_field(env->satp, stap_mode);
} else {
- page_fault_exceptions =
- get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
- !pmp_violation;
+ vm = get_field(env->hgatp, stap_mode);
}
+
+ page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation;
+
switch (access_type) {
case MMU_INST_FETCH:
if (riscv_cpu_virt_enabled(env) && !first_stage) {
@@ -666,13 +691,13 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
int mmu_idx = cpu_mmu_index(&cpu->env, false);
if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx,
- true, riscv_cpu_virt_enabled(env))) {
+ true, riscv_cpu_virt_enabled(env), true)) {
return -1;
}
if (riscv_cpu_virt_enabled(env)) {
if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL,
- 0, mmu_idx, false, true)) {
+ 0, mmu_idx, false, true, true)) {
return -1;
}
}
@@ -691,8 +716,10 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
if (access_type == MMU_DATA_STORE) {
cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
- } else {
+ } else if (access_type == MMU_DATA_LOAD) {
cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
+ } else {
+ cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
}
env->badaddr = addr;
@@ -768,7 +795,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
/* Two stage lookup */
ret = get_physical_address(env, &pa, &prot, address,
&env->guest_phys_fault_addr, access_type,
- mmu_idx, true, true);
+ mmu_idx, true, true, false);
/*
* A G-stage exception may be triggered during two state lookup.
@@ -790,7 +817,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
im_address = pa;
ret = get_physical_address(env, &pa, &prot2, im_address, NULL,
- access_type, mmu_idx, false, true);
+ access_type, mmu_idx, false, true,
+ false);
qemu_log_mask(CPU_LOG_MMU,
"%s 2nd-stage address=%" VADDR_PRIx " ret %d physical "
@@ -825,7 +853,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
} else {
/* Single stage lookup */
ret = get_physical_address(env, &pa, &prot, address, NULL,
- access_type, mmu_idx, true, false);
+ access_type, mmu_idx, true, false, false);
qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " ret %d physical "
@@ -1023,7 +1051,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mstatus = s;
env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
env->sepc = env->pc;
- env->sbadaddr = tval;
+ env->stval = tval;
env->htval = htval;
env->pc = (env->stvec >> 2 << 2) +
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
@@ -1054,7 +1082,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mstatus = s;
env->mcause = cause | ~(((target_ulong)-1) >> async);
env->mepc = env->pc;
- env->mbadaddr = tval;
+ env->mtval = tval;
env->mtval2 = mtval2;
env->pc = (env->mtvec >> 2 << 2) +
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
@@ -1069,5 +1097,5 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->two_stage_lookup = false;
#endif
- cs->exception_index = EXCP_NONE; /* mark handled to qemu */
+ cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */
}
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index d2585395bf..fe5628fea6 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -35,29 +35,29 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
}
/* Predicates */
-static int fs(CPURISCVState *env, int csrno)
+static RISCVException fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
/* loose check condition for fcsr in vector extension */
if ((csrno == CSR_FCSR) && (env->misa & RVV)) {
- return 0;
+ return RISCV_EXCP_NONE;
}
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int vs(CPURISCVState *env, int csrno)
+static RISCVException vs(CPURISCVState *env, int csrno)
{
if (env->misa & RVV) {
- return 0;
+ return RISCV_EXCP_NONE;
}
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
-static int ctr(CPURISCVState *env, int csrno)
+static RISCVException ctr(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
CPUState *cs = env_cpu(env);
@@ -65,7 +65,7 @@ static int ctr(CPURISCVState *env, int csrno)
if (!cpu->cfg.ext_counters) {
/* The Counters extensions is not enabled */
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
if (riscv_cpu_virt_enabled(env)) {
@@ -73,25 +73,25 @@ static int ctr(CPURISCVState *env, int csrno)
case CSR_CYCLE:
if (!get_field(env->hcounteren, HCOUNTEREN_CY) &&
get_field(env->mcounteren, HCOUNTEREN_CY)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_TIME:
if (!get_field(env->hcounteren, HCOUNTEREN_TM) &&
get_field(env->mcounteren, HCOUNTEREN_TM)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_INSTRET:
if (!get_field(env->hcounteren, HCOUNTEREN_IR) &&
get_field(env->mcounteren, HCOUNTEREN_IR)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) &&
get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
}
@@ -100,148 +100,174 @@ static int ctr(CPURISCVState *env, int csrno)
case CSR_CYCLEH:
if (!get_field(env->hcounteren, HCOUNTEREN_CY) &&
get_field(env->mcounteren, HCOUNTEREN_CY)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_TIMEH:
if (!get_field(env->hcounteren, HCOUNTEREN_TM) &&
get_field(env->mcounteren, HCOUNTEREN_TM)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_INSTRETH:
if (!get_field(env->hcounteren, HCOUNTEREN_IR) &&
get_field(env->mcounteren, HCOUNTEREN_IR)) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) &&
get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
}
}
}
#endif
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int ctr32(CPURISCVState *env, int csrno)
+static RISCVException ctr32(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_is_32bit(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
return ctr(env, csrno);
}
#if !defined(CONFIG_USER_ONLY)
-static int any(CPURISCVState *env, int csrno)
+static RISCVException any(CPURISCVState *env, int csrno)
{
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int any32(CPURISCVState *env, int csrno)
+static RISCVException any32(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_is_32bit(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
return any(env, csrno);
}
-static int smode(CPURISCVState *env, int csrno)
+static RISCVException smode(CPURISCVState *env, int csrno)
{
- return -!riscv_has_ext(env, RVS);
+ if (riscv_has_ext(env, RVS)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
}
-static int hmode(CPURISCVState *env, int csrno)
+static RISCVException hmode(CPURISCVState *env, int csrno)
{
if (riscv_has_ext(env, RVS) &&
riscv_has_ext(env, RVH)) {
/* Hypervisor extension is supported */
if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
env->priv == PRV_M) {
- return 0;
+ return RISCV_EXCP_NONE;
} else {
- return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
}
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
-static int hmode32(CPURISCVState *env, int csrno)
+static RISCVException hmode32(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_is_32bit(env)) {
- return 0;
+ if (riscv_cpu_virt_enabled(env)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
}
return hmode(env, csrno);
}
-static int pmp(CPURISCVState *env, int csrno)
+static RISCVException pmp(CPURISCVState *env, int csrno)
+{
+ if (riscv_feature(env, RISCV_FEATURE_PMP)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException epmp(CPURISCVState *env, int csrno)
{
- return -!riscv_feature(env, RISCV_FEATURE_PMP);
+ if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
/* User Floating-Point CSRs */
-static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_fflags(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
*val = riscv_cpu_get_fflags(env);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_fflags(CPURISCVState *env, int csrno,
+ target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
env->mstatus |= MSTATUS_FS;
#endif
riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_frm(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
*val = env->frm;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_frm(CPURISCVState *env, int csrno,
+ target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
env->mstatus |= MSTATUS_FS;
#endif
env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_fcsr(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
*val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT)
@@ -250,14 +276,15 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
*val |= (env->vxrm << FSR_VXRM_SHIFT)
| (env->vxsat << FSR_VXSAT_SHIFT);
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_fcsr(CPURISCVState *env, int csrno,
+ target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
env->mstatus |= MSTATUS_FS;
#endif
@@ -267,59 +294,68 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT;
}
riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vtype(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vtype(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vtype;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vl(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vl(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vl;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vxrm(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vxrm(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vxrm;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vxrm(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vxrm(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vxrm = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vxsat(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vxsat(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vxsat;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vxsat(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vxsat(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vxsat = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vstart(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vstart(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vstart;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vstart(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vstart(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vstart = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* User Timers and Counters */
-static int read_instret(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_instret(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (icount_enabled()) {
@@ -330,10 +366,11 @@ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val)
#else
*val = cpu_get_host_ticks();
#endif
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_instreth(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (icount_enabled()) {
@@ -344,46 +381,50 @@ static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val)
#else
*val = cpu_get_host_ticks() >> 32;
#endif
- return 0;
+ return RISCV_EXCP_NONE;
}
#if defined(CONFIG_USER_ONLY)
-static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_time(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = cpu_get_host_ticks();
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_timeh(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = cpu_get_host_ticks() >> 32;
- return 0;
+ return RISCV_EXCP_NONE;
}
#else /* CONFIG_USER_ONLY */
-static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_time(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
*val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_timeh(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
*val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Machine constants */
@@ -418,7 +459,7 @@ static const target_ulong delegable_excps =
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT));
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;
+ SSTATUS_SUM | SSTATUS_MXR;
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
static const target_ulong hip_writable_mask = MIP_VSSIP;
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
@@ -437,22 +478,26 @@ static const char valid_vm_1_10_64[16] = {
};
/* Machine Information Registers */
-static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_zero(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
- return *val = 0;
+ *val = 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mhartid(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mhartid;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Machine Trap Setup */
-static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mstatus;
- return 0;
+ return RISCV_EXCP_NONE;
}
static int validate_vm(CPURISCVState *env, target_ulong vm)
@@ -464,7 +509,8 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
}
}
-static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
{
uint64_t mstatus = env->mstatus;
uint64_t mask = 0;
@@ -492,19 +538,25 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
((mstatus & MSTATUS_XS) == MSTATUS_XS);
- mstatus = set_field(mstatus, MSTATUS_SD, dirty);
+ if (riscv_cpu_is_32bit(env)) {
+ mstatus = set_field(mstatus, MSTATUS32_SD, dirty);
+ } else {
+ mstatus = set_field(mstatus, MSTATUS64_SD, dirty);
+ }
env->mstatus = mstatus;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mstatush(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mstatus >> 32;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mstatush(CPURISCVState *env, int csrno,
+ target_ulong val)
{
uint64_t valh = (uint64_t)val << 32;
uint64_t mask = MSTATUS_MPV | MSTATUS_GVA;
@@ -515,26 +567,28 @@ static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val)
env->mstatus = (env->mstatus & ~mask) | (valh & mask);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_misa(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_misa(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->misa;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_misa(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_misa(CPURISCVState *env, int csrno,
+ target_ulong val)
{
if (!riscv_feature(env, RISCV_FEATURE_MISA)) {
/* drop write to misa */
- return 0;
+ return RISCV_EXCP_NONE;
}
/* 'I' or 'E' must be present */
if (!(val & (RVI | RVE))) {
/* It is not, drop write to misa */
- return 0;
+ return RISCV_EXCP_NONE;
}
/* 'E' excludes all other extensions */
@@ -542,7 +596,7 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val)
/* when we support 'E' we can do "val = RVE;" however
* for now we just drop writes if 'E' is present.
*/
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Mask extensions that are not supported by this hart */
@@ -564,7 +618,11 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val)
}
/* misa.MXL writes are not supported by QEMU */
- val = (env->misa & MISA_MXL) | (val & ~MISA_MXL);
+ if (riscv_cpu_is_32bit(env)) {
+ val = (env->misa & MISA32_MXL) | (val & ~MISA32_MXL);
+ } else {
+ val = (env->misa & MISA64_MXL) | (val & ~MISA64_MXL);
+ }
/* flush translation cache */
if (val != env->misa) {
@@ -573,55 +631,63 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val)
env->misa = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_medeleg(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_medeleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->medeleg;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_medeleg(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_medeleg(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->medeleg = (env->medeleg & ~delegable_excps) | (val & delegable_excps);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mideleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mideleg;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mideleg(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
if (riscv_has_ext(env, RVH)) {
env->mideleg |= VS_MODE_INTERRUPTS;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mie(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mie;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mie(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mie = (env->mie & ~all_ints) | (val & all_ints);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mtvec(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mtvec;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mtvec(CPURISCVState *env, int csrno,
+ target_ulong val)
{
/* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
if ((val & 3) < 2) {
@@ -629,92 +695,83 @@ static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val)
} else {
qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n");
}
- return 0;
-}
-
-static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val)
-{
- *val = env->mcounteren;
- return 0;
-}
-
-static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val)
-{
- env->mcounteren = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
-static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mcounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
- if (env->priv_ver < PRIV_VERSION_1_11_0) {
- return -RISCV_EXCP_ILLEGAL_INST;
- }
*val = env->mcounteren;
- return 0;
+ return RISCV_EXCP_NONE;
}
-/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */
-static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mcounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
{
- if (env->priv_ver < PRIV_VERSION_1_11_0) {
- return -RISCV_EXCP_ILLEGAL_INST;
- }
env->mcounteren = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Machine Trap Handling */
-static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mscratch;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mscratch(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mscratch = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mepc(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mepc;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mepc(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mepc(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mepc = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mcause(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mcause(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mcause;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mcause(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mcause(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mcause = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mbadaddr(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mtval(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
- *val = env->mbadaddr;
- return 0;
+ *val = env->mtval;
+ return RISCV_EXCP_NONE;
}
-static int write_mbadaddr(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mtval(CPURISCVState *env, int csrno,
+ target_ulong val)
{
- env->mbadaddr = val;
- return 0;
+ env->mtval = val;
+ return RISCV_EXCP_NONE;
}
-static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static RISCVException rmw_mip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
RISCVCPU *cpu = env_archcpu(env);
/* Allow software control of delegable interrupts not claimed by hardware */
@@ -731,42 +788,54 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
*ret_value = old_mip;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Supervisor Trap Setup */
-static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_sstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
target_ulong mask = (sstatus_v1_10_mask);
+
+ if (riscv_cpu_is_32bit(env)) {
+ mask |= SSTATUS32_SD;
+ } else {
+ mask |= SSTATUS64_SD;
+ }
+
*val = env->mstatus & mask;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_sstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
{
target_ulong mask = (sstatus_v1_10_mask);
target_ulong newval = (env->mstatus & ~mask) | (val & mask);
return write_mstatus(env, CSR_MSTATUS, newval);
}
-static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vsie(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
/* Shift the VS bits to their S bit location in vsie */
*val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_sie(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
if (riscv_cpu_virt_enabled(env)) {
read_vsie(env, CSR_VSIE, val);
} else {
*val = env->mie & env->mideleg;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vsie(CPURISCVState *env, int csrno,
+ target_ulong val)
{
/* Shift the S bits to their VS bit location in mie */
target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
@@ -784,16 +853,18 @@ static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
write_mie(env, CSR_MIE, newval);
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_stvec(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->stvec;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_stvec(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_stvec(CPURISCVState *env, int csrno,
+ target_ulong val)
{
/* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
if ((val & 3) < 2) {
@@ -801,72 +872,83 @@ static int write_stvec(CPURISCVState *env, int csrno, target_ulong val)
} else {
qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n");
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_scounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->scounteren;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_scounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->scounteren = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Supervisor Trap Handling */
-static int read_sscratch(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_sscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->sscratch;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_sscratch(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_sscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->sscratch = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_sepc(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_sepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->sepc;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_sepc(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_sepc(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->sepc = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_scause(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_scause(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->scause;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_scause(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_scause(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->scause = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_sbadaddr(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_stval(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
- *val = env->sbadaddr;
- return 0;
+ *val = env->stval;
+ return RISCV_EXCP_NONE;
}
-static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_stval(CPURISCVState *env, int csrno,
+ target_ulong val)
{
- env->sbadaddr = val;
- return 0;
+ env->stval = val;
+ return RISCV_EXCP_NONE;
}
-static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static RISCVException rmw_vsip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
/* Shift the S bits to their VS bit location in mip */
int ret = rmw_mip(env, 0, ret_value, new_value << 1,
@@ -877,8 +959,9 @@ static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
return ret;
}
-static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static RISCVException rmw_sip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
int ret;
@@ -894,44 +977,58 @@ static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
}
/* Supervisor Protection and Translation */
-static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_satp(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
*val = 0;
- return 0;
+ return RISCV_EXCP_NONE;
}
if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
} else {
*val = env->satp;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_satp(CPURISCVState *env, int csrno,
+ target_ulong val)
{
+ int vm, mask, asid;
+
if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
- return 0;
+ return RISCV_EXCP_NONE;
+ }
+
+ if (riscv_cpu_is_32bit(env)) {
+ vm = validate_vm(env, get_field(val, SATP32_MODE));
+ mask = (val ^ env->satp) & (SATP32_MODE | SATP32_ASID | SATP32_PPN);
+ asid = (val ^ env->satp) & SATP32_ASID;
+ } else {
+ vm = validate_vm(env, get_field(val, SATP64_MODE));
+ mask = (val ^ env->satp) & (SATP64_MODE | SATP64_ASID | SATP64_PPN);
+ asid = (val ^ env->satp) & SATP64_ASID;
}
- if (validate_vm(env, get_field(val, SATP_MODE)) &&
- ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
- {
+
+ if (vm && mask) {
if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
} else {
- if ((val ^ env->satp) & SATP_ASID) {
+ if (asid) {
tlb_flush(env_cpu(env));
}
env->satp = val;
}
}
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Hypervisor Extensions */
-static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->hstatus;
if (!riscv_cpu_is_32bit(env)) {
@@ -940,10 +1037,11 @@ static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
}
/* We only support little endian */
*val = set_field(*val, HSTATUS_VSBE, 0);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->hstatus = val;
if (!riscv_cpu_is_32bit(env) && get_field(val, HSTATUS_VSXL) != 2) {
@@ -952,35 +1050,40 @@ static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val)
if (get_field(val, HSTATUS_VSBE) != 0) {
qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests.");
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hedeleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->hedeleg;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hedeleg(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->hedeleg = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hideleg(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->hideleg;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hideleg(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->hideleg = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static RISCVException rmw_hvip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
int ret = rmw_mip(env, 0, ret_value, new_value,
write_mask & hvip_writable_mask);
@@ -990,8 +1093,9 @@ static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
return ret;
}
-static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+static RISCVException rmw_hip(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
int ret = rmw_mip(env, 0, ret_value, new_value,
write_mask & hip_writable_mask);
@@ -1001,103 +1105,119 @@ static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
return ret;
}
-static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hie(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mie & VS_MODE_INTERRUPTS;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hie(CPURISCVState *env, int csrno,
+ target_ulong val)
{
target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
return write_mie(env, CSR_MIE, newval);
}
-static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hcounteren(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->hcounteren;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hcounteren(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->hcounteren = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_hgeie(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hgeie(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hgeie(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hgeie(CPURISCVState *env, int csrno,
+ target_ulong val)
{
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_htval(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_htval(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->htval;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_htval(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_htval(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->htval = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_htinst(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->htinst;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_htinst(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_htinst(CPURISCVState *env, int csrno,
+ target_ulong val)
{
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_hgeip(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hgeip(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hgeip(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hgeip(CPURISCVState *env, int csrno,
+ target_ulong val)
{
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_hgatp(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->hgatp;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_hgatp(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->hgatp = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_htimedelta(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
*val = env->htimedelta;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_htimedelta(CPURISCVState *env, int csrno,
+ target_ulong val)
{
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
if (riscv_cpu_is_32bit(env)) {
@@ -1105,162 +1225,199 @@ static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val)
} else {
env->htimedelta = val;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_htimedeltah(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
*val = env->htimedelta >> 32;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_htimedeltah(CPURISCVState *env, int csrno,
+ target_ulong val)
{
if (!env->rdtime_fn) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val);
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Virtual CSR Registers */
-static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vsstatus(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vsstatus;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vsstatus(CPURISCVState *env, int csrno,
+ target_ulong val)
{
uint64_t mask = (target_ulong)-1;
env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val;
- return 0;
+ return RISCV_EXCP_NONE;
}
static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val)
{
*val = env->vstvec;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vstvec(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vstvec = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vsscratch(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vsscratch;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vsscratch = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vsepc(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vsepc;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vsepc(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vsepc = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vscause(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vscause;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vscause(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vscause(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vscause = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vstval(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vstval;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vstval(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vstval(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vstval = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_vsatp(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->vsatp;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_vsatp(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->vsatp = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mtval2(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mtval2(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mtval2;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mtval2(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mtval2(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mtval2 = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_mtinst(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mtinst(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = env->mtinst;
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_mtinst(CPURISCVState *env, int csrno,
+ target_ulong val)
{
env->mtinst = val;
- return 0;
+ return RISCV_EXCP_NONE;
}
/* Physical Memory Protection */
-static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_mseccfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = mseccfg_csr_read(env);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mseccfg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ mseccfg_csr_write(env, val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_pmpcfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_pmpcfg(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_pmpcfg(CPURISCVState *env, int csrno,
+ target_ulong val)
{
pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int read_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val)
+static RISCVException read_pmpaddr(CPURISCVState *env, int csrno,
+ target_ulong *val)
{
*val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0);
- return 0;
+ return RISCV_EXCP_NONE;
}
-static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val)
+static RISCVException write_pmpaddr(CPURISCVState *env, int csrno,
+ target_ulong val)
{
pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val);
- return 0;
+ return RISCV_EXCP_NONE;
}
#endif
@@ -1274,10 +1431,11 @@ static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val)
* 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)
+RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
{
- int ret;
+ RISCVException ret;
target_ulong old_value;
RISCVCPU *cpu = env_archcpu(env);
@@ -1299,21 +1457,21 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
if ((write_mask && read_only) ||
(!env->debugger && (effective_priv < get_field(csrno, 0x300)))) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
#endif
/* ensure the CSR extension is enabled. */
if (!cpu->cfg.ext_icsr) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
/* check predicate */
if (!csr_ops[csrno].predicate) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
ret = csr_ops[csrno].predicate(env, csrno);
- if (ret < 0) {
+ if (ret != RISCV_EXCP_NONE) {
return ret;
}
@@ -1324,12 +1482,11 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
/* if no accessor exists then return failure */
if (!csr_ops[csrno].read) {
- return -RISCV_EXCP_ILLEGAL_INST;
+ return RISCV_EXCP_ILLEGAL_INST;
}
-
/* read old value */
ret = csr_ops[csrno].read(env, csrno, &old_value);
- if (ret < 0) {
+ if (ret != RISCV_EXCP_NONE) {
return ret;
}
@@ -1338,7 +1495,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
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) {
+ if (ret != RISCV_EXCP_NONE) {
return ret;
}
}
@@ -1349,17 +1506,19 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
*ret_value = old_value;
}
- return 0;
+ return RISCV_EXCP_NONE;
}
/*
* Debugger support. If not in user mode, set env->debugger before the
* riscv_csrrw call and clear it after the call.
*/
-int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
+RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask)
{
- int ret;
+ RISCVException ret;
#if !defined(CONFIG_USER_ONLY)
env->debugger = true;
#endif
@@ -1419,13 +1578,11 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush },
- [CSR_MSCOUNTEREN] = { "msounteren", any, read_mscounteren, write_mscounteren },
-
/* Machine Trap Handling */
[CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch },
[CSR_MEPC] = { "mepc", any, read_mepc, write_mepc },
[CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause },
- [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr },
+ [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval },
[CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip },
/* Supervisor Trap Setup */
@@ -1438,7 +1595,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch },
[CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc },
[CSR_SCAUSE] = { "scause", smode, read_scause, write_scause },
- [CSR_SBADADDR] = { "sbadaddr", smode, read_sbadaddr, write_sbadaddr },
+ [CSR_STVAL] = { "stval", smode, read_stval, write_stval },
[CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip },
/* Supervisor Protection and Translation */
@@ -1473,6 +1630,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst },
/* Physical Memory Protection */
+ [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg },
[CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg },
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index 7c4ab92ecb..8700516a14 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -223,13 +223,13 @@ target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
return (int32_t)float32_to_uint32(frs1, &env->fp_status);
}
-uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
+target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
{
float32 frs1 = check_nanbox_s(rs1);
return float32_to_int64(frs1, &env->fp_status);
}
-uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
+target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
{
float32 frs1 = check_nanbox_s(rs1);
return float32_to_uint64(frs1, &env->fp_status);
@@ -245,12 +245,12 @@ uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1)
return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status));
}
-uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1)
+uint64_t helper_fcvt_s_l(CPURISCVState *env, target_ulong rs1)
{
return nanbox_s(int64_to_float32(rs1, &env->fp_status));
}
-uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1)
+uint64_t helper_fcvt_s_lu(CPURISCVState *env, target_ulong rs1)
{
return nanbox_s(uint64_to_float32(rs1, &env->fp_status));
}
@@ -332,12 +332,12 @@ target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
return (int32_t)float64_to_uint32(frs1, &env->fp_status);
}
-uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
+target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
{
return float64_to_int64(frs1, &env->fp_status);
}
-uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
+target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
{
return float64_to_uint64(frs1, &env->fp_status);
}
@@ -352,12 +352,12 @@ uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1)
return uint32_to_float64((uint32_t)rs1, &env->fp_status);
}
-uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1)
+uint64_t helper_fcvt_d_l(CPURISCVState *env, target_ulong rs1)
{
return int64_to_float64(rs1, &env->fp_status);
}
-uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1)
+uint64_t helper_fcvt_d_lu(CPURISCVState *env, target_ulong rs1)
{
return uint64_to_float64(rs1, &env->fp_status);
}
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 5f96b7ea2a..ca78682cf4 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -71,7 +71,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
*/
result = riscv_csrrw_debug(env, n - 32, &val,
0, 0);
- if (result == 0) {
+ if (result == RISCV_EXCP_NONE) {
return gdb_get_regl(buf, val);
}
}
@@ -94,7 +94,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
*/
result = riscv_csrrw_debug(env, n - 32, NULL,
val, -1);
- if (result == 0) {
+ if (result == RISCV_EXCP_NONE) {
return sizeof(target_ulong);
}
}
@@ -108,7 +108,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
int result;
result = riscv_csrrw_debug(env, n, &val, 0, 0);
- if (result == 0) {
+ if (result == RISCV_EXCP_NONE) {
return gdb_get_regl(buf, val);
}
}
@@ -122,7 +122,7 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
int result;
result = riscv_csrrw_debug(env, n, NULL, val, -1);
- if (result == 0) {
+ if (result == RISCV_EXCP_NONE) {
return sizeof(target_ulong);
}
}
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index e3f3f41e89..c7267593c3 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -27,12 +27,12 @@ DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
DEF_HELPER_FLAGS_2(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64)
DEF_HELPER_FLAGS_2(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, tl, env, i64)
DEF_HELPER_FLAGS_2(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl)
-DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_1(fclass_s, TCG_CALL_NO_RWG_SE, tl, i64)
/* Floating Point - Double Precision */
@@ -50,12 +50,12 @@ DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
DEF_HELPER_FLAGS_2(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64)
DEF_HELPER_FLAGS_2(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, tl, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, tl, env, i64)
DEF_HELPER_FLAGS_2(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl)
-DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64)
-DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64)
+DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl)
+DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64)
/* Special functions */
@@ -241,7 +241,6 @@ DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32)
DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32)
DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32)
DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32)
-#ifdef TARGET_RISCV64
DEF_HELPER_6(vamoswapw_v_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamoswapd_v_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamoaddw_v_d, void, ptr, ptr, tl, ptr, env, i32)
@@ -260,7 +259,6 @@ DEF_HELPER_6(vamominuw_v_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamominud_v_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamomaxuw_v_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamomaxud_v_d, void, ptr, ptr, tl, ptr, env, i32)
-#endif
DEF_HELPER_6(vamoswapw_v_w, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamoaddw_v_w, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vamoxorw_v_w, void, ptr, ptr, tl, ptr, env, i32)
diff --git a/target/riscv/insn16-32.decode b/target/riscv/insn16-32.decode
deleted file mode 100644
index 0819b17028..0000000000
--- a/target/riscv/insn16-32.decode
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# RISC-V translation routines for the RVXI Base Integer Instruction Set.
-#
-# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
-# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
-#
-# 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/>.
-
-# *** RV32C Standard Extension (Quadrant 0) ***
-flw 011 ... ... .. ... 00 @cl_w
-fsw 111 ... ... .. ... 00 @cs_w
-
-# *** RV32C Standard Extension (Quadrant 1) ***
-jal 001 ........... 01 @cj rd=1 # C.JAL
-
-# *** RV32C Standard Extension (Quadrant 2) ***
-flw 011 . ..... ..... 10 @c_lwsp
-fsw 111 . ..... ..... 10 @c_swsp
diff --git a/target/riscv/insn16-64.decode b/target/riscv/insn16-64.decode
deleted file mode 100644
index 672e1e916f..0000000000
--- a/target/riscv/insn16-64.decode
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# RISC-V translation routines for the RVXI Base Integer Instruction Set.
-#
-# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
-# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
-#
-# 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/>.
-
-# *** RV64C Standard Extension (Quadrant 0) ***
-ld 011 ... ... .. ... 00 @cl_d
-sd 111 ... ... .. ... 00 @cs_d
-
-# *** RV64C Standard Extension (Quadrant 1) ***
-{
- illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0
- addiw 001 . ..... ..... 01 @ci
-}
-subw 100 1 11 ... 00 ... 01 @cs_2
-addw 100 1 11 ... 01 ... 01 @cs_2
-
-# *** RV64C Standard Extension (Quadrant 2) ***
-{
- illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0
- ld 011 . ..... ..... 10 @c_ldsp
-}
-sd 111 . ..... ..... 10 @c_sdsp
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
index 1cb93876fe..2e9212663c 100644
--- a/target/riscv/insn16.decode
+++ b/target/riscv/insn16.decode
@@ -92,6 +92,16 @@ lw 010 ... ... .. ... 00 @cl_w
fsd 101 ... ... .. ... 00 @cs_d
sw 110 ... ... .. ... 00 @cs_w
+# *** RV32C and RV64C specific Standard Extension (Quadrant 0) ***
+{
+ ld 011 ... ... .. ... 00 @cl_d
+ flw 011 ... ... .. ... 00 @cl_w
+}
+{
+ sd 111 ... ... .. ... 00 @cs_d
+ fsw 111 ... ... .. ... 00 @cs_w
+}
+
# *** RV32/64C Standard Extension (Quadrant 1) ***
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
@@ -111,6 +121,15 @@ jal 101 ........... 01 @cj rd=0 # C.J
beq 110 ... ... ..... 01 @cb_z
bne 111 ... ... ..... 01 @cb_z
+# *** RV64C and RV32C specific Standard Extension (Quadrant 1) ***
+{
+ c64_illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0
+ addiw 001 . ..... ..... 01 @ci
+ jal 001 ........... 01 @cj rd=1 # C.JAL
+}
+subw 100 1 11 ... 00 ... 01 @cs_2
+addw 100 1 11 ... 01 ... 01 @cs_2
+
# *** RV32/64C Standard Extension (Quadrant 2) ***
slli 000 . ..... ..... 10 @c_shift2
fld 001 . ..... ..... 10 @c_ldsp
@@ -130,3 +149,14 @@ fld 001 . ..... ..... 10 @c_ldsp
}
fsd 101 ...... ..... 10 @c_sdsp
sw 110 . ..... ..... 10 @c_swsp
+
+# *** RV32C and RV64C specific Standard Extension (Quadrant 2) ***
+{
+ c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0
+ ld 011 . ..... ..... 10 @c_ldsp
+ flw 011 . ..... ..... 10 @c_lwsp
+}
+{
+ sd 111 . ..... ..... 10 @c_sdsp
+ fsw 111 . ..... ..... 10 @c_swsp
+}
diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode
deleted file mode 100644
index 8157dee8b7..0000000000
--- a/target/riscv/insn32-64.decode
+++ /dev/null
@@ -1,88 +0,0 @@
-#
-# RISC-V translation routines for the RV Instruction Set.
-#
-# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de
-# Bastian Koppelmann, kbastian@mail.uni-paderborn.de
-#
-# 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/>.
-
-# This is concatenated with insn32.decode for risc64 targets.
-# Most of the fields and formats are there.
-
-%sh5 20:5
-
-@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
-
-# *** RV64I Base Instruction Set (in addition to RV32I) ***
-lwu ............ ..... 110 ..... 0000011 @i
-ld ............ ..... 011 ..... 0000011 @i
-sd ....... ..... ..... 011 ..... 0100011 @s
-addiw ............ ..... 000 ..... 0011011 @i
-slliw 0000000 ..... ..... 001 ..... 0011011 @sh5
-srliw 0000000 ..... ..... 101 ..... 0011011 @sh5
-sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5
-addw 0000000 ..... ..... 000 ..... 0111011 @r
-subw 0100000 ..... ..... 000 ..... 0111011 @r
-sllw 0000000 ..... ..... 001 ..... 0111011 @r
-srlw 0000000 ..... ..... 101 ..... 0111011 @r
-sraw 0100000 ..... ..... 101 ..... 0111011 @r
-
-# *** RV64M Standard Extension (in addition to RV32M) ***
-mulw 0000001 ..... ..... 000 ..... 0111011 @r
-divw 0000001 ..... ..... 100 ..... 0111011 @r
-divuw 0000001 ..... ..... 101 ..... 0111011 @r
-remw 0000001 ..... ..... 110 ..... 0111011 @r
-remuw 0000001 ..... ..... 111 ..... 0111011 @r
-
-# *** RV64A Standard Extension (in addition to RV32A) ***
-lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
-sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
-amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
-amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
-amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
-amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
-amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st
-amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st
-amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
-amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
-amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
-
-#*** Vector AMO operations (in addition to Zvamo) ***
-vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm
-vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm
-
-# *** RV64F Standard Extension (in addition to RV32F) ***
-fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
-fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
-fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm
-fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm
-
-# *** RV64D Standard Extension (in addition to RV32D) ***
-fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm
-fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm
-fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2
-fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm
-fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm
-fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2
-
-# *** RV32H Base Instruction Set ***
-hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2
-hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2
-hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 84080dd18c..8901ba1e1b 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -21,6 +21,7 @@
%rs2 20:5
%rs1 15:5
%rd 7:5
+%sh5 20:5
%sh10 20:10
%csr 20:12
@@ -86,6 +87,8 @@
@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1
@sfence_vm ....... ..... ..... ... ..... ....... %rs1
+# Formats 64:
+@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
# *** Privileged Instructions ***
ecall 000000000000 00000 000 00000 1110011
@@ -144,6 +147,20 @@ csrrwi ............ ..... 101 ..... 1110011 @csr
csrrsi ............ ..... 110 ..... 1110011 @csr
csrrci ............ ..... 111 ..... 1110011 @csr
+# *** RV64I Base Instruction Set (in addition to RV32I) ***
+lwu ............ ..... 110 ..... 0000011 @i
+ld ............ ..... 011 ..... 0000011 @i
+sd ....... ..... ..... 011 ..... 0100011 @s
+addiw ............ ..... 000 ..... 0011011 @i
+slliw 0000000 ..... ..... 001 ..... 0011011 @sh5
+srliw 0000000 ..... ..... 101 ..... 0011011 @sh5
+sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5
+addw 0000000 ..... ..... 000 ..... 0111011 @r
+subw 0100000 ..... ..... 000 ..... 0111011 @r
+sllw 0000000 ..... ..... 001 ..... 0111011 @r
+srlw 0000000 ..... ..... 101 ..... 0111011 @r
+sraw 0100000 ..... ..... 101 ..... 0111011 @r
+
# *** RV32M Standard Extension ***
mul 0000001 ..... ..... 000 ..... 0110011 @r
mulh 0000001 ..... ..... 001 ..... 0110011 @r
@@ -154,6 +171,13 @@ divu 0000001 ..... ..... 101 ..... 0110011 @r
rem 0000001 ..... ..... 110 ..... 0110011 @r
remu 0000001 ..... ..... 111 ..... 0110011 @r
+# *** RV64M Standard Extension (in addition to RV32M) ***
+mulw 0000001 ..... ..... 000 ..... 0111011 @r
+divw 0000001 ..... ..... 100 ..... 0111011 @r
+divuw 0000001 ..... ..... 101 ..... 0111011 @r
+remw 0000001 ..... ..... 110 ..... 0111011 @r
+remuw 0000001 ..... ..... 111 ..... 0111011 @r
+
# *** RV32A Standard Extension ***
lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
@@ -167,6 +191,19 @@ amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st
amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st
amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st
+# *** RV64A Standard Extension (in addition to RV32A) ***
+lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
+sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
+amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
+amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
+amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
+amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st
+amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st
+amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st
+
# *** RV32F Standard Extension ***
flw ............ ..... 010 ..... 0000111 @i
fsw ....... ..... ..... 010 ..... 0100111 @s
@@ -195,6 +232,12 @@ fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm
fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm
fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2
+# *** RV64F Standard Extension (in addition to RV32F) ***
+fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm
+fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm
+
# *** RV32D Standard Extension ***
fld ............ ..... 011 ..... 0000111 @i
fsd ....... ..... ..... 011 ..... 0100111 @s
@@ -223,6 +266,14 @@ fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm
fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm
fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
+# *** RV64D Standard Extension (in addition to RV32D) ***
+fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2
+fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm
+fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm
+fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2
+
# *** RV32H Base Instruction Set ***
hlv_b 0110000 00000 ..... 100 ..... 1110011 @r2
hlv_bu 0110000 00001 ..... 100 ..... 1110011 @r2
@@ -237,7 +288,10 @@ hsv_w 0110101 ..... ..... 100 00000 1110011 @r2_s
hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma
hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma
-# *** RV32V Extension ***
+# *** RV64H Base Instruction Set ***
+hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2
+hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2
+hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s
# *** Vector loads and stores are encoded within LOADFP/STORE-FP ***
vlb_v ... 100 . 00000 ..... 000 ..... 0000111 @r2_nfvm
@@ -592,3 +646,14 @@ vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r
vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm
vsetvl 1000000 ..... ..... 111 ..... 1010111 @r
+
+#*** Vector AMO operations (in addition to Zvamo) ***
+vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm
+vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index be8a9f06dd..ab2ec4f0a5 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -165,60 +165,68 @@ static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
}
-#ifdef TARGET_RISCV64
-
static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_lr(ctx, a, MO_ALIGN | MO_TEQ);
}
static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ));
}
static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ));
}
static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
{
+ REQUIRE_64BIT(ctx);
return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ));
}
-#endif
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
index 4f832637fa..7e45538ae0 100644
--- a/target/riscv/insn_trans/trans_rvd.c.inc
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -358,10 +358,9 @@ static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a)
return true;
}
-#ifdef TARGET_RISCV64
-
static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
@@ -375,6 +374,7 @@ static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a)
static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
@@ -388,15 +388,21 @@ static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a)
static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
+#ifdef TARGET_RISCV64
gen_set_gpr(a->rd, cpu_fpr[a->rs1]);
return true;
+#else
+ qemu_build_not_reached();
+#endif
}
static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
@@ -412,6 +418,7 @@ static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a)
static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
@@ -427,9 +434,11 @@ static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a)
static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
+#ifdef TARGET_RISCV64
TCGv t0 = tcg_temp_new();
gen_get_gpr(t0, a->rs1);
@@ -437,5 +446,7 @@ static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a)
tcg_temp_free(t0);
mark_fs_dirty(ctx);
return true;
-}
+#else
+ qemu_build_not_reached();
#endif
+}
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
index 3dfec8211d..db1c0c9974 100644
--- a/target/riscv/insn_trans/trans_rvf.c.inc
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -415,9 +415,9 @@ static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a)
return true;
}
-#ifdef TARGET_RISCV64
static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
@@ -431,6 +431,7 @@ static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a)
static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
@@ -444,6 +445,7 @@ static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a)
static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
@@ -460,6 +462,7 @@ static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a)
static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
@@ -473,4 +476,3 @@ static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a)
tcg_temp_free(t0);
return true;
}
-#endif
diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc
index ce7ed5affb..6b5edf82b7 100644
--- a/target/riscv/insn_trans/trans_rvh.c.inc
+++ b/target/riscv/insn_trans/trans_rvh.c.inc
@@ -203,10 +203,11 @@ static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a)
#endif
}
-#ifdef TARGET_RISCV64
static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVH);
+
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
@@ -228,7 +229,9 @@ static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a)
static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVH);
+
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
@@ -250,7 +253,9 @@ static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a)
static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVH);
+
#ifndef CONFIG_USER_ONLY
TCGv t0 = tcg_temp_new();
TCGv dat = tcg_temp_new();
@@ -269,7 +274,6 @@ static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a)
return false;
#endif
}
-#endif
static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a)
{
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index d04ca0394c..bd93f634cf 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -24,6 +24,12 @@ static bool trans_illegal(DisasContext *ctx, arg_empty *a)
return true;
}
+static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a)
+{
+ REQUIRE_64BIT(ctx);
+ return trans_illegal(ctx, a);
+}
+
static bool trans_lui(DisasContext *ctx, arg_lui *a)
{
if (a->rd != 0) {
@@ -204,22 +210,23 @@ static bool trans_sw(DisasContext *ctx, arg_sw *a)
return gen_store(ctx, a, MO_TESL);
}
-#ifdef TARGET_RISCV64
static bool trans_lwu(DisasContext *ctx, arg_lwu *a)
{
+ REQUIRE_64BIT(ctx);
return gen_load(ctx, a, MO_TEUL);
}
static bool trans_ld(DisasContext *ctx, arg_ld *a)
{
+ REQUIRE_64BIT(ctx);
return gen_load(ctx, a, MO_TEQ);
}
static bool trans_sd(DisasContext *ctx, arg_sd *a)
{
+ REQUIRE_64BIT(ctx);
return gen_store(ctx, a, MO_TEQ);
}
-#endif
static bool trans_addi(DisasContext *ctx, arg_addi *a)
{
@@ -361,14 +368,15 @@ static bool trans_and(DisasContext *ctx, arg_and *a)
return gen_arith(ctx, a, &tcg_gen_and_tl);
}
-#ifdef TARGET_RISCV64
static bool trans_addiw(DisasContext *ctx, arg_addiw *a)
{
+ REQUIRE_64BIT(ctx);
return gen_arith_imm_tl(ctx, a, &gen_addw);
}
static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv source1;
source1 = tcg_temp_new();
gen_get_gpr(source1, a->rs1);
@@ -383,6 +391,7 @@ static bool trans_slliw(DisasContext *ctx, arg_slliw *a)
static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv t = tcg_temp_new();
gen_get_gpr(t, a->rs1);
tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt);
@@ -395,6 +404,7 @@ static bool trans_srliw(DisasContext *ctx, arg_srliw *a)
static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv t = tcg_temp_new();
gen_get_gpr(t, a->rs1);
tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt);
@@ -405,16 +415,19 @@ static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a)
static bool trans_addw(DisasContext *ctx, arg_addw *a)
{
+ REQUIRE_64BIT(ctx);
return gen_arith(ctx, a, &gen_addw);
}
static bool trans_subw(DisasContext *ctx, arg_subw *a)
{
+ REQUIRE_64BIT(ctx);
return gen_arith(ctx, a, &gen_subw);
}
static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
@@ -433,6 +446,7 @@ static bool trans_sllw(DisasContext *ctx, arg_sllw *a)
static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
@@ -453,6 +467,7 @@ static bool trans_srlw(DisasContext *ctx, arg_srlw *a)
static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
{
+ REQUIRE_64BIT(ctx);
TCGv source1 = tcg_temp_new();
TCGv source2 = tcg_temp_new();
@@ -473,7 +488,6 @@ static bool trans_sraw(DisasContext *ctx, arg_sraw *a)
return true;
}
-#endif
static bool trans_fence(DisasContext *ctx, arg_fence *a)
{
diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc
index 47cd6edc72..10ecc456fc 100644
--- a/target/riscv/insn_trans/trans_rvm.c.inc
+++ b/target/riscv/insn_trans/trans_rvm.c.inc
@@ -87,34 +87,42 @@ static bool trans_remu(DisasContext *ctx, arg_remu *a)
return gen_arith(ctx, a, &gen_remu);
}
-#ifdef TARGET_RISCV64
static bool trans_mulw(DisasContext *ctx, arg_mulw *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVM);
+
return gen_arith(ctx, a, &gen_mulw);
}
static bool trans_divw(DisasContext *ctx, arg_divw *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVM);
+
return gen_arith_div_w(ctx, a, &gen_div);
}
static bool trans_divuw(DisasContext *ctx, arg_divuw *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVM);
+
return gen_arith_div_uw(ctx, a, &gen_divu);
}
static bool trans_remw(DisasContext *ctx, arg_remw *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVM);
+
return gen_arith_div_w(ctx, a, &gen_rem);
}
static bool trans_remuw(DisasContext *ctx, arg_remuw *a)
{
+ REQUIRE_64BIT(ctx);
REQUIRE_EXT(ctx, RVM);
+
return gen_arith_div_uw(ctx, a, &gen_remu);
}
-#endif
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 887c6b8883..47914a3b69 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -705,7 +705,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
gen_helper_vamominuw_v_w,
gen_helper_vamomaxuw_v_w
};
-#ifdef TARGET_RISCV64
static gen_helper_amo *const fnsd[18] = {
gen_helper_vamoswapw_v_d,
gen_helper_vamoaddw_v_d,
@@ -726,7 +725,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
gen_helper_vamominud_v_d,
gen_helper_vamomaxud_v_d
};
-#endif
if (tb_cflags(s->base.tb) & CF_PARALLEL) {
gen_helper_exit_atomic(cpu_env);
@@ -734,12 +732,12 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq)
return true;
} else {
if (s->sew == 3) {
-#ifdef TARGET_RISCV64
- fn = fnsd[seq];
-#else
- /* Check done in amo_check(). */
- g_assert_not_reached();
-#endif
+ if (!is_32bit(s)) {
+ fn = fnsd[seq];
+ } else {
+ /* Check done in amo_check(). */
+ g_assert_not_reached();
+ }
} else {
assert(seq < ARRAY_SIZE(fnsw));
fn = fnsw[seq];
@@ -769,6 +767,11 @@ static bool amo_check(DisasContext *s, arg_rwdvm* a)
((1 << s->sew) >= 4));
}
+static bool amo_check64(DisasContext *s, arg_rwdvm* a)
+{
+ return !is_32bit(s) && amo_check(s, a);
+}
+
GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check)
GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check)
GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check)
@@ -778,17 +781,15 @@ GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check)
GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check)
GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check)
GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check)
-#ifdef TARGET_RISCV64
-GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check)
-GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check)
-#endif
+GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64)
+GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64)
/*
*** Vector Integer Arithmetic Instructions
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 44d4015bd6..16a08302da 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -140,8 +140,8 @@ static const VMStateDescription vmstate_hyper = {
const VMStateDescription vmstate_riscv_cpu = {
.name = "cpu",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
@@ -165,10 +165,8 @@ const VMStateDescription vmstate_riscv_cpu = {
VMSTATE_UINT32(env.miclaim, RISCVCPU),
VMSTATE_UINTTL(env.mie, RISCVCPU),
VMSTATE_UINTTL(env.mideleg, RISCVCPU),
- VMSTATE_UINTTL(env.sptbr, RISCVCPU),
VMSTATE_UINTTL(env.satp, RISCVCPU),
- VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
- VMSTATE_UINTTL(env.mbadaddr, RISCVCPU),
+ VMSTATE_UINTTL(env.stval, RISCVCPU),
VMSTATE_UINTTL(env.medeleg, RISCVCPU),
VMSTATE_UINTTL(env.stvec, RISCVCPU),
VMSTATE_UINTTL(env.sepc, RISCVCPU),
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 88ab850682..af6c3416b7 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -1,18 +1,13 @@
# FIXME extra_args should accept files()
dir = meson.current_source_dir()
-gen32 = [
- decodetree.process('insn16.decode', extra_args: [dir / 'insn16-32.decode', '--static-decode=decode_insn16', '--insnwidth=16']),
- decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),
-]
-gen64 = [
- decodetree.process('insn16.decode', extra_args: [dir / 'insn16-64.decode', '--static-decode=decode_insn16', '--insnwidth=16']),
- decodetree.process('insn32.decode', extra_args: [dir / 'insn32-64.decode', '--static-decode=decode_insn32']),
+gen = [
+ decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']),
+ decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),
]
riscv_ss = ss.source_set()
-riscv_ss.add(when: 'TARGET_RISCV32', if_true: gen32)
-riscv_ss.add(when: 'TARGET_RISCV64', if_true: gen64)
+riscv_ss.add(gen)
riscv_ss.add(files(
'cpu.c',
'cpu_helper.c',
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
index e51188f919..f7e6ea72b3 100644
--- a/target/riscv/monitor.c
+++ b/target/riscv/monitor.c
@@ -150,9 +150,14 @@ static void mem_info_svxx(Monitor *mon, CPUArchState *env)
target_ulong last_size;
int last_attr;
- base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+ if (riscv_cpu_is_32bit(env)) {
+ base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP32_MODE);
+ } else {
+ base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP64_MODE);
+ }
- vm = get_field(env->satp, SATP_MODE);
switch (vm) {
case VM_1_10_SV32:
levels = 2;
@@ -215,9 +220,16 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict)
return;
}
- if (!(env->satp & SATP_MODE)) {
- monitor_printf(mon, "No translation or protection\n");
- return;
+ if (riscv_cpu_is_32bit(env)) {
+ if (!(env->satp & SATP32_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
+ } else {
+ if (!(env->satp & SATP64_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
}
mem_info_svxx(mon, env);
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index f0bbd73ca5..170b494227 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -41,10 +41,10 @@ target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
target_ulong csr)
{
target_ulong val = 0;
- int ret = riscv_csrrw(env, csr, &val, src, -1);
+ RISCVException ret = riscv_csrrw(env, csr, &val, src, -1);
- if (ret < 0) {
- riscv_raise_exception(env, -ret, GETPC());
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
}
return val;
}
@@ -53,10 +53,10 @@ target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
{
target_ulong val = 0;
- int ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0);
+ RISCVException ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0);
- if (ret < 0) {
- riscv_raise_exception(env, -ret, GETPC());
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
}
return val;
}
@@ -65,10 +65,10 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
target_ulong csr, target_ulong rs1_pass)
{
target_ulong val = 0;
- int ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0);
+ RISCVException ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0);
- if (ret < 0) {
- riscv_raise_exception(env, -ret, GETPC());
+ if (ret != RISCV_EXCP_NONE) {
+ riscv_raise_exception(env, ret, GETPC());
}
return val;
}
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index cff020122a..78203291de 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -19,10 +19,6 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/*
- * PMP (Physical Memory Protection) is as-of-yet unused and needs testing.
- */
-
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/error.h"
@@ -59,16 +55,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
return 0;
}
- /* In TOR mode, need to check the lock bit of the next pmp
- * (if there is a next)
- */
- const uint8_t a_field =
- pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg);
- if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) &&
- (PMP_AMATCH_TOR == a_field)) {
- return 1;
- }
-
return 0;
}
@@ -100,11 +86,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
{
if (pmp_index < MAX_RISCV_PMPS) {
- if (!pmp_is_locked(env, pmp_index)) {
- env->pmp_state.pmp[pmp_index].cfg_reg = val;
- pmp_update_rule(env, pmp_index);
+ bool locked = true;
+
+ if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ /* mseccfg.RLB is set */
+ if (MSECCFG_RLB_ISSET(env)) {
+ locked = false;
+ }
+
+ /* mseccfg.MML is not set */
+ if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
+ locked = false;
+ }
+
+ /* mseccfg.MML is set */
+ if (MSECCFG_MML_ISSET(env)) {
+ /* not adding execute bit */
+ if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
+ locked = false;
+ }
+ /* shared region and not adding X bit */
+ if ((val & PMP_LOCK) != PMP_LOCK &&
+ (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
+ locked = false;
+ }
+ }
} else {
+ if (!pmp_is_locked(env, pmp_index)) {
+ locked = false;
+ }
+ }
+
+ if (locked) {
qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
+ } else {
+ env->pmp_state.pmp[pmp_index].cfg_reg = val;
+ pmp_update_rule(env, pmp_index);
}
} else {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -227,6 +244,32 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
{
bool ret;
+ if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
+ if (MSECCFG_MMWP_ISSET(env)) {
+ /*
+ * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
+ * so we default to deny all, even for M-mode.
+ */
+ *allowed_privs = 0;
+ return false;
+ } else if (MSECCFG_MML_ISSET(env)) {
+ /*
+ * The Machine Mode Lockdown (mseccfg.MML) bit is set
+ * so we can only execute code in M-mode with an applicable
+ * rule. Other modes are disabled.
+ */
+ if (mode == PRV_M && !(privs & PMP_EXEC)) {
+ ret = true;
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ } else {
+ ret = false;
+ *allowed_privs = 0;
+ }
+
+ return ret;
+ }
+ }
+
if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
/*
* Privileged spec v1.10 states if HW doesn't implement any PMP entry
@@ -304,13 +347,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
/*
- * If the PMP entry is not off and the address is in range, do the priv
- * check
+ * Convert the PMP permissions to match the truth table in the
+ * ePMP spec.
*/
+ const uint8_t epmp_operation =
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
+ (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
+ ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
+
if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
- *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
- if ((mode != PRV_M) || pmp_is_locked(env, i)) {
- *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+ /*
+ * If the PMP entry is not off and the address is in range,
+ * do the priv check
+ */
+ if (!MSECCFG_MML_ISSET(env)) {
+ /*
+ * If mseccfg.MML Bit is not set, do pmp priv check
+ * This will always apply to regular PMP.
+ */
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ if ((mode != PRV_M) || pmp_is_locked(env, i)) {
+ *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+ }
+ } else {
+ /*
+ * If mseccfg.MML Bit set, do the enhanced pmp priv check
+ */
+ if (mode == PRV_M) {
+ switch (epmp_operation) {
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ *allowed_privs = 0;
+ break;
+ case 2:
+ case 3:
+ case 14:
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ break;
+ case 9:
+ case 10:
+ *allowed_privs = PMP_EXEC;
+ break;
+ case 11:
+ case 13:
+ *allowed_privs = PMP_READ | PMP_EXEC;
+ break;
+ case 12:
+ case 15:
+ *allowed_privs = PMP_READ;
+ break;
+ }
+ } else {
+ switch (epmp_operation) {
+ case 0:
+ case 8:
+ case 9:
+ case 12:
+ case 13:
+ case 14:
+ *allowed_privs = 0;
+ break;
+ case 1:
+ case 10:
+ case 11:
+ *allowed_privs = PMP_EXEC;
+ break;
+ case 2:
+ case 4:
+ case 15:
+ *allowed_privs = PMP_READ;
+ break;
+ case 3:
+ case 6:
+ *allowed_privs = PMP_READ | PMP_WRITE;
+ break;
+ case 5:
+ *allowed_privs = PMP_READ | PMP_EXEC;
+ break;
+ case 7:
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ break;
+ }
+ }
}
ret = ((privs & *allowed_privs) == privs);
@@ -380,7 +504,23 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong val)
{
trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
+
if (addr_index < MAX_RISCV_PMPS) {
+ /*
+ * In TOR mode, need to check the lock bit of the next pmp
+ * (if there is a next).
+ */
+ if (addr_index + 1 < MAX_RISCV_PMPS) {
+ uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
+
+ if (pmp_cfg & PMP_LOCK &&
+ PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "ignoring pmpaddr write - pmpcfg + 1 locked\n");
+ return;
+ }
+ }
+
if (!pmp_is_locked(env, addr_index)) {
env->pmp_state.pmp[addr_index].addr_reg = val;
pmp_update_rule(env, addr_index);
@@ -414,6 +554,40 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
}
/*
+ * Handle a write to a mseccfg CSR
+ */
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
+{
+ int i;
+
+ trace_mseccfg_csr_write(env->mhartid, val);
+
+ /* RLB cannot be enabled if it's already 0 and if any regions are locked */
+ if (!MSECCFG_RLB_ISSET(env)) {
+ for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ if (pmp_is_locked(env, i)) {
+ val &= ~MSECCFG_RLB;
+ break;
+ }
+ }
+ }
+
+ /* Sticky bits */
+ val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML));
+
+ env->mseccfg = val;
+}
+
+/*
+ * Handle a read from a mseccfg CSR
+ */
+target_ulong mseccfg_csr_read(CPURISCVState *env)
+{
+ trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
+ return env->mseccfg;
+}
+
+/*
* Calculate the TLB size if the start address or the end address of
* PMP entry is presented in thie TLB page.
*/
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index b82a30f0d5..a9a0b363a7 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -36,6 +36,12 @@ typedef enum {
PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */
} pmp_am_t;
+typedef enum {
+ MSECCFG_MML = 1 << 0,
+ MSECCFG_MMWP = 1 << 1,
+ MSECCFG_RLB = 1 << 2
+} mseccfg_field_t;
+
typedef struct {
target_ulong addr_reg;
uint8_t cfg_reg;
@@ -55,6 +61,10 @@ typedef struct {
void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
target_ulong val);
target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index);
+
+void mseccfg_csr_write(CPURISCVState *env, target_ulong val);
+target_ulong mseccfg_csr_read(CPURISCVState *env);
+
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong val);
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
@@ -68,4 +78,8 @@ void pmp_update_rule_nums(CPURISCVState *env);
uint32_t pmp_get_num_rules(CPURISCVState *env);
int pmp_priv_to_page_prot(pmp_priv_t pmp_priv);
+#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML)
+#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP)
+#define MSECCFG_RLB_ISSET(env) get_field(env->mseccfg, MSECCFG_RLB)
+
#endif
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
index b7e371ee97..49ec4d3b7d 100644
--- a/target/riscv/trace-events
+++ b/target/riscv/trace-events
@@ -6,3 +6,6 @@ pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRI
pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
+
+mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64
+mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 2f9f5ccc62..e945352bca 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -67,17 +67,22 @@ typedef struct DisasContext {
CPUState *cs;
} DisasContext;
-#ifdef TARGET_RISCV64
-#define CASE_OP_32_64(X) case X: case glue(X, W)
-#else
-#define CASE_OP_32_64(X) case X
-#endif
-
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
{
return ctx->misa & ext;
}
+#ifdef TARGET_RISCV32
+# define is_32bit(ctx) true
+#elif defined(CONFIG_USER_ONLY)
+# define is_32bit(ctx) false
+#else
+static inline bool is_32bit(DisasContext *ctx)
+{
+ return (ctx->misa & RV32) == RV32;
+}
+#endif
+
/*
* RISC-V requires NaN-boxing of narrower width floating point values.
* This applies when a 32-bit value is assigned to a 64-bit FP register.
@@ -116,7 +121,7 @@ static void generate_exception(DisasContext *ctx, int excp)
ctx->base.is_jmp = DISAS_NORETURN;
}
-static void generate_exception_mbadaddr(DisasContext *ctx, int excp)
+static void generate_exception_mtval(DisasContext *ctx, int excp)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
@@ -160,7 +165,7 @@ static void gen_exception_illegal(DisasContext *ctx)
static void gen_exception_inst_addr_mis(DisasContext *ctx)
{
- generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS);
+ generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS);
}
static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
@@ -369,6 +374,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
static void mark_fs_dirty(DisasContext *ctx)
{
TCGv tmp;
+ target_ulong sd;
+
if (ctx->mstatus_fs == MSTATUS_FS) {
return;
}
@@ -376,13 +383,15 @@ static void mark_fs_dirty(DisasContext *ctx)
ctx->mstatus_fs = MSTATUS_FS;
tmp = tcg_temp_new();
+ sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD;
+
tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
- tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD);
+ tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd);
tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
if (ctx->virt_enabled) {
tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
- tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD);
+ tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd);
tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs));
}
tcg_temp_free(tmp);
@@ -426,6 +435,12 @@ EX_SH(12)
} \
} while (0)
+#define REQUIRE_64BIT(ctx) do { \
+ if (is_32bit(ctx)) { \
+ return false; \
+ } \
+} while (0)
+
static int ex_rvc_register(DisasContext *ctx, int reg)
{
return 8 + reg;
@@ -473,7 +488,6 @@ static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a,
return true;
}
-#ifdef TARGET_RISCV64
static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2)
{
tcg_gen_add_tl(ret, arg1, arg2);
@@ -534,8 +548,6 @@ static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a,
return true;
}
-#endif
-
static bool gen_arith(DisasContext *ctx, arg_r *a,
void(*func)(TCGv, TCGv, TCGv))
{
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index a156573d28..12c31aa4b4 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -751,7 +751,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_w, 32, 32, H4, DO_MIN, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_w, 32, 32, H4, DO_MAX, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_w, 32, 32, H4, DO_MINU, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_w, 32, 32, H4, DO_MAXU, l)
-#ifdef TARGET_RISCV64
GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_d, 64, 32, H8, DO_SWAP, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamoswapd_v_d, 64, 64, H8, DO_SWAP, q)
GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_d, 64, 32, H8, DO_ADD, l)
@@ -770,7 +769,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_d, 64, 32, H8, DO_MINU, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamominud_v_d, 64, 64, H8, DO_MINU, q)
GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_d, 64, 32, H8, DO_MAXU, l)
GEN_VEXT_AMO_NOATOMIC_OP(vamomaxud_v_d, 64, 64, H8, DO_MAXU, q)
-#endif
static inline void
vext_amo_noatomic(void *vs3, void *v0, target_ulong base,
@@ -814,7 +812,6 @@ void HELPER(NAME)(void *vs3, void *v0, target_ulong base, \
GETPC()); \
}
-#ifdef TARGET_RISCV64
GEN_VEXT_AMO(vamoswapw_v_d, int32_t, int64_t, idx_d, clearq)
GEN_VEXT_AMO(vamoswapd_v_d, int64_t, int64_t, idx_d, clearq)
GEN_VEXT_AMO(vamoaddw_v_d, int32_t, int64_t, idx_d, clearq)
@@ -833,7 +830,6 @@ GEN_VEXT_AMO(vamominuw_v_d, uint32_t, uint64_t, idx_d, clearq)
GEN_VEXT_AMO(vamominud_v_d, uint64_t, uint64_t, idx_d, clearq)
GEN_VEXT_AMO(vamomaxuw_v_d, uint32_t, uint64_t, idx_d, clearq)
GEN_VEXT_AMO(vamomaxud_v_d, uint64_t, uint64_t, idx_d, clearq)
-#endif
GEN_VEXT_AMO(vamoswapw_v_w, int32_t, int32_t, idx_w, clearl)
GEN_VEXT_AMO(vamoaddw_v_w, int32_t, int32_t, idx_w, clearl)
GEN_VEXT_AMO(vamoxorw_v_w, int32_t, int32_t, idx_w, clearl)
@@ -2451,7 +2447,7 @@ static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b)
{
int8_t res = a - b;
if ((res ^ a) & (a ^ b) & INT8_MIN) {
- res = a > 0 ? INT8_MAX : INT8_MIN;
+ res = a >= 0 ? INT8_MAX : INT8_MIN;
env->vxsat = 0x1;
}
return res;
@@ -2461,7 +2457,7 @@ static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a, int16_t b)
{
int16_t res = a - b;
if ((res ^ a) & (a ^ b) & INT16_MIN) {
- res = a > 0 ? INT16_MAX : INT16_MIN;
+ res = a >= 0 ? INT16_MAX : INT16_MIN;
env->vxsat = 0x1;
}
return res;
@@ -2471,7 +2467,7 @@ static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b)
{
int32_t res = a - b;
if ((res ^ a) & (a ^ b) & INT32_MIN) {
- res = a > 0 ? INT32_MAX : INT32_MIN;
+ res = a >= 0 ? INT32_MAX : INT32_MIN;
env->vxsat = 0x1;
}
return res;
@@ -2481,7 +2477,7 @@ static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b)
{
int64_t res = a - b;
if ((res ^ a) & (a ^ b) & INT64_MIN) {
- res = a > 0 ? INT64_MAX : INT64_MIN;
+ res = a >= 0 ? INT64_MAX : INT64_MIN;
env->vxsat = 0x1;
}
return res;
@@ -4796,7 +4792,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
uint32_t vm = vext_vm(desc); \
uint32_t vl = env->vl; \
- uint32_t index, i; \
+ uint64_t index; \
+ uint32_t i; \
\
for (i = 0; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, mlen, i)) { \
@@ -4826,7 +4823,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \
uint32_t vm = vext_vm(desc); \
uint32_t vl = env->vl; \
- uint32_t index = s1, i; \
+ uint64_t index = s1; \
+ uint32_t i; \
\
for (i = 0; i < vl; i++) { \
if (!vm && !vext_elem_mask(v0, mlen, i)) { \
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index bd8e034f17..2d622081e8 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -441,9 +441,12 @@ hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
target_ulong physical;
int prot;
- get_physical_address(&cpu->env, &physical, &prot, addr, MMU_DATA_LOAD);
+ if (get_physical_address(&cpu->env, &physical, &prot, addr, MMU_DATA_LOAD)
+ == MMU_OK) {
+ return physical;
+ }
- return physical;
+ return -1;
}
void cpu_load_tlb(CPUSH4State * env)
diff --git a/target/unicore32/cpu-param.h b/target/unicore32/cpu-param.h
deleted file mode 100644
index 94d8a5daa1..0000000000
--- a/target/unicore32/cpu-param.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * UniCore32 cpu parameters for qemu.
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-#ifndef UNICORE32_CPU_PARAM_H
-#define UNICORE32_CPU_PARAM_H 1
-
-#define TARGET_LONG_BITS 32
-#define TARGET_PAGE_BITS 12
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
-#define NB_MMU_MODES 2
-
-#endif
diff --git a/target/unicore32/cpu-qom.h b/target/unicore32/cpu-qom.h
deleted file mode 100644
index 43621e7479..0000000000
--- a/target/unicore32/cpu-qom.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * QEMU UniCore32 CPU
- *
- * Copyright (c) 2012 SUSE LINUX Products GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-#ifndef QEMU_UC32_CPU_QOM_H
-#define QEMU_UC32_CPU_QOM_H
-
-#include "hw/core/cpu.h"
-#include "qom/object.h"
-
-#define TYPE_UNICORE32_CPU "unicore32-cpu"
-
-OBJECT_DECLARE_TYPE(UniCore32CPU, UniCore32CPUClass,
- UNICORE32_CPU)
-
-/**
- * UniCore32CPUClass:
- * @parent_realize: The parent class' realize handler.
- *
- * A UniCore32 CPU model.
- */
-struct UniCore32CPUClass {
- /*< private >*/
- CPUClass parent_class;
- /*< public >*/
-
- DeviceRealize parent_realize;
-};
-
-
-#endif
diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c
deleted file mode 100644
index 0258884f84..0000000000
--- a/target/unicore32/cpu.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * QEMU UniCore32 CPU
- *
- * Copyright (c) 2010-2012 Guan Xuetao
- * Copyright (c) 2012 SUSE LINUX Products GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Contributions from 2012-04-01 on are considered under GPL version 2,
- * or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "migration/vmstate.h"
-#include "exec/exec-all.h"
-
-static void uc32_cpu_set_pc(CPUState *cs, vaddr value)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(cs);
-
- cpu->env.regs[31] = value;
-}
-
-static bool uc32_cpu_has_work(CPUState *cs)
-{
- return cs->interrupt_request &
- (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
-}
-
-static inline void set_feature(CPUUniCore32State *env, int feature)
-{
- env->features |= feature;
-}
-
-/* CPU models */
-
-static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model)
-{
- ObjectClass *oc;
- char *typename;
-
- typename = g_strdup_printf(UNICORE32_CPU_TYPE_NAME("%s"), cpu_model);
- oc = object_class_by_name(typename);
- g_free(typename);
- if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) ||
- object_class_is_abstract(oc))) {
- oc = NULL;
- }
- return oc;
-}
-
-static void unicore_ii_cpu_initfn(Object *obj)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(obj);
- CPUUniCore32State *env = &cpu->env;
-
- env->cp0.c0_cpuid = 0x4d000863;
- env->cp0.c0_cachetype = 0x0d152152;
- env->cp0.c1_sys = 0x2000;
- env->cp0.c2_base = 0x0;
- env->cp0.c3_faultstatus = 0x0;
- env->cp0.c4_faultaddr = 0x0;
- env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
-
- set_feature(env, UC32_HWCAP_CMOV);
- set_feature(env, UC32_HWCAP_UCF64);
-}
-
-static void uc32_any_cpu_initfn(Object *obj)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(obj);
- CPUUniCore32State *env = &cpu->env;
-
- env->cp0.c0_cpuid = 0xffffffff;
- env->ucf64.xregs[UC32_UCF64_FPSCR] = 0;
-
- set_feature(env, UC32_HWCAP_CMOV);
- set_feature(env, UC32_HWCAP_UCF64);
-}
-
-static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)
-{
- CPUState *cs = CPU(dev);
- UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev);
- Error *local_err = NULL;
-
- cpu_exec_realizefn(cs, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
- return;
- }
-
- qemu_init_vcpu(cs);
-
- ucc->parent_realize(dev, errp);
-}
-
-static void uc32_cpu_initfn(Object *obj)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(obj);
- CPUUniCore32State *env = &cpu->env;
-
- cpu_set_cpustate_pointers(cpu);
-
-#ifdef CONFIG_USER_ONLY
- env->uncached_asr = ASR_MODE_USER;
- env->regs[31] = 0;
-#else
- env->uncached_asr = ASR_MODE_PRIV;
- env->regs[31] = 0x03000000;
-#endif
-}
-
-static const VMStateDescription vmstate_uc32_cpu = {
- .name = "cpu",
- .unmigratable = 1,
-};
-
-#include "hw/core/tcg-cpu-ops.h"
-
-static struct TCGCPUOps uc32_tcg_ops = {
- .initialize = uc32_translate_init,
- .cpu_exec_interrupt = uc32_cpu_exec_interrupt,
- .tlb_fill = uc32_cpu_tlb_fill,
-
-#ifndef CONFIG_USER_ONLY
- .do_interrupt = uc32_cpu_do_interrupt,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static void uc32_cpu_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- CPUClass *cc = CPU_CLASS(oc);
- UniCore32CPUClass *ucc = UNICORE32_CPU_CLASS(oc);
-
- device_class_set_parent_realize(dc, uc32_cpu_realizefn,
- &ucc->parent_realize);
-
- cc->class_by_name = uc32_cpu_class_by_name;
- cc->has_work = uc32_cpu_has_work;
- cc->dump_state = uc32_cpu_dump_state;
- cc->set_pc = uc32_cpu_set_pc;
- cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
- dc->vmsd = &vmstate_uc32_cpu;
- cc->tcg_ops = &uc32_tcg_ops;
-}
-
-#define DEFINE_UNICORE32_CPU_TYPE(cpu_model, initfn) \
- { \
- .parent = TYPE_UNICORE32_CPU, \
- .instance_init = initfn, \
- .name = UNICORE32_CPU_TYPE_NAME(cpu_model), \
- }
-
-static const TypeInfo uc32_cpu_type_infos[] = {
- {
- .name = TYPE_UNICORE32_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(UniCore32CPU),
- .instance_init = uc32_cpu_initfn,
- .abstract = true,
- .class_size = sizeof(UniCore32CPUClass),
- .class_init = uc32_cpu_class_init,
- },
- DEFINE_UNICORE32_CPU_TYPE("UniCore-II", unicore_ii_cpu_initfn),
- DEFINE_UNICORE32_CPU_TYPE("any", uc32_any_cpu_initfn),
-};
-
-DEFINE_TYPES(uc32_cpu_type_infos)
diff --git a/target/unicore32/cpu.h b/target/unicore32/cpu.h
deleted file mode 100644
index 7a32e086ed..0000000000
--- a/target/unicore32/cpu.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * UniCore32 virtual CPU header
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-
-#ifndef UNICORE32_CPU_H
-#define UNICORE32_CPU_H
-
-#include "cpu-qom.h"
-#include "exec/cpu-defs.h"
-
-typedef struct CPUUniCore32State {
- /* Regs for current mode. */
- uint32_t regs[32];
- /* Frequently accessed ASR bits are stored separately for efficiently.
- This contains all the other bits. Use asr_{read,write} to access
- the whole ASR. */
- uint32_t uncached_asr;
- uint32_t bsr;
-
- /* Banked registers. */
- uint32_t banked_bsr[6];
- uint32_t banked_r29[6];
- uint32_t banked_r30[6];
-
- /* asr flag cache for faster execution */
- uint32_t CF; /* 0 or 1 */
- uint32_t VF; /* V is the bit 31. All other bits are undefined */
- uint32_t NF; /* N is bit 31. All other bits are undefined. */
- uint32_t ZF; /* Z set if zero. */
-
- /* System control coprocessor (cp0) */
- struct {
- uint32_t c0_cpuid;
- uint32_t c0_cachetype;
- uint32_t c1_sys; /* System control register. */
- uint32_t c2_base; /* MMU translation table base. */
- uint32_t c3_faultstatus; /* Fault status registers. */
- uint32_t c4_faultaddr; /* Fault address registers. */
- uint32_t c5_cacheop; /* Cache operation registers. */
- uint32_t c6_tlbop; /* TLB operation registers. */
- } cp0;
-
- /* UniCore-F64 coprocessor state. */
- struct {
- float64 regs[16];
- uint32_t xregs[32];
- float_status fp_status;
- } ucf64;
-
- /* Internal CPU feature flags. */
- uint32_t features;
-
-} CPUUniCore32State;
-
-/**
- * UniCore32CPU:
- * @env: #CPUUniCore32State
- *
- * A UniCore32 CPU.
- */
-struct UniCore32CPU {
- /*< private >*/
- CPUState parent_obj;
- /*< public >*/
-
- CPUNegativeOffsetState neg;
- CPUUniCore32State env;
-};
-
-
-void uc32_cpu_do_interrupt(CPUState *cpu);
-bool uc32_cpu_exec_interrupt(CPUState *cpu, int int_req);
-void uc32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
-hwaddr uc32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-
-#define ASR_M (0x1f)
-#define ASR_MODE_USER (0x10)
-#define ASR_MODE_INTR (0x12)
-#define ASR_MODE_PRIV (0x13)
-#define ASR_MODE_TRAP (0x17)
-#define ASR_MODE_EXTN (0x1b)
-#define ASR_MODE_SUSR (0x1f)
-#define ASR_I (1 << 7)
-#define ASR_V (1 << 28)
-#define ASR_C (1 << 29)
-#define ASR_Z (1 << 30)
-#define ASR_N (1 << 31)
-#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V)
-#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV))
-
-#define UC32_EXCP_PRIV (1)
-#define UC32_EXCP_ITRAP (2)
-#define UC32_EXCP_DTRAP (3)
-#define UC32_EXCP_INTR (4)
-
-/* Return the current ASR value. */
-target_ulong cpu_asr_read(CPUUniCore32State *env1);
-/* Set the ASR. Note that some bits of mask must be all-set or all-clear. */
-void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask);
-
-/* UniCore-F64 system registers. */
-#define UC32_UCF64_FPSCR (31)
-#define UCF64_FPSCR_MASK (0x27ffffff)
-#define UCF64_FPSCR_RND_MASK (0x7)
-#define UCF64_FPSCR_RND(r) (((r) >> 0) & UCF64_FPSCR_RND_MASK)
-#define UCF64_FPSCR_TRAPEN_MASK (0x7f)
-#define UCF64_FPSCR_TRAPEN(r) (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK)
-#define UCF64_FPSCR_FLAG_MASK (0x3ff)
-#define UCF64_FPSCR_FLAG(r) (((r) >> 17) & UCF64_FPSCR_FLAG_MASK)
-#define UCF64_FPSCR_FLAG_ZERO (1 << 17)
-#define UCF64_FPSCR_FLAG_INFINITY (1 << 18)
-#define UCF64_FPSCR_FLAG_INVALID (1 << 19)
-#define UCF64_FPSCR_FLAG_UNDERFLOW (1 << 20)
-#define UCF64_FPSCR_FLAG_OVERFLOW (1 << 21)
-#define UCF64_FPSCR_FLAG_INEXACT (1 << 22)
-#define UCF64_FPSCR_FLAG_HUGEINT (1 << 23)
-#define UCF64_FPSCR_FLAG_DENORMAL (1 << 24)
-#define UCF64_FPSCR_FLAG_UNIMP (1 << 25)
-#define UCF64_FPSCR_FLAG_DIVZERO (1 << 26)
-
-#define UC32_HWCAP_CMOV 4 /* 1 << 2 */
-#define UC32_HWCAP_UCF64 8 /* 1 << 3 */
-
-#define cpu_signal_handler uc32_cpu_signal_handler
-
-int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
-
-/* MMU modes definitions */
-#define MMU_USER_IDX 1
-static inline int cpu_mmu_index(CPUUniCore32State *env, bool ifetch)
-{
- return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0;
-}
-
-typedef CPUUniCore32State CPUArchState;
-typedef UniCore32CPU ArchCPU;
-
-#include "exec/cpu-all.h"
-
-#define UNICORE32_CPU_TYPE_SUFFIX "-" TYPE_UNICORE32_CPU
-#define UNICORE32_CPU_TYPE_NAME(model) model UNICORE32_CPU_TYPE_SUFFIX
-#define CPU_RESOLVING_TYPE TYPE_UNICORE32_CPU
-
-static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc,
- target_ulong *cs_base, uint32_t *flags)
-{
- *pc = env->regs[31];
- *cs_base = 0;
- *flags = 0;
- if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) {
- *flags |= (1 << 6);
- }
-}
-
-bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-void uc32_translate_init(void);
-void switch_mode(CPUUniCore32State *, int);
-
-#endif /* UNICORE32_CPU_H */
diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c
deleted file mode 100644
index 704393c27f..0000000000
--- a/target/unicore32/helper.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Contributions from 2012-04-01 on are considered under GPL version 2,
- * or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "exec/helper-proto.h"
-#include "semihosting/console.h"
-
-#undef DEBUG_UC32
-
-#ifdef DEBUG_UC32
-#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#ifndef CONFIG_USER_ONLY
-void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg,
- uint32_t cop)
-{
- /*
- * movc pp.nn, rn, #imm9
- * rn: UCOP_REG_D
- * nn: UCOP_REG_N
- * 1: sys control reg.
- * 2: page table base reg.
- * 3: data fault status reg.
- * 4: insn fault status reg.
- * 5: cache op. reg.
- * 6: tlb op. reg.
- * imm9: split UCOP_IMM10 with bit5 is 0
- */
- switch (creg) {
- case 1:
- if (cop != 0) {
- goto unrecognized;
- }
- env->cp0.c1_sys = val;
- break;
- case 2:
- if (cop != 0) {
- goto unrecognized;
- }
- env->cp0.c2_base = val;
- break;
- case 3:
- if (cop != 0) {
- goto unrecognized;
- }
- env->cp0.c3_faultstatus = val;
- break;
- case 4:
- if (cop != 0) {
- goto unrecognized;
- }
- env->cp0.c4_faultaddr = val;
- break;
- case 5:
- switch (cop) {
- case 28:
- DPRINTF("Invalidate Entire I&D cache\n");
- return;
- case 20:
- DPRINTF("Invalidate Entire Icache\n");
- return;
- case 12:
- DPRINTF("Invalidate Entire Dcache\n");
- return;
- case 10:
- DPRINTF("Clean Entire Dcache\n");
- return;
- case 14:
- DPRINTF("Flush Entire Dcache\n");
- return;
- case 13:
- DPRINTF("Invalidate Dcache line\n");
- return;
- case 11:
- DPRINTF("Clean Dcache line\n");
- return;
- case 15:
- DPRINTF("Flush Dcache line\n");
- return;
- }
- break;
- case 6:
- if ((cop <= 6) && (cop >= 2)) {
- /* invalid all tlb */
- tlb_flush(env_cpu(env));
- return;
- }
- break;
- default:
- goto unrecognized;
- }
- return;
-unrecognized:
- qemu_log_mask(LOG_GUEST_ERROR,
- "Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
- creg, cop);
-}
-
-uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop)
-{
- /*
- * movc rd, pp.nn, #imm9
- * rd: UCOP_REG_D
- * nn: UCOP_REG_N
- * 0: cpuid and cachetype
- * 1: sys control reg.
- * 2: page table base reg.
- * 3: data fault status reg.
- * 4: insn fault status reg.
- * imm9: split UCOP_IMM10 with bit5 is 0
- */
- switch (creg) {
- case 0:
- switch (cop) {
- case 0:
- return env->cp0.c0_cpuid;
- case 1:
- return env->cp0.c0_cachetype;
- }
- break;
- case 1:
- if (cop == 0) {
- return env->cp0.c1_sys;
- }
- break;
- case 2:
- if (cop == 0) {
- return env->cp0.c2_base;
- }
- break;
- case 3:
- if (cop == 0) {
- return env->cp0.c3_faultstatus;
- }
- break;
- case 4:
- if (cop == 0) {
- return env->cp0.c4_faultaddr;
- }
- break;
- }
- qemu_log_mask(LOG_GUEST_ERROR,
- "Wrong register (%d) or wrong operation (%d) in cp0_set!\n",
- creg, cop);
- return 0;
-}
-
-void helper_cp1_putc(target_ulong regval)
-{
- const char c = regval;
-
- qemu_semihosting_log_out(&c, sizeof(c));
-}
-#endif /* !CONFIG_USER_ONLY */
-
-bool uc32_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- UniCore32CPU *cpu = UNICORE32_CPU(cs);
- CPUUniCore32State *env = &cpu->env;
-
- if (!(env->uncached_asr & ASR_I)) {
- cs->exception_index = UC32_EXCP_INTR;
- uc32_cpu_do_interrupt(cs);
- return true;
- }
- }
- return false;
-}
diff --git a/target/unicore32/helper.h b/target/unicore32/helper.h
deleted file mode 100644
index a4a5d45d1d..0000000000
--- a/target/unicore32/helper.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-
-#ifndef CONFIG_USER_ONLY
-DEF_HELPER_4(cp0_set, void, env, i32, i32, i32)
-DEF_HELPER_3(cp0_get, i32, env, i32, i32)
-DEF_HELPER_1(cp1_putc, void, i32)
-#endif
-
-DEF_HELPER_2(exception, void, env, i32)
-
-DEF_HELPER_3(asr_write, void, env, i32, i32)
-DEF_HELPER_1(asr_read, i32, env)
-
-DEF_HELPER_2(get_user_reg, i32, env, i32)
-DEF_HELPER_3(set_user_reg, void, env, i32, i32)
-
-DEF_HELPER_3(add_cc, i32, env, i32, i32)
-DEF_HELPER_3(adc_cc, i32, env, i32, i32)
-DEF_HELPER_3(sub_cc, i32, env, i32, i32)
-DEF_HELPER_3(sbc_cc, i32, env, i32, i32)
-
-DEF_HELPER_2(shl, i32, i32, i32)
-DEF_HELPER_2(shr, i32, i32, i32)
-DEF_HELPER_2(sar, i32, i32, i32)
-DEF_HELPER_3(shl_cc, i32, env, i32, i32)
-DEF_HELPER_3(shr_cc, i32, env, i32, i32)
-DEF_HELPER_3(sar_cc, i32, env, i32, i32)
-DEF_HELPER_3(ror_cc, i32, env, i32, i32)
-
-DEF_HELPER_1(ucf64_get_fpscr, i32, env)
-DEF_HELPER_2(ucf64_set_fpscr, void, env, i32)
-
-DEF_HELPER_3(ucf64_adds, f32, f32, f32, env)
-DEF_HELPER_3(ucf64_addd, f64, f64, f64, env)
-DEF_HELPER_3(ucf64_subs, f32, f32, f32, env)
-DEF_HELPER_3(ucf64_subd, f64, f64, f64, env)
-DEF_HELPER_3(ucf64_muls, f32, f32, f32, env)
-DEF_HELPER_3(ucf64_muld, f64, f64, f64, env)
-DEF_HELPER_3(ucf64_divs, f32, f32, f32, env)
-DEF_HELPER_3(ucf64_divd, f64, f64, f64, env)
-DEF_HELPER_1(ucf64_negs, f32, f32)
-DEF_HELPER_1(ucf64_negd, f64, f64)
-DEF_HELPER_1(ucf64_abss, f32, f32)
-DEF_HELPER_1(ucf64_absd, f64, f64)
-DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env)
-DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env)
-
-DEF_HELPER_2(ucf64_sf2df, f64, f32, env)
-DEF_HELPER_2(ucf64_df2sf, f32, f64, env)
-
-DEF_HELPER_2(ucf64_si2sf, f32, f32, env)
-DEF_HELPER_2(ucf64_si2df, f64, f32, env)
-
-DEF_HELPER_2(ucf64_sf2si, f32, f32, env)
-DEF_HELPER_2(ucf64_df2si, f32, f64, env)
diff --git a/target/unicore32/meson.build b/target/unicore32/meson.build
deleted file mode 100644
index 0fa78772eb..0000000000
--- a/target/unicore32/meson.build
+++ /dev/null
@@ -1,14 +0,0 @@
-unicore32_ss = ss.source_set()
-unicore32_ss.add(files(
- 'cpu.c',
- 'helper.c',
- 'op_helper.c',
- 'translate.c',
- 'ucf64_helper.c',
-), curses)
-
-unicore32_softmmu_ss = ss.source_set()
-unicore32_softmmu_ss.add(files('softmmu.c'))
-
-target_arch += {'unicore32': unicore32_ss}
-target_softmmu_arch += {'unicore32': unicore32_softmmu_ss}
diff --git a/target/unicore32/op_helper.c b/target/unicore32/op_helper.c
deleted file mode 100644
index eeaa78601a..0000000000
--- a/target/unicore32/op_helper.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * UniCore32 helper routines
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-
-#define SIGNBIT (uint32_t)0x80000000
-#define SIGNBIT64 ((uint64_t)1 << 63)
-
-void HELPER(exception)(CPUUniCore32State *env, uint32_t excp)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = excp;
- cpu_loop_exit(cs);
-}
-
-static target_ulong asr_read(CPUUniCore32State *env)
-{
- int ZF;
- ZF = (env->ZF == 0);
- return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) |
- (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
-}
-
-target_ulong cpu_asr_read(CPUUniCore32State *env)
-{
- return asr_read(env);
-}
-
-target_ulong HELPER(asr_read)(CPUUniCore32State *env)
-{
- return asr_read(env);
-}
-
-static void asr_write(CPUUniCore32State *env, target_ulong val,
- target_ulong mask)
-{
- if (mask & ASR_NZCV) {
- env->ZF = (~val) & ASR_Z;
- env->NF = val;
- env->CF = (val >> 29) & 1;
- env->VF = (val << 3) & 0x80000000;
- }
-
- if ((env->uncached_asr ^ val) & mask & ASR_M) {
- switch_mode(env, val & ASR_M);
- }
- mask &= ~ASR_NZCV;
- env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask);
-}
-
-void cpu_asr_write(CPUUniCore32State *env, target_ulong val, target_ulong mask)
-{
- asr_write(env, val, mask);
-}
-
-void HELPER(asr_write)(CPUUniCore32State *env, target_ulong val,
- target_ulong mask)
-{
- asr_write(env, val, mask);
-}
-
-/* Access to user mode registers from privileged modes. */
-uint32_t HELPER(get_user_reg)(CPUUniCore32State *env, uint32_t regno)
-{
- uint32_t val;
-
- if (regno == 29) {
- val = env->banked_r29[0];
- } else if (regno == 30) {
- val = env->banked_r30[0];
- } else {
- val = env->regs[regno];
- }
- return val;
-}
-
-void HELPER(set_user_reg)(CPUUniCore32State *env, uint32_t regno, uint32_t val)
-{
- if (regno == 29) {
- env->banked_r29[0] = val;
- } else if (regno == 30) {
- env->banked_r30[0] = val;
- } else {
- env->regs[regno] = val;
- }
-}
-
-/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
- The only way to do that in TCG is a conditional branch, which clobbers
- all our temporaries. For now implement these as helper functions. */
-
-uint32_t HELPER(add_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- result = a + b;
- env->NF = env->ZF = result;
- env->CF = result < a;
- env->VF = (a ^ b ^ -1) & (a ^ result);
- return result;
-}
-
-uint32_t HELPER(adc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- if (!env->CF) {
- result = a + b;
- env->CF = result < a;
- } else {
- result = a + b + 1;
- env->CF = result <= a;
- }
- env->VF = (a ^ b ^ -1) & (a ^ result);
- env->NF = env->ZF = result;
- return result;
-}
-
-uint32_t HELPER(sub_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- result = a - b;
- env->NF = env->ZF = result;
- env->CF = a >= b;
- env->VF = (a ^ b) & (a ^ result);
- return result;
-}
-
-uint32_t HELPER(sbc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b)
-{
- uint32_t result;
- if (!env->CF) {
- result = a - b - 1;
- env->CF = a > b;
- } else {
- result = a - b;
- env->CF = a >= b;
- }
- env->VF = (a ^ b) & (a ^ result);
- env->NF = env->ZF = result;
- return result;
-}
-
-/* Similarly for variable shift instructions. */
-
-uint32_t HELPER(shl)(uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- return 0;
- }
- return x << shift;
-}
-
-uint32_t HELPER(shr)(uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- return 0;
- }
- return (uint32_t)x >> shift;
-}
-
-uint32_t HELPER(sar)(uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- shift = 31;
- }
- return (int32_t)x >> shift;
-}
-
-uint32_t HELPER(shl_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- if (shift == 32) {
- env->CF = x & 1;
- } else {
- env->CF = 0;
- }
- return 0;
- } else if (shift != 0) {
- env->CF = (x >> (32 - shift)) & 1;
- return x << shift;
- }
- return x;
-}
-
-uint32_t HELPER(shr_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- if (shift == 32) {
- env->CF = (x >> 31) & 1;
- } else {
- env->CF = 0;
- }
- return 0;
- } else if (shift != 0) {
- env->CF = (x >> (shift - 1)) & 1;
- return x >> shift;
- }
- return x;
-}
-
-uint32_t HELPER(sar_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
-{
- int shift = i & 0xff;
- if (shift >= 32) {
- env->CF = (x >> 31) & 1;
- return (int32_t)x >> 31;
- } else if (shift != 0) {
- env->CF = (x >> (shift - 1)) & 1;
- return (int32_t)x >> shift;
- }
- return x;
-}
-
-uint32_t HELPER(ror_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i)
-{
- int shift1, shift;
- shift1 = i & 0xff;
- shift = shift1 & 0x1f;
- if (shift == 0) {
- if (shift1 != 0) {
- env->CF = (x >> 31) & 1;
- }
- return x;
- } else {
- env->CF = (x >> (shift - 1)) & 1;
- return ((uint32_t)x >> shift) | (x << (32 - shift));
- }
-}
diff --git a/target/unicore32/softmmu.c b/target/unicore32/softmmu.c
deleted file mode 100644
index cbdaa500b7..0000000000
--- a/target/unicore32/softmmu.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Softmmu related functions
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#ifdef CONFIG_USER_ONLY
-#error This file only exist under softmmu circumstance
-#endif
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "qemu/error-report.h"
-
-#undef DEBUG_UC32
-
-#ifdef DEBUG_UC32
-#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define SUPERPAGE_SIZE (1 << 22)
-#define UC32_PAGETABLE_READ (1 << 8)
-#define UC32_PAGETABLE_WRITE (1 << 7)
-#define UC32_PAGETABLE_EXEC (1 << 6)
-#define UC32_PAGETABLE_EXIST (1 << 2)
-#define PAGETABLE_TYPE(x) ((x) & 3)
-
-
-/* Map CPU modes onto saved register banks. */
-static inline int bank_number(CPUUniCore32State *env, int mode)
-{
- switch (mode) {
- case ASR_MODE_USER:
- case ASR_MODE_SUSR:
- return 0;
- case ASR_MODE_PRIV:
- return 1;
- case ASR_MODE_TRAP:
- return 2;
- case ASR_MODE_EXTN:
- return 3;
- case ASR_MODE_INTR:
- return 4;
- }
- cpu_abort(env_cpu(env), "Bad mode %x\n", mode);
- return -1;
-}
-
-void switch_mode(CPUUniCore32State *env, int mode)
-{
- int old_mode;
- int i;
-
- old_mode = env->uncached_asr & ASR_M;
- if (mode == old_mode) {
- return;
- }
-
- i = bank_number(env, old_mode);
- env->banked_r29[i] = env->regs[29];
- env->banked_r30[i] = env->regs[30];
- env->banked_bsr[i] = env->bsr;
-
- i = bank_number(env, mode);
- env->regs[29] = env->banked_r29[i];
- env->regs[30] = env->banked_r30[i];
- env->bsr = env->banked_bsr[i];
-}
-
-/* Handle a CPU exception. */
-void uc32_cpu_do_interrupt(CPUState *cs)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(cs);
- CPUUniCore32State *env = &cpu->env;
- uint32_t addr;
- int new_mode;
-
- switch (cs->exception_index) {
- case UC32_EXCP_PRIV:
- new_mode = ASR_MODE_PRIV;
- addr = 0x08;
- break;
- case UC32_EXCP_ITRAP:
- DPRINTF("itrap happened at %x\n", env->regs[31]);
- new_mode = ASR_MODE_TRAP;
- addr = 0x0c;
- break;
- case UC32_EXCP_DTRAP:
- DPRINTF("dtrap happened at %x\n", env->regs[31]);
- new_mode = ASR_MODE_TRAP;
- addr = 0x10;
- break;
- case UC32_EXCP_INTR:
- new_mode = ASR_MODE_INTR;
- addr = 0x18;
- break;
- default:
- cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
- return;
- }
- /* High vectors. */
- if (env->cp0.c1_sys & (1 << 13)) {
- addr += 0xffff0000;
- }
-
- switch_mode(env, new_mode);
- env->bsr = cpu_asr_read(env);
- env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode;
- env->uncached_asr |= ASR_I;
- /* The PC already points to the proper instruction. */
- env->regs[30] = env->regs[31];
- env->regs[31] = addr;
- cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
-}
-
-static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address,
- int access_type, int is_user, uint32_t *phys_ptr, int *prot,
- target_ulong *page_size)
-{
- CPUState *cs = env_cpu(env);
- int code;
- uint32_t table;
- uint32_t desc;
- uint32_t phys_addr;
-
- /* Pagetable walk. */
- /* Lookup l1 descriptor. */
- table = env->cp0.c2_base & 0xfffff000;
- table |= (address >> 20) & 0xffc;
- desc = ldl_phys(cs->as, table);
- code = 0;
- switch (PAGETABLE_TYPE(desc)) {
- case 3:
- /* Superpage */
- if (!(desc & UC32_PAGETABLE_EXIST)) {
- code = 0x0b; /* superpage miss */
- goto do_fault;
- }
- phys_addr = (desc & 0xffc00000) | (address & 0x003fffff);
- *page_size = SUPERPAGE_SIZE;
- break;
- case 0:
- /* Lookup l2 entry. */
- if (is_user) {
- DPRINTF("PGD address %x, desc %x\n", table, desc);
- }
- if (!(desc & UC32_PAGETABLE_EXIST)) {
- code = 0x05; /* second pagetable miss */
- goto do_fault;
- }
- table = (desc & 0xfffff000) | ((address >> 10) & 0xffc);
- desc = ldl_phys(cs->as, table);
- /* 4k page. */
- if (is_user) {
- DPRINTF("PTE address %x, desc %x\n", table, desc);
- }
- if (!(desc & UC32_PAGETABLE_EXIST)) {
- code = 0x08; /* page miss */
- goto do_fault;
- }
- switch (PAGETABLE_TYPE(desc)) {
- case 0:
- phys_addr = (desc & 0xfffff000) | (address & 0xfff);
- *page_size = TARGET_PAGE_SIZE;
- break;
- default:
- cpu_abort(cs, "wrong page type!");
- }
- break;
- default:
- cpu_abort(cs, "wrong page type!");
- }
-
- *phys_ptr = phys_addr;
- *prot = 0;
- /* Check access permissions. */
- if (desc & UC32_PAGETABLE_READ) {
- *prot |= PAGE_READ;
- } else {
- if (is_user && (access_type == 0)) {
- code = 0x11; /* access unreadable area */
- goto do_fault;
- }
- }
-
- if (desc & UC32_PAGETABLE_WRITE) {
- *prot |= PAGE_WRITE;
- } else {
- if (is_user && (access_type == 1)) {
- code = 0x12; /* access unwritable area */
- goto do_fault;
- }
- }
-
- if (desc & UC32_PAGETABLE_EXEC) {
- *prot |= PAGE_EXEC;
- } else {
- if (is_user && (access_type == 2)) {
- code = 0x13; /* access unexecutable area */
- goto do_fault;
- }
- }
-
-do_fault:
- return code;
-}
-
-bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(cs);
- CPUUniCore32State *env = &cpu->env;
- uint32_t phys_addr;
- target_ulong page_size;
- int prot;
- int ret, is_user;
-
- ret = 1;
- is_user = mmu_idx == MMU_USER_IDX;
-
- if ((env->cp0.c1_sys & 1) == 0) {
- /* MMU disabled. */
- phys_addr = address;
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- page_size = TARGET_PAGE_SIZE;
- ret = 0;
- } else {
- if ((address & (1 << 31)) || (is_user)) {
- ret = get_phys_addr_ucv2(env, address, access_type, is_user,
- &phys_addr, &prot, &page_size);
- if (is_user) {
- DPRINTF("user space access: ret %x, address %" VADDR_PRIx ", "
- "access_type %x, phys_addr %x, prot %x\n",
- ret, address, access_type, phys_addr, prot);
- }
- } else {
- /*IO memory */
- phys_addr = address | (1 << 31);
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- page_size = TARGET_PAGE_SIZE;
- ret = 0;
- }
- }
-
- if (ret == 0) {
- /* Map a single page. */
- phys_addr &= TARGET_PAGE_MASK;
- address &= TARGET_PAGE_MASK;
- tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
- return true;
- }
-
- if (probe) {
- return false;
- }
-
- env->cp0.c3_faultstatus = ret;
- env->cp0.c4_faultaddr = address;
- if (access_type == 2) {
- cs->exception_index = UC32_EXCP_ITRAP;
- } else {
- cs->exception_index = UC32_EXCP_DTRAP;
- }
- cpu_loop_exit_restore(cs, retaddr);
-}
-
-hwaddr uc32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- error_report("function uc32_cpu_get_phys_page_debug not "
- "implemented, aborting");
- return -1;
-}
diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c
deleted file mode 100644
index 370709c9ea..0000000000
--- a/target/unicore32/translate.c
+++ /dev/null
@@ -1,2083 +0,0 @@
-/*
- * UniCore32 translation
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or (at your option) any
- * later version. See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "disas/disas.h"
-#include "exec/exec-all.h"
-#include "tcg/tcg-op.h"
-#include "qemu/log.h"
-#include "exec/cpu_ldst.h"
-#include "exec/translator.h"
-#include "qemu/qemu-print.h"
-
-#include "exec/helper-proto.h"
-#include "exec/helper-gen.h"
-
-#include "trace-tcg.h"
-#include "exec/log.h"
-
-
-/* internal defines */
-typedef struct DisasContext {
- target_ulong pc;
- int is_jmp;
- /* Nonzero if this instruction has been conditionally skipped. */
- int condjmp;
- /* The label that will be jumped to when the instruction is skipped. */
- TCGLabel *condlabel;
- TranslationBlock *tb;
- int singlestep_enabled;
-#ifndef CONFIG_USER_ONLY
- int user;
-#endif
-} DisasContext;
-
-#ifndef CONFIG_USER_ONLY
-#define IS_USER(s) (s->user)
-#else
-#define IS_USER(s) 1
-#endif
-
-/* is_jmp field values */
-#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
-#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
-#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */
-/* These instructions trap after executing, so defer them until after the
- conditional executions state has been updated. */
-#define DISAS_SYSCALL DISAS_TARGET_3
-
-static TCGv_i32 cpu_R[32];
-
-/* FIXME: These should be removed. */
-static TCGv cpu_F0s, cpu_F1s;
-static TCGv_i64 cpu_F0d, cpu_F1d;
-
-#include "exec/gen-icount.h"
-
-static const char *regnames[] = {
- "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07",
- "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" };
-
-/* initialize TCG globals. */
-void uc32_translate_init(void)
-{
- int i;
-
- for (i = 0; i < 32; i++) {
- cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
- offsetof(CPUUniCore32State, regs[i]), regnames[i]);
- }
-}
-
-static int num_temps;
-
-/* Allocate a temporary variable. */
-static TCGv_i32 new_tmp(void)
-{
- num_temps++;
- return tcg_temp_new_i32();
-}
-
-/* Release a temporary variable. */
-static void dead_tmp(TCGv tmp)
-{
- tcg_temp_free(tmp);
- num_temps--;
-}
-
-static inline TCGv load_cpu_offset(int offset)
-{
- TCGv tmp = new_tmp();
- tcg_gen_ld_i32(tmp, cpu_env, offset);
- return tmp;
-}
-
-#define load_cpu_field(name) load_cpu_offset(offsetof(CPUUniCore32State, name))
-
-static inline void store_cpu_offset(TCGv var, int offset)
-{
- tcg_gen_st_i32(var, cpu_env, offset);
- dead_tmp(var);
-}
-
-#define store_cpu_field(var, name) \
- store_cpu_offset(var, offsetof(CPUUniCore32State, name))
-
-/* Set a variable to the value of a CPU register. */
-static void load_reg_var(DisasContext *s, TCGv var, int reg)
-{
- if (reg == 31) {
- uint32_t addr;
- /* normaly, since we updated PC */
- addr = (long)s->pc;
- tcg_gen_movi_i32(var, addr);
- } else {
- tcg_gen_mov_i32(var, cpu_R[reg]);
- }
-}
-
-/* Create a new temporary and set it to the value of a CPU register. */
-static inline TCGv load_reg(DisasContext *s, int reg)
-{
- TCGv tmp = new_tmp();
- load_reg_var(s, tmp, reg);
- return tmp;
-}
-
-/* Set a CPU register. The source must be a temporary and will be
- marked as dead. */
-static void store_reg(DisasContext *s, int reg, TCGv var)
-{
- if (reg == 31) {
- tcg_gen_andi_i32(var, var, ~3);
- s->is_jmp = DISAS_JUMP;
- }
- tcg_gen_mov_i32(cpu_R[reg], var);
- dead_tmp(var);
-}
-
-/* Value extensions. */
-#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
-#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
-#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
-#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
-
-#define UCOP_REG_M (((insn) >> 0) & 0x1f)
-#define UCOP_REG_N (((insn) >> 19) & 0x1f)
-#define UCOP_REG_D (((insn) >> 14) & 0x1f)
-#define UCOP_REG_S (((insn) >> 9) & 0x1f)
-#define UCOP_REG_LO (((insn) >> 14) & 0x1f)
-#define UCOP_REG_HI (((insn) >> 9) & 0x1f)
-#define UCOP_SH_OP (((insn) >> 6) & 0x03)
-#define UCOP_SH_IM (((insn) >> 9) & 0x1f)
-#define UCOP_OPCODES (((insn) >> 25) & 0x0f)
-#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff)
-#define UCOP_IMM10 (((insn) >> 0) & 0x3ff)
-#define UCOP_IMM14 (((insn) >> 0) & 0x3fff)
-#define UCOP_COND (((insn) >> 25) & 0x0f)
-#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f)
-#define UCOP_CPNUM (((insn) >> 10) & 0x0f)
-#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03)
-#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f)
-#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f)
-
-#define UCOP_SET(i) ((insn) & (1 << (i)))
-#define UCOP_SET_P UCOP_SET(28)
-#define UCOP_SET_U UCOP_SET(27)
-#define UCOP_SET_B UCOP_SET(26)
-#define UCOP_SET_W UCOP_SET(25)
-#define UCOP_SET_L UCOP_SET(24)
-#define UCOP_SET_S UCOP_SET(24)
-
-#define ILLEGAL cpu_abort(env_cpu(env), \
- "Illegal UniCore32 instruction %x at line %d!", \
- insn, __LINE__)
-
-#ifndef CONFIG_USER_ONLY
-static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s,
- uint32_t insn)
-{
- TCGv tmp, tmp2, tmp3;
- if ((insn & 0xfe000000) == 0xe0000000) {
- tmp2 = new_tmp();
- tmp3 = new_tmp();
- tcg_gen_movi_i32(tmp2, UCOP_REG_N);
- tcg_gen_movi_i32(tmp3, UCOP_IMM10);
- if (UCOP_SET_L) {
- tmp = new_tmp();
- gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3);
- store_reg(s, UCOP_REG_D, tmp);
- } else {
- tmp = load_reg(s, UCOP_REG_D);
- gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3);
- dead_tmp(tmp);
- }
- dead_tmp(tmp2);
- dead_tmp(tmp3);
- return;
- }
- ILLEGAL;
-}
-
-static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s,
- uint32_t insn)
-{
- TCGv tmp;
-
- if ((insn & 0xff003fff) == 0xe1000400) {
- /*
- * movc rd, pp.nn, #imm9
- * rd: UCOP_REG_D
- * nn: UCOP_REG_N (must be 0)
- * imm9: 0
- */
- if (UCOP_REG_N == 0) {
- tmp = new_tmp();
- tcg_gen_movi_i32(tmp, 0);
- store_reg(s, UCOP_REG_D, tmp);
- return;
- } else {
- ILLEGAL;
- }
- }
- if ((insn & 0xff003fff) == 0xe0000401) {
- /*
- * movc pp.nn, rn, #imm9
- * rn: UCOP_REG_D
- * nn: UCOP_REG_N (must be 1)
- * imm9: 1
- */
- if (UCOP_REG_N == 1) {
- tmp = load_reg(s, UCOP_REG_D);
- gen_helper_cp1_putc(tmp);
- dead_tmp(tmp);
- return;
- } else {
- ILLEGAL;
- }
- }
- ILLEGAL;
-}
-#endif
-
-static inline void gen_set_asr(TCGv var, uint32_t mask)
-{
- TCGv tmp_mask = tcg_const_i32(mask);
- gen_helper_asr_write(cpu_env, var, tmp_mask);
- tcg_temp_free_i32(tmp_mask);
-}
-/* Set NZCV flags from the high 4 bits of var. */
-#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV)
-
-static void gen_exception(int excp)
-{
- TCGv tmp = new_tmp();
- tcg_gen_movi_i32(tmp, excp);
- gen_helper_exception(cpu_env, tmp);
- dead_tmp(tmp);
-}
-
-#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF))
-
-/* Set CF to the top bit of var. */
-static void gen_set_CF_bit31(TCGv var)
-{
- TCGv tmp = new_tmp();
- tcg_gen_shri_i32(tmp, var, 31);
- gen_set_CF(tmp);
- dead_tmp(tmp);
-}
-
-/* Set N and Z flags from var. */
-static inline void gen_logic_CC(TCGv var)
-{
- tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, NF));
- tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, ZF));
-}
-
-/* dest = T0 + T1 + CF. */
-static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
-{
- TCGv tmp;
- tcg_gen_add_i32(dest, t0, t1);
- tmp = load_cpu_field(CF);
- tcg_gen_add_i32(dest, dest, tmp);
- dead_tmp(tmp);
-}
-
-/* dest = T0 - T1 + CF - 1. */
-static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
-{
- TCGv tmp;
- tcg_gen_sub_i32(dest, t0, t1);
- tmp = load_cpu_field(CF);
- tcg_gen_add_i32(dest, dest, tmp);
- tcg_gen_subi_i32(dest, dest, 1);
- dead_tmp(tmp);
-}
-
-static void shifter_out_im(TCGv var, int shift)
-{
- TCGv tmp = new_tmp();
- if (shift == 0) {
- tcg_gen_andi_i32(tmp, var, 1);
- } else {
- tcg_gen_shri_i32(tmp, var, shift);
- if (shift != 31) {
- tcg_gen_andi_i32(tmp, tmp, 1);
- }
- }
- gen_set_CF(tmp);
- dead_tmp(tmp);
-}
-
-/* Shift by immediate. Includes special handling for shift == 0. */
-static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift,
- int flags)
-{
- switch (shiftop) {
- case 0: /* LSL */
- if (shift != 0) {
- if (flags) {
- shifter_out_im(var, 32 - shift);
- }
- tcg_gen_shli_i32(var, var, shift);
- }
- break;
- case 1: /* LSR */
- if (shift == 0) {
- if (flags) {
- tcg_gen_shri_i32(var, var, 31);
- gen_set_CF(var);
- }
- tcg_gen_movi_i32(var, 0);
- } else {
- if (flags) {
- shifter_out_im(var, shift - 1);
- }
- tcg_gen_shri_i32(var, var, shift);
- }
- break;
- case 2: /* ASR */
- if (shift == 0) {
- shift = 32;
- }
- if (flags) {
- shifter_out_im(var, shift - 1);
- }
- if (shift == 32) {
- shift = 31;
- }
- tcg_gen_sari_i32(var, var, shift);
- break;
- case 3: /* ROR/RRX */
- if (shift != 0) {
- if (flags) {
- shifter_out_im(var, shift - 1);
- }
- tcg_gen_rotri_i32(var, var, shift); break;
- } else {
- TCGv tmp = load_cpu_field(CF);
- if (flags) {
- shifter_out_im(var, 0);
- }
- tcg_gen_shri_i32(var, var, 1);
- tcg_gen_shli_i32(tmp, tmp, 31);
- tcg_gen_or_i32(var, var, tmp);
- dead_tmp(tmp);
- }
- }
-};
-
-static inline void gen_uc32_shift_reg(TCGv var, int shiftop,
- TCGv shift, int flags)
-{
- if (flags) {
- switch (shiftop) {
- case 0:
- gen_helper_shl_cc(var, cpu_env, var, shift);
- break;
- case 1:
- gen_helper_shr_cc(var, cpu_env, var, shift);
- break;
- case 2:
- gen_helper_sar_cc(var, cpu_env, var, shift);
- break;
- case 3:
- gen_helper_ror_cc(var, cpu_env, var, shift);
- break;
- }
- } else {
- switch (shiftop) {
- case 0:
- gen_helper_shl(var, var, shift);
- break;
- case 1:
- gen_helper_shr(var, var, shift);
- break;
- case 2:
- gen_helper_sar(var, var, shift);
- break;
- case 3:
- tcg_gen_andi_i32(shift, shift, 0x1f);
- tcg_gen_rotr_i32(var, var, shift);
- break;
- }
- }
- dead_tmp(shift);
-}
-
-static void gen_test_cc(int cc, TCGLabel *label)
-{
- TCGv tmp;
- TCGv tmp2;
- TCGLabel *inv;
-
- switch (cc) {
- case 0: /* eq: Z */
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
- break;
- case 1: /* ne: !Z */
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
- break;
- case 2: /* cs: C */
- tmp = load_cpu_field(CF);
- tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
- break;
- case 3: /* cc: !C */
- tmp = load_cpu_field(CF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
- break;
- case 4: /* mi: N */
- tmp = load_cpu_field(NF);
- tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
- break;
- case 5: /* pl: !N */
- tmp = load_cpu_field(NF);
- tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
- break;
- case 6: /* vs: V */
- tmp = load_cpu_field(VF);
- tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
- break;
- case 7: /* vc: !V */
- tmp = load_cpu_field(VF);
- tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
- break;
- case 8: /* hi: C && !Z */
- inv = gen_new_label();
- tmp = load_cpu_field(CF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
- dead_tmp(tmp);
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
- gen_set_label(inv);
- break;
- case 9: /* ls: !C || Z */
- tmp = load_cpu_field(CF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
- dead_tmp(tmp);
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
- break;
- case 10: /* ge: N == V -> N ^ V == 0 */
- tmp = load_cpu_field(VF);
- tmp2 = load_cpu_field(NF);
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
- break;
- case 11: /* lt: N != V -> N ^ V != 0 */
- tmp = load_cpu_field(VF);
- tmp2 = load_cpu_field(NF);
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
- break;
- case 12: /* gt: !Z && N == V */
- inv = gen_new_label();
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
- dead_tmp(tmp);
- tmp = load_cpu_field(VF);
- tmp2 = load_cpu_field(NF);
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
- gen_set_label(inv);
- break;
- case 13: /* le: Z || N != V */
- tmp = load_cpu_field(ZF);
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
- dead_tmp(tmp);
- tmp = load_cpu_field(VF);
- tmp2 = load_cpu_field(NF);
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
- break;
- default:
- fprintf(stderr, "Bad condition code 0x%x\n", cc);
- abort();
- }
- dead_tmp(tmp);
-}
-
-static const uint8_t table_logic_cc[16] = {
- 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */
- 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */
- 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */
- 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */
-};
-
-/* Set PC state from an immediate address. */
-static inline void gen_bx_im(DisasContext *s, uint32_t addr)
-{
- s->is_jmp = DISAS_UPDATE;
- tcg_gen_movi_i32(cpu_R[31], addr & ~3);
-}
-
-/* Set PC state from var. var is marked as dead. */
-static inline void gen_bx(DisasContext *s, TCGv var)
-{
- s->is_jmp = DISAS_UPDATE;
- tcg_gen_andi_i32(cpu_R[31], var, ~3);
- dead_tmp(var);
-}
-
-static inline void store_reg_bx(DisasContext *s, int reg, TCGv var)
-{
- store_reg(s, reg, var);
-}
-
-static inline TCGv gen_ld8s(TCGv addr, int index)
-{
- TCGv tmp = new_tmp();
- tcg_gen_qemu_ld8s(tmp, addr, index);
- return tmp;
-}
-
-static inline TCGv gen_ld8u(TCGv addr, int index)
-{
- TCGv tmp = new_tmp();
- tcg_gen_qemu_ld8u(tmp, addr, index);
- return tmp;
-}
-
-static inline TCGv gen_ld16s(TCGv addr, int index)
-{
- TCGv tmp = new_tmp();
- tcg_gen_qemu_ld16s(tmp, addr, index);
- return tmp;
-}
-
-static inline TCGv gen_ld16u(TCGv addr, int index)
-{
- TCGv tmp = new_tmp();
- tcg_gen_qemu_ld16u(tmp, addr, index);
- return tmp;
-}
-
-static inline TCGv gen_ld32(TCGv addr, int index)
-{
- TCGv tmp = new_tmp();
- tcg_gen_qemu_ld32u(tmp, addr, index);
- return tmp;
-}
-
-static inline void gen_st8(TCGv val, TCGv addr, int index)
-{
- tcg_gen_qemu_st8(val, addr, index);
- dead_tmp(val);
-}
-
-static inline void gen_st16(TCGv val, TCGv addr, int index)
-{
- tcg_gen_qemu_st16(val, addr, index);
- dead_tmp(val);
-}
-
-static inline void gen_st32(TCGv val, TCGv addr, int index)
-{
- tcg_gen_qemu_st32(val, addr, index);
- dead_tmp(val);
-}
-
-static inline void gen_set_pc_im(uint32_t val)
-{
- tcg_gen_movi_i32(cpu_R[31], val);
-}
-
-/* Force a TB lookup after an instruction that changes the CPU state. */
-static inline void gen_lookup_tb(DisasContext *s)
-{
- tcg_gen_movi_i32(cpu_R[31], s->pc & ~1);
- s->is_jmp = DISAS_UPDATE;
-}
-
-static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
- TCGv var)
-{
- int val;
- TCGv offset;
-
- if (UCOP_SET(29)) {
- /* immediate */
- val = UCOP_IMM14;
- if (!UCOP_SET_U) {
- val = -val;
- }
- if (val != 0) {
- tcg_gen_addi_i32(var, var, val);
- }
- } else {
- /* shift/register */
- offset = load_reg(s, UCOP_REG_M);
- gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0);
- if (!UCOP_SET_U) {
- tcg_gen_sub_i32(var, var, offset);
- } else {
- tcg_gen_add_i32(var, var, offset);
- }
- dead_tmp(offset);
- }
-}
-
-static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
- TCGv var)
-{
- int val;
- TCGv offset;
-
- if (UCOP_SET(26)) {
- /* immediate */
- val = (insn & 0x1f) | ((insn >> 4) & 0x3e0);
- if (!UCOP_SET_U) {
- val = -val;
- }
- if (val != 0) {
- tcg_gen_addi_i32(var, var, val);
- }
- } else {
- /* register */
- offset = load_reg(s, UCOP_REG_M);
- if (!UCOP_SET_U) {
- tcg_gen_sub_i32(var, var, offset);
- } else {
- tcg_gen_add_i32(var, var, offset);
- }
- dead_tmp(offset);
- }
-}
-
-static inline long ucf64_reg_offset(int reg)
-{
- if (reg & 1) {
- return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
- + offsetof(CPU_DoubleU, l.upper);
- } else {
- return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1])
- + offsetof(CPU_DoubleU, l.lower);
- }
-}
-
-#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg))
-#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg))
-
-/* UniCore-F64 single load/store I_offset */
-static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- int offset;
- TCGv tmp;
- TCGv addr;
-
- addr = load_reg(s, UCOP_REG_N);
- if (!UCOP_SET_P && !UCOP_SET_W) {
- ILLEGAL;
- }
-
- if (UCOP_SET_P) {
- offset = UCOP_IMM10 << 2;
- if (!UCOP_SET_U) {
- offset = -offset;
- }
- if (offset != 0) {
- tcg_gen_addi_i32(addr, addr, offset);
- }
- }
-
- if (UCOP_SET_L) { /* load */
- tmp = gen_ld32(addr, IS_USER(s));
- ucf64_gen_st32(tmp, UCOP_REG_D);
- } else { /* store */
- tmp = ucf64_gen_ld32(UCOP_REG_D);
- gen_st32(tmp, addr, IS_USER(s));
- }
-
- if (!UCOP_SET_P) {
- offset = UCOP_IMM10 << 2;
- if (!UCOP_SET_U) {
- offset = -offset;
- }
- if (offset != 0) {
- tcg_gen_addi_i32(addr, addr, offset);
- }
- }
- if (UCOP_SET_W) {
- store_reg(s, UCOP_REG_N, addr);
- } else {
- dead_tmp(addr);
- }
-}
-
-/* UniCore-F64 load/store multiple words */
-static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- unsigned int i;
- int j, n, freg;
- TCGv tmp;
- TCGv addr;
-
- if (UCOP_REG_D != 0) {
- ILLEGAL;
- }
- if (UCOP_REG_N == 31) {
- ILLEGAL;
- }
- if ((insn << 24) == 0) {
- ILLEGAL;
- }
-
- addr = load_reg(s, UCOP_REG_N);
-
- n = 0;
- for (i = 0; i < 8; i++) {
- if (UCOP_SET(i)) {
- n++;
- }
- }
-
- if (UCOP_SET_U) {
- if (UCOP_SET_P) { /* pre increment */
- tcg_gen_addi_i32(addr, addr, 4);
- } /* unnecessary to do anything when post increment */
- } else {
- if (UCOP_SET_P) { /* pre decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- } else { /* post decrement */
- if (n != 1) {
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- }
- }
- }
-
- freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */
-
- for (i = 0, j = 0; i < 8; i++, freg++) {
- if (!UCOP_SET(i)) {
- continue;
- }
-
- if (UCOP_SET_L) { /* load */
- tmp = gen_ld32(addr, IS_USER(s));
- ucf64_gen_st32(tmp, freg);
- } else { /* store */
- tmp = ucf64_gen_ld32(freg);
- gen_st32(tmp, addr, IS_USER(s));
- }
-
- j++;
- /* unnecessary to add after the last transfer */
- if (j != n) {
- tcg_gen_addi_i32(addr, addr, 4);
- }
- }
-
- if (UCOP_SET_W) { /* write back */
- if (UCOP_SET_U) {
- if (!UCOP_SET_P) { /* post increment */
- tcg_gen_addi_i32(addr, addr, 4);
- } /* unnecessary to do anything when pre increment */
- } else {
- if (UCOP_SET_P) {
- /* pre decrement */
- if (n != 1) {
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- }
- } else {
- /* post decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- }
- }
- store_reg(s, UCOP_REG_N, addr);
- } else {
- dead_tmp(addr);
- }
-}
-
-/* UniCore-F64 mrc/mcr */
-static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- TCGv tmp;
-
- if ((insn & 0xfe0003ff) == 0xe2000000) {
- /* control register */
- if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) {
- ILLEGAL;
- }
- if (UCOP_SET(24)) {
- /* CFF */
- tmp = new_tmp();
- gen_helper_ucf64_get_fpscr(tmp, cpu_env);
- store_reg(s, UCOP_REG_D, tmp);
- } else {
- /* CTF */
- tmp = load_reg(s, UCOP_REG_D);
- gen_helper_ucf64_set_fpscr(cpu_env, tmp);
- dead_tmp(tmp);
- gen_lookup_tb(s);
- }
- return;
- }
- if ((insn & 0xfe0003ff) == 0xe0000000) {
- /* general register */
- if (UCOP_REG_D == 31) {
- ILLEGAL;
- }
- if (UCOP_SET(24)) { /* MFF */
- tmp = ucf64_gen_ld32(UCOP_REG_N);
- store_reg(s, UCOP_REG_D, tmp);
- } else { /* MTF */
- tmp = load_reg(s, UCOP_REG_D);
- ucf64_gen_st32(tmp, UCOP_REG_N);
- }
- return;
- }
- if ((insn & 0xfb000000) == 0xe9000000) {
- /* MFFC */
- if (UCOP_REG_D != 31) {
- ILLEGAL;
- }
- if (UCOP_UCF64_COND & 0x8) {
- ILLEGAL;
- }
-
- tmp = new_tmp();
- tcg_gen_movi_i32(tmp, UCOP_UCF64_COND);
- if (UCOP_SET(26)) {
- tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
- tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env);
- } else {
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
- tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env);
- }
- dead_tmp(tmp);
- return;
- }
- ILLEGAL;
-}
-
-/* UniCore-F64 convert instructions */
-static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- if (UCOP_UCF64_FMT == 3) {
- ILLEGAL;
- }
- if (UCOP_REG_N != 0) {
- ILLEGAL;
- }
- switch (UCOP_UCF64_FUNC) {
- case 0: /* cvt.s */
- switch (UCOP_UCF64_FMT) {
- case 1 /* d */:
- tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env);
- tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- case 2 /* w */:
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env);
- tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- default /* s */:
- ILLEGAL;
- break;
- }
- break;
- case 1: /* cvt.d */
- switch (UCOP_UCF64_FMT) {
- case 0 /* s */:
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env);
- tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- case 2 /* w */:
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env);
- tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- default /* d */:
- ILLEGAL;
- break;
- }
- break;
- case 4: /* cvt.w */
- switch (UCOP_UCF64_FMT) {
- case 0 /* s */:
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env);
- tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- case 1 /* d */:
- tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env);
- tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D));
- break;
- default /* w */:
- ILLEGAL;
- break;
- }
- break;
- default:
- ILLEGAL;
- }
-}
-
-/* UniCore-F64 compare instructions */
-static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- if (UCOP_SET(25)) {
- ILLEGAL;
- }
- if (UCOP_REG_D != 0) {
- ILLEGAL;
- }
-
- ILLEGAL; /* TODO */
- if (UCOP_SET(24)) {
- tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N));
- tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */
- } else {
- tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N));
- tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M));
- /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */
- }
-}
-
-#define gen_helper_ucf64_movs(x, y) do { } while (0)
-#define gen_helper_ucf64_movd(x, y) do { } while (0)
-
-#define UCF64_OP1(name) do { \
- if (UCOP_REG_N != 0) { \
- ILLEGAL; \
- } \
- switch (UCOP_UCF64_FMT) { \
- case 0 /* s */: \
- tcg_gen_ld_i32(cpu_F0s, cpu_env, \
- ucf64_reg_offset(UCOP_REG_M)); \
- gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \
- tcg_gen_st_i32(cpu_F0s, cpu_env, \
- ucf64_reg_offset(UCOP_REG_D)); \
- break; \
- case 1 /* d */: \
- tcg_gen_ld_i64(cpu_F0d, cpu_env, \
- ucf64_reg_offset(UCOP_REG_M)); \
- gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \
- tcg_gen_st_i64(cpu_F0d, cpu_env, \
- ucf64_reg_offset(UCOP_REG_D)); \
- break; \
- case 2 /* w */: \
- ILLEGAL; \
- break; \
- } \
- } while (0)
-
-#define UCF64_OP2(name) do { \
- switch (UCOP_UCF64_FMT) { \
- case 0 /* s */: \
- tcg_gen_ld_i32(cpu_F0s, cpu_env, \
- ucf64_reg_offset(UCOP_REG_N)); \
- tcg_gen_ld_i32(cpu_F1s, cpu_env, \
- ucf64_reg_offset(UCOP_REG_M)); \
- gen_helper_ucf64_##name##s(cpu_F0s, \
- cpu_F0s, cpu_F1s, cpu_env); \
- tcg_gen_st_i32(cpu_F0s, cpu_env, \
- ucf64_reg_offset(UCOP_REG_D)); \
- break; \
- case 1 /* d */: \
- tcg_gen_ld_i64(cpu_F0d, cpu_env, \
- ucf64_reg_offset(UCOP_REG_N)); \
- tcg_gen_ld_i64(cpu_F1d, cpu_env, \
- ucf64_reg_offset(UCOP_REG_M)); \
- gen_helper_ucf64_##name##d(cpu_F0d, \
- cpu_F0d, cpu_F1d, cpu_env); \
- tcg_gen_st_i64(cpu_F0d, cpu_env, \
- ucf64_reg_offset(UCOP_REG_D)); \
- break; \
- case 2 /* w */: \
- ILLEGAL; \
- break; \
- } \
- } while (0)
-
-/* UniCore-F64 data processing */
-static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- if (UCOP_UCF64_FMT == 3) {
- ILLEGAL;
- }
- switch (UCOP_UCF64_FUNC) {
- case 0: /* add */
- UCF64_OP2(add);
- break;
- case 1: /* sub */
- UCF64_OP2(sub);
- break;
- case 2: /* mul */
- UCF64_OP2(mul);
- break;
- case 4: /* div */
- UCF64_OP2(div);
- break;
- case 5: /* abs */
- UCF64_OP1(abs);
- break;
- case 6: /* mov */
- UCF64_OP1(mov);
- break;
- case 7: /* neg */
- UCF64_OP1(neg);
- break;
- default:
- ILLEGAL;
- }
-}
-
-/* Disassemble an F64 instruction */
-static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- if (!UCOP_SET(29)) {
- if (UCOP_SET(26)) {
- do_ucf64_ldst_m(env, s, insn);
- } else {
- do_ucf64_ldst_i(env, s, insn);
- }
- } else {
- if (UCOP_SET(5)) {
- switch ((insn >> 26) & 0x3) {
- case 0:
- do_ucf64_datap(env, s, insn);
- break;
- case 1:
- ILLEGAL;
- break;
- case 2:
- do_ucf64_fcvt(env, s, insn);
- break;
- case 3:
- do_ucf64_fcmp(env, s, insn);
- break;
- }
- } else {
- do_ucf64_trans(env, s, insn);
- }
- }
-}
-
-static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
-{
-#ifndef CONFIG_USER_ONLY
- return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
-#else
- return true;
-#endif
-}
-
-static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
-{
- if (use_goto_tb(s, dest)) {
- tcg_gen_goto_tb(n);
- gen_set_pc_im(dest);
- tcg_gen_exit_tb(s->tb, n);
- } else {
- gen_set_pc_im(dest);
- tcg_gen_exit_tb(NULL, 0);
- }
-}
-
-static inline void gen_jmp(DisasContext *s, uint32_t dest)
-{
- if (unlikely(s->singlestep_enabled)) {
- /* An indirect jump so that we still trigger the debug exception. */
- gen_bx_im(s, dest);
- } else {
- gen_goto_tb(s, 0, dest);
- s->is_jmp = DISAS_TB_JUMP;
- }
-}
-
-/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
-static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0)
-{
- TCGv tmp;
- if (bsr) {
- /* ??? This is also undefined in system mode. */
- if (IS_USER(s)) {
- return 1;
- }
-
- tmp = load_cpu_field(bsr);
- tcg_gen_andi_i32(tmp, tmp, ~mask);
- tcg_gen_andi_i32(t0, t0, mask);
- tcg_gen_or_i32(tmp, tmp, t0);
- store_cpu_field(tmp, bsr);
- } else {
- gen_set_asr(t0, mask);
- }
- dead_tmp(t0);
- gen_lookup_tb(s);
- return 0;
-}
-
-/* Generate an old-style exception return. Marks pc as dead. */
-static void gen_exception_return(DisasContext *s, TCGv pc)
-{
- TCGv tmp;
- store_reg(s, 31, pc);
- tmp = load_cpu_field(bsr);
- gen_set_asr(tmp, 0xffffffff);
- dead_tmp(tmp);
- s->is_jmp = DISAS_UPDATE;
-}
-
-static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s,
- uint32_t insn)
-{
- switch (UCOP_CPNUM) {
-#ifndef CONFIG_USER_ONLY
- case 0:
- disas_cp0_insn(env, s, insn);
- break;
- case 1:
- disas_ocd_insn(env, s, insn);
- break;
-#endif
- case 2:
- disas_ucf64_insn(env, s, insn);
- break;
- default:
- /* Unknown coprocessor. */
- cpu_abort(env_cpu(env), "Unknown coprocessor!");
- }
-}
-
-/* data processing instructions */
-static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- TCGv tmp;
- TCGv tmp2;
- int logic_cc;
-
- if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) {
- if (UCOP_SET(23)) { /* CMOV instructions */
- if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) {
- ILLEGAL;
- }
- /* if not always execute, we generate a conditional jump to
- next instruction */
- s->condlabel = gen_new_label();
- gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel);
- s->condjmp = 1;
- }
- }
-
- logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24);
-
- if (UCOP_SET(29)) {
- unsigned int val;
- /* immediate operand */
- val = UCOP_IMM_9;
- if (UCOP_SH_IM) {
- val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
- }
- tmp2 = new_tmp();
- tcg_gen_movi_i32(tmp2, val);
- if (logic_cc && UCOP_SH_IM) {
- gen_set_CF_bit31(tmp2);
- }
- } else {
- /* register */
- tmp2 = load_reg(s, UCOP_REG_M);
- if (UCOP_SET(5)) {
- tmp = load_reg(s, UCOP_REG_S);
- gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc);
- } else {
- gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc);
- }
- }
-
- if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
- tmp = load_reg(s, UCOP_REG_N);
- } else {
- tmp = NULL;
- }
-
- switch (UCOP_OPCODES) {
- case 0x00:
- tcg_gen_and_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x01:
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x02:
- if (UCOP_SET_S && UCOP_REG_D == 31) {
- /* SUBS r31, ... is used for exception return. */
- if (IS_USER(s)) {
- ILLEGAL;
- }
- gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
- gen_exception_return(s, tmp);
- } else {
- if (UCOP_SET_S) {
- gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
- } else {
- tcg_gen_sub_i32(tmp, tmp, tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- }
- break;
- case 0x03:
- if (UCOP_SET_S) {
- gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp);
- } else {
- tcg_gen_sub_i32(tmp, tmp2, tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x04:
- if (UCOP_SET_S) {
- gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
- } else {
- tcg_gen_add_i32(tmp, tmp, tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x05:
- if (UCOP_SET_S) {
- gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_add_carry(tmp, tmp, tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x06:
- if (UCOP_SET_S) {
- gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2);
- } else {
- gen_sub_carry(tmp, tmp, tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x07:
- if (UCOP_SET_S) {
- gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp);
- } else {
- gen_sub_carry(tmp, tmp2, tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x08:
- if (UCOP_SET_S) {
- tcg_gen_and_i32(tmp, tmp, tmp2);
- gen_logic_CC(tmp);
- }
- dead_tmp(tmp);
- break;
- case 0x09:
- if (UCOP_SET_S) {
- tcg_gen_xor_i32(tmp, tmp, tmp2);
- gen_logic_CC(tmp);
- }
- dead_tmp(tmp);
- break;
- case 0x0a:
- if (UCOP_SET_S) {
- gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2);
- }
- dead_tmp(tmp);
- break;
- case 0x0b:
- if (UCOP_SET_S) {
- gen_helper_add_cc(tmp, cpu_env, tmp, tmp2);
- }
- dead_tmp(tmp);
- break;
- case 0x0c:
- tcg_gen_or_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- case 0x0d:
- if (logic_cc && UCOP_REG_D == 31) {
- /* MOVS r31, ... is used for exception return. */
- if (IS_USER(s)) {
- ILLEGAL;
- }
- gen_exception_return(s, tmp2);
- } else {
- if (logic_cc) {
- gen_logic_CC(tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp2);
- }
- break;
- case 0x0e:
- tcg_gen_andc_i32(tmp, tmp, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp);
- }
- store_reg_bx(s, UCOP_REG_D, tmp);
- break;
- default:
- case 0x0f:
- tcg_gen_not_i32(tmp2, tmp2);
- if (logic_cc) {
- gen_logic_CC(tmp2);
- }
- store_reg_bx(s, UCOP_REG_D, tmp2);
- break;
- }
- if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) {
- dead_tmp(tmp2);
- }
-}
-
-/* multiply */
-static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- TCGv tmp, tmp2, tmp3, tmp4;
-
- if (UCOP_SET(27)) {
- /* 64 bit mul */
- tmp = load_reg(s, UCOP_REG_M);
- tmp2 = load_reg(s, UCOP_REG_N);
- if (UCOP_SET(26)) {
- tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
- } else {
- tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
- }
- if (UCOP_SET(25)) { /* mult accumulate */
- tmp3 = load_reg(s, UCOP_REG_LO);
- tmp4 = load_reg(s, UCOP_REG_HI);
- tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4);
- dead_tmp(tmp3);
- dead_tmp(tmp4);
- }
- store_reg(s, UCOP_REG_LO, tmp);
- store_reg(s, UCOP_REG_HI, tmp2);
- } else {
- /* 32 bit mul */
- tmp = load_reg(s, UCOP_REG_M);
- tmp2 = load_reg(s, UCOP_REG_N);
- tcg_gen_mul_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- if (UCOP_SET(25)) {
- /* Add */
- tmp2 = load_reg(s, UCOP_REG_S);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- dead_tmp(tmp2);
- }
- if (UCOP_SET_S) {
- gen_logic_CC(tmp);
- }
- store_reg(s, UCOP_REG_D, tmp);
- }
-}
-
-/* miscellaneous instructions */
-static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- unsigned int val;
- TCGv tmp;
-
- if ((insn & 0xffffffe0) == 0x10ffc120) {
- /* Trivial implementation equivalent to bx. */
- tmp = load_reg(s, UCOP_REG_M);
- gen_bx(s, tmp);
- return;
- }
-
- if ((insn & 0xfbffc000) == 0x30ffc000) {
- /* PSR = immediate */
- val = UCOP_IMM_9;
- if (UCOP_SH_IM) {
- val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM));
- }
- tmp = new_tmp();
- tcg_gen_movi_i32(tmp, val);
- if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
- ILLEGAL;
- }
- return;
- }
-
- if ((insn & 0xfbffffe0) == 0x12ffc020) {
- /* PSR.flag = reg */
- tmp = load_reg(s, UCOP_REG_M);
- if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) {
- ILLEGAL;
- }
- return;
- }
-
- if ((insn & 0xfbffffe0) == 0x10ffc020) {
- /* PSR = reg */
- tmp = load_reg(s, UCOP_REG_M);
- if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) {
- ILLEGAL;
- }
- return;
- }
-
- if ((insn & 0xfbf83fff) == 0x10f80000) {
- /* reg = PSR */
- if (UCOP_SET_B) {
- if (IS_USER(s)) {
- ILLEGAL;
- }
- tmp = load_cpu_field(bsr);
- } else {
- tmp = new_tmp();
- gen_helper_asr_read(tmp, cpu_env);
- }
- store_reg(s, UCOP_REG_D, tmp);
- return;
- }
-
- if ((insn & 0xfbf83fe0) == 0x12f80120) {
- /* clz */
- tmp = load_reg(s, UCOP_REG_M);
- if (UCOP_SET(26)) {
- /* clo */
- tcg_gen_not_i32(tmp, tmp);
- }
- tcg_gen_clzi_i32(tmp, tmp, 32);
- store_reg(s, UCOP_REG_D, tmp);
- return;
- }
-
- /* otherwise */
- ILLEGAL;
-}
-
-/* load/store I_offset and R_offset */
-static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- unsigned int mmu_idx;
- TCGv tmp;
- TCGv tmp2;
-
- tmp2 = load_reg(s, UCOP_REG_N);
- mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
-
- /* immediate */
- if (UCOP_SET_P) {
- gen_add_data_offset(s, insn, tmp2);
- }
-
- if (UCOP_SET_L) {
- /* load */
- if (UCOP_SET_B) {
- tmp = gen_ld8u(tmp2, mmu_idx);
- } else {
- tmp = gen_ld32(tmp2, mmu_idx);
- }
- } else {
- /* store */
- tmp = load_reg(s, UCOP_REG_D);
- if (UCOP_SET_B) {
- gen_st8(tmp, tmp2, mmu_idx);
- } else {
- gen_st32(tmp, tmp2, mmu_idx);
- }
- }
- if (!UCOP_SET_P) {
- gen_add_data_offset(s, insn, tmp2);
- store_reg(s, UCOP_REG_N, tmp2);
- } else if (UCOP_SET_W) {
- store_reg(s, UCOP_REG_N, tmp2);
- } else {
- dead_tmp(tmp2);
- }
- if (UCOP_SET_L) {
- /* Complete the load. */
- if (UCOP_REG_D == 31) {
- gen_bx(s, tmp);
- } else {
- store_reg(s, UCOP_REG_D, tmp);
- }
- }
-}
-
-/* SWP instruction */
-static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- TCGv addr;
- TCGv tmp;
- TCGv tmp2;
-
- if ((insn & 0xff003fe0) != 0x40000120) {
- ILLEGAL;
- }
-
- /* ??? This is not really atomic. However we know
- we never have multiple CPUs running in parallel,
- so it is good enough. */
- addr = load_reg(s, UCOP_REG_N);
- tmp = load_reg(s, UCOP_REG_M);
- if (UCOP_SET_B) {
- tmp2 = gen_ld8u(addr, IS_USER(s));
- gen_st8(tmp, addr, IS_USER(s));
- } else {
- tmp2 = gen_ld32(addr, IS_USER(s));
- gen_st32(tmp, addr, IS_USER(s));
- }
- dead_tmp(addr);
- store_reg(s, UCOP_REG_D, tmp2);
-}
-
-/* load/store hw/sb */
-static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- TCGv addr;
- TCGv tmp;
-
- if (UCOP_SH_OP == 0) {
- do_swap(env, s, insn);
- return;
- }
-
- addr = load_reg(s, UCOP_REG_N);
- if (UCOP_SET_P) {
- gen_add_datah_offset(s, insn, addr);
- }
-
- if (UCOP_SET_L) { /* load */
- switch (UCOP_SH_OP) {
- case 1:
- tmp = gen_ld16u(addr, IS_USER(s));
- break;
- case 2:
- tmp = gen_ld8s(addr, IS_USER(s));
- break;
- default: /* see do_swap */
- case 3:
- tmp = gen_ld16s(addr, IS_USER(s));
- break;
- }
- } else { /* store */
- if (UCOP_SH_OP != 1) {
- ILLEGAL;
- }
- tmp = load_reg(s, UCOP_REG_D);
- gen_st16(tmp, addr, IS_USER(s));
- }
- /* Perform base writeback before the loaded value to
- ensure correct behavior with overlapping index registers. */
- if (!UCOP_SET_P) {
- gen_add_datah_offset(s, insn, addr);
- store_reg(s, UCOP_REG_N, addr);
- } else if (UCOP_SET_W) {
- store_reg(s, UCOP_REG_N, addr);
- } else {
- dead_tmp(addr);
- }
- if (UCOP_SET_L) {
- /* Complete the load. */
- store_reg(s, UCOP_REG_D, tmp);
- }
-}
-
-/* load/store multiple words */
-static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- unsigned int val, i, mmu_idx;
- int j, n, reg, user, loaded_base;
- TCGv tmp;
- TCGv tmp2;
- TCGv addr;
- TCGv loaded_var;
-
- if (UCOP_SET(7)) {
- ILLEGAL;
- }
- /* XXX: store correct base if write back */
- user = 0;
- if (UCOP_SET_B) { /* S bit in instruction table */
- if (IS_USER(s)) {
- ILLEGAL; /* only usable in supervisor mode */
- }
- if (UCOP_SET(18) == 0) { /* pc reg */
- user = 1;
- }
- }
-
- mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W));
- addr = load_reg(s, UCOP_REG_N);
-
- /* compute total size */
- loaded_base = 0;
- loaded_var = NULL;
- n = 0;
- for (i = 0; i < 6; i++) {
- if (UCOP_SET(i)) {
- n++;
- }
- }
- for (i = 9; i < 19; i++) {
- if (UCOP_SET(i)) {
- n++;
- }
- }
- /* XXX: test invalid n == 0 case ? */
- if (UCOP_SET_U) {
- if (UCOP_SET_P) {
- /* pre increment */
- tcg_gen_addi_i32(addr, addr, 4);
- } else {
- /* post increment */
- }
- } else {
- if (UCOP_SET_P) {
- /* pre decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- } else {
- /* post decrement */
- if (n != 1) {
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- }
- }
- }
-
- j = 0;
- reg = UCOP_SET(6) ? 16 : 0;
- for (i = 0; i < 19; i++, reg++) {
- if (i == 6) {
- i = i + 3;
- }
- if (UCOP_SET(i)) {
- if (UCOP_SET_L) { /* load */
- tmp = gen_ld32(addr, mmu_idx);
- if (reg == 31) {
- gen_bx(s, tmp);
- } else if (user) {
- tmp2 = tcg_const_i32(reg);
- gen_helper_set_user_reg(cpu_env, tmp2, tmp);
- tcg_temp_free_i32(tmp2);
- dead_tmp(tmp);
- } else if (reg == UCOP_REG_N) {
- loaded_var = tmp;
- loaded_base = 1;
- } else {
- store_reg(s, reg, tmp);
- }
- } else { /* store */
- if (reg == 31) {
- /* special case: r31 = PC + 4 */
- val = (long)s->pc;
- tmp = new_tmp();
- tcg_gen_movi_i32(tmp, val);
- } else if (user) {
- tmp = new_tmp();
- tmp2 = tcg_const_i32(reg);
- gen_helper_get_user_reg(tmp, cpu_env, tmp2);
- tcg_temp_free_i32(tmp2);
- } else {
- tmp = load_reg(s, reg);
- }
- gen_st32(tmp, addr, mmu_idx);
- }
- j++;
- /* no need to add after the last transfer */
- if (j != n) {
- tcg_gen_addi_i32(addr, addr, 4);
- }
- }
- }
- if (UCOP_SET_W) { /* write back */
- if (UCOP_SET_U) {
- if (UCOP_SET_P) {
- /* pre increment */
- } else {
- /* post increment */
- tcg_gen_addi_i32(addr, addr, 4);
- }
- } else {
- if (UCOP_SET_P) {
- /* pre decrement */
- if (n != 1) {
- tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
- }
- } else {
- /* post decrement */
- tcg_gen_addi_i32(addr, addr, -(n * 4));
- }
- }
- store_reg(s, UCOP_REG_N, addr);
- } else {
- dead_tmp(addr);
- }
- if (loaded_base) {
- store_reg(s, UCOP_REG_N, loaded_var);
- }
- if (UCOP_SET_B && !user) {
- /* Restore ASR from BSR. */
- tmp = load_cpu_field(bsr);
- gen_set_asr(tmp, 0xffffffff);
- dead_tmp(tmp);
- s->is_jmp = DISAS_UPDATE;
- }
-}
-
-/* branch (and link) */
-static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn)
-{
- unsigned int val;
- int32_t offset;
- TCGv tmp;
-
- if (UCOP_COND == 0xf) {
- ILLEGAL;
- }
-
- if (UCOP_COND != 0xe) {
- /* if not always execute, we generate a conditional jump to
- next instruction */
- s->condlabel = gen_new_label();
- gen_test_cc(UCOP_COND ^ 1, s->condlabel);
- s->condjmp = 1;
- }
-
- val = (int32_t)s->pc;
- if (UCOP_SET_L) {
- tmp = new_tmp();
- tcg_gen_movi_i32(tmp, val);
- store_reg(s, 30, tmp);
- }
- offset = (((int32_t)insn << 8) >> 8);
- val += (offset << 2); /* unicore is pc+4 */
- gen_jmp(s, val);
-}
-
-static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s)
-{
- unsigned int insn;
-
- insn = cpu_ldl_code(env, s->pc);
- s->pc += 4;
-
- /* UniCore instructions class:
- * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx
- * AAA : see switch case
- * BBBB : opcodes or cond or PUBW
- * C : S OR L
- * D : 8
- * E : 5
- */
- switch (insn >> 29) {
- case 0x0:
- if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) {
- do_mult(env, s, insn);
- break;
- }
-
- if (UCOP_SET(8)) {
- do_misc(env, s, insn);
- break;
- }
- /* fallthrough */
- case 0x1:
- if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) {
- do_misc(env, s, insn);
- break;
- }
- do_datap(env, s, insn);
- break;
-
- case 0x2:
- if (UCOP_SET(8) && UCOP_SET(5)) {
- do_ldst_hwsb(env, s, insn);
- break;
- }
- if (UCOP_SET(8) || UCOP_SET(5)) {
- ILLEGAL;
- }
- /* fallthrough */
- case 0x3:
- do_ldst_ir(env, s, insn);
- break;
-
- case 0x4:
- if (UCOP_SET(8)) {
- ILLEGAL; /* extended instructions */
- }
- do_ldst_m(env, s, insn);
- break;
- case 0x5:
- do_branch(env, s, insn);
- break;
- case 0x6:
- /* Coprocessor. */
- disas_coproc_insn(env, s, insn);
- break;
- case 0x7:
- if (!UCOP_SET(28)) {
- disas_coproc_insn(env, s, insn);
- break;
- }
- if ((insn & 0xff000000) == 0xff000000) { /* syscall */
- gen_set_pc_im(s->pc);
- s->is_jmp = DISAS_SYSCALL;
- break;
- }
- ILLEGAL;
- }
-}
-
-/* generate intermediate code for basic block 'tb'. */
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
-{
- CPUUniCore32State *env = cs->env_ptr;
- DisasContext dc1, *dc = &dc1;
- target_ulong pc_start;
- uint32_t page_start;
- int num_insns;
-
- /* generate intermediate code */
- num_temps = 0;
-
- pc_start = tb->pc;
-
- dc->tb = tb;
-
- dc->is_jmp = DISAS_NEXT;
- dc->pc = pc_start;
- dc->singlestep_enabled = cs->singlestep_enabled;
- dc->condjmp = 0;
- cpu_F0s = tcg_temp_new_i32();
- cpu_F1s = tcg_temp_new_i32();
- cpu_F0d = tcg_temp_new_i64();
- cpu_F1d = tcg_temp_new_i64();
- page_start = pc_start & TARGET_PAGE_MASK;
- num_insns = 0;
-
-#ifndef CONFIG_USER_ONLY
- if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) {
- dc->user = 1;
- } else {
- dc->user = 0;
- }
-#endif
-
- gen_tb_start(tb);
- do {
- tcg_gen_insn_start(dc->pc);
- num_insns++;
-
- if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
- gen_set_pc_im(dc->pc);
- gen_exception(EXCP_DEBUG);
- dc->is_jmp = DISAS_JUMP;
- /* The address covered by the breakpoint must be included in
- [tb->pc, tb->pc + tb->size) in order to for it to be
- properly cleared -- thus we increment the PC here so that
- the logic setting tb->size below does the right thing. */
- dc->pc += 4;
- goto done_generating;
- }
-
- if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
- gen_io_start();
- }
-
- disas_uc32_insn(env, dc);
-
- if (num_temps) {
- fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
- num_temps = 0;
- }
-
- if (dc->condjmp && !dc->is_jmp) {
- gen_set_label(dc->condlabel);
- dc->condjmp = 0;
- }
- /* Translation stops when a conditional branch is encountered.
- * Otherwise the subsequent code could get translated several times.
- * Also stop translation when a page boundary is reached. This
- * ensures prefetch aborts occur at the right place. */
- } while (!dc->is_jmp && !tcg_op_buf_full() &&
- !cs->singlestep_enabled &&
- !singlestep &&
- dc->pc - page_start < TARGET_PAGE_SIZE &&
- num_insns < max_insns);
-
- if (tb_cflags(tb) & CF_LAST_IO) {
- if (dc->condjmp) {
- /* FIXME: This can theoretically happen with self-modifying
- code. */
- cpu_abort(cs, "IO on conditional branch instruction");
- }
- }
-
- /* At this stage dc->condjmp will only be set when the skipped
- instruction was a conditional branch or trap, and the PC has
- already been written. */
- if (unlikely(cs->singlestep_enabled)) {
- /* Make sure the pc is updated, and raise a debug exception. */
- if (dc->condjmp) {
- if (dc->is_jmp == DISAS_SYSCALL) {
- gen_exception(UC32_EXCP_PRIV);
- } else {
- gen_exception(EXCP_DEBUG);
- }
- gen_set_label(dc->condlabel);
- }
- if (dc->condjmp || !dc->is_jmp) {
- gen_set_pc_im(dc->pc);
- dc->condjmp = 0;
- }
- if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) {
- gen_exception(UC32_EXCP_PRIV);
- } else {
- gen_exception(EXCP_DEBUG);
- }
- } else {
- /* While branches must always occur at the end of an IT block,
- there are a few other things that can cause us to terminate
- the TB in the middel of an IT block:
- - Exception generating instructions (bkpt, swi, undefined).
- - Page boundaries.
- - Hardware watchpoints.
- Hardware breakpoints have already been handled and skip this code.
- */
- switch (dc->is_jmp) {
- case DISAS_NEXT:
- gen_goto_tb(dc, 1, dc->pc);
- break;
- default:
- case DISAS_JUMP:
- case DISAS_UPDATE:
- /* indicate that the hash table must be used to find the next TB */
- tcg_gen_exit_tb(NULL, 0);
- break;
- case DISAS_TB_JUMP:
- /* nothing more to generate */
- break;
- case DISAS_SYSCALL:
- gen_exception(UC32_EXCP_PRIV);
- break;
- }
- if (dc->condjmp) {
- gen_set_label(dc->condlabel);
- gen_goto_tb(dc, 1, dc->pc);
- dc->condjmp = 0;
- }
- }
-
-done_generating:
- gen_tb_end(tb, num_insns);
-
-#ifdef DEBUG_DISAS
- if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
- && qemu_log_in_addr_range(pc_start)) {
- FILE *logfile = qemu_log_lock();
- qemu_log("----------------\n");
- qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(cs, pc_start, dc->pc - pc_start);
- qemu_log("\n");
- qemu_log_unlock(logfile);
- }
-#endif
- tb->size = dc->pc - pc_start;
- tb->icount = num_insns;
-}
-
-static const char *cpu_mode_names[16] = {
- "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP",
- "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR"
-};
-
-#undef UCF64_DUMP_STATE
-#ifdef UCF64_DUMP_STATE
-static void cpu_dump_state_ucf64(CPUUniCore32State *env, int flags)
-{
- int i;
- union {
- uint32_t i;
- float s;
- } s0, s1;
- CPU_DoubleU d;
- /* ??? This assumes float64 and double have the same layout.
- Oh well, it's only debug dumps. */
- union {
- float64 f64;
- double d;
- } d0;
-
- for (i = 0; i < 16; i++) {
- d.d = env->ucf64.regs[i];
- s0.i = d.l.lower;
- s1.i = d.l.upper;
- d0.f64 = d.d;
- qemu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)",
- i * 2, (int)s0.i, s0.s,
- i * 2 + 1, (int)s1.i, s1.s);
- qemu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n",
- i, (uint64_t)d0.f64, d0.d);
- }
- qemu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]);
-}
-#else
-#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0)
-#endif
-
-void uc32_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- UniCore32CPU *cpu = UNICORE32_CPU(cs);
- CPUUniCore32State *env = &cpu->env;
- int i;
- uint32_t psr;
-
- for (i = 0; i < 32; i++) {
- qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
- if ((i % 4) == 3) {
- qemu_fprintf(f, "\n");
- } else {
- qemu_fprintf(f, " ");
- }
- }
- psr = cpu_asr_read(env);
- qemu_fprintf(f, "PSR=%08x %c%c%c%c %s\n",
- psr,
- psr & (1 << 31) ? 'N' : '-',
- psr & (1 << 30) ? 'Z' : '-',
- psr & (1 << 29) ? 'C' : '-',
- psr & (1 << 28) ? 'V' : '-',
- cpu_mode_names[psr & 0xf]);
-
- if (flags & CPU_DUMP_FPU) {
- cpu_dump_state_ucf64(env, f, cpu_fprintf, flags);
- }
-}
-
-void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb,
- target_ulong *data)
-{
- env->regs[31] = data[0];
-}
diff --git a/target/unicore32/ucf64_helper.c b/target/unicore32/ucf64_helper.c
deleted file mode 100644
index 12a91900f6..0000000000
--- a/target/unicore32/ucf64_helper.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * UniCore-F64 simulation helpers for QEMU.
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/helper-proto.h"
-#include "fpu/softfloat.h"
-
-/*
- * The convention used for UniCore-F64 instructions:
- * Single precition routines have a "s" suffix
- * Double precision routines have a "d" suffix.
- */
-
-/* Convert host exception flags to f64 form. */
-static inline int ucf64_exceptbits_from_host(int host_bits)
-{
- int target_bits = 0;
-
- if (host_bits & float_flag_invalid) {
- target_bits |= UCF64_FPSCR_FLAG_INVALID;
- }
- if (host_bits & float_flag_divbyzero) {
- target_bits |= UCF64_FPSCR_FLAG_DIVZERO;
- }
- if (host_bits & float_flag_overflow) {
- target_bits |= UCF64_FPSCR_FLAG_OVERFLOW;
- }
- if (host_bits & float_flag_underflow) {
- target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW;
- }
- if (host_bits & float_flag_inexact) {
- target_bits |= UCF64_FPSCR_FLAG_INEXACT;
- }
- return target_bits;
-}
-
-uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env)
-{
- int i;
- uint32_t fpscr;
-
- fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK);
- i = get_float_exception_flags(&env->ucf64.fp_status);
- fpscr |= ucf64_exceptbits_from_host(i);
- return fpscr;
-}
-
-/* Convert ucf64 exception flags to target form. */
-static inline int ucf64_exceptbits_to_host(int target_bits)
-{
- int host_bits = 0;
-
- if (target_bits & UCF64_FPSCR_FLAG_INVALID) {
- host_bits |= float_flag_invalid;
- }
- if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) {
- host_bits |= float_flag_divbyzero;
- }
- if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) {
- host_bits |= float_flag_overflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) {
- host_bits |= float_flag_underflow;
- }
- if (target_bits & UCF64_FPSCR_FLAG_INEXACT) {
- host_bits |= float_flag_inexact;
- }
- return host_bits;
-}
-
-void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val)
-{
- UniCore32CPU *cpu = env_archcpu(env);
- int i;
- uint32_t changed;
-
- changed = env->ucf64.xregs[UC32_UCF64_FPSCR];
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK);
-
- changed ^= val;
- if (changed & (UCF64_FPSCR_RND_MASK)) {
- i = UCF64_FPSCR_RND(val);
- switch (i) {
- case 0:
- i = float_round_nearest_even;
- break;
- case 1:
- i = float_round_to_zero;
- break;
- case 2:
- i = float_round_up;
- break;
- case 3:
- i = float_round_down;
- break;
- default: /* 100 and 101 not implement */
- cpu_abort(CPU(cpu), "Unsupported UniCore-F64 round mode");
- }
- set_float_rounding_mode(i, &env->ucf64.fp_status);
- }
-
- i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val));
- set_float_exception_flags(i, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_add(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_add(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_sub(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_sub(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_mul(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_mul(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env)
-{
- return float32_div(a, b, &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env)
-{
- return float64_div(a, b, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_negs)(float32 a)
-{
- return float32_chs(a);
-}
-
-float64 HELPER(ucf64_negd)(float64 a)
-{
- return float64_chs(a);
-}
-
-float32 HELPER(ucf64_abss)(float32 a)
-{
- return float32_abs(a);
-}
-
-float64 HELPER(ucf64_absd)(float64 a)
-{
- return float64_abs(a);
-}
-
-void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c,
- CPUUniCore32State *env)
-{
- FloatRelation flag = float32_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
- }
- break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
- }
- break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
- }
- break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
- }
- break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
- }
- break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
- }
- break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
- }
- break;
- }
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c,
- CPUUniCore32State *env)
-{
- FloatRelation flag = float64_compare_quiet(a, b, &env->ucf64.fp_status);
- env->CF = 0;
- switch (c & 0x7) {
- case 0: /* F */
- break;
- case 1: /* UN */
- if (flag == 2) {
- env->CF = 1;
- }
- break;
- case 2: /* EQ */
- if (flag == 0) {
- env->CF = 1;
- }
- break;
- case 3: /* UEQ */
- if ((flag == 0) || (flag == 2)) {
- env->CF = 1;
- }
- break;
- case 4: /* OLT */
- if (flag == -1) {
- env->CF = 1;
- }
- break;
- case 5: /* ULT */
- if ((flag == -1) || (flag == 2)) {
- env->CF = 1;
- }
- break;
- case 6: /* OLE */
- if ((flag == -1) || (flag == 0)) {
- env->CF = 1;
- }
- break;
- case 7: /* ULE */
- if (flag != 1) {
- env->CF = 1;
- }
- break;
- }
- env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29)
- | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff);
-}
-
-/* Helper routines to perform bitwise copies between float and int. */
-static inline float32 ucf64_itos(uint32_t i)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.i = i;
- return v.s;
-}
-
-static inline uint32_t ucf64_stoi(float32 s)
-{
- union {
- uint32_t i;
- float32 s;
- } v;
-
- v.s = s;
- return v.i;
-}
-
-/* Integer to float conversion. */
-float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status);
-}
-
-float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env)
-{
- return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status);
-}
-
-/* Float to integer conversion. */
-float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env)
-{
- return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status));
-}
-
-float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env)
-{
- return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status));
-}
-
-/* floating point conversion */
-float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env)
-{
- return float32_to_float64(x, &env->ucf64.fp_status);
-}
-
-float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env)
-{
- return float64_to_float32(x, &env->ucf64.fp_status);
-}
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 9f464cb92c..ff5d732889 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -140,25 +140,46 @@ docker-image-debian-mips-cross: docker-image-debian10
docker-image-debian-mips64-cross: docker-image-debian10
docker-image-debian-mips64el-cross: docker-image-debian10
docker-image-debian-mipsel-cross: docker-image-debian10
-docker-image-debian-powerpc-cross: docker-image-debian10
-docker-image-debian-ppc64-cross: docker-image-debian10
docker-image-debian-ppc64el-cross: docker-image-debian10
docker-image-debian-riscv64-cross: docker-image-debian10
docker-image-debian-s390x-cross: docker-image-debian10
docker-image-debian-sh4-cross: docker-image-debian10
docker-image-debian-sparc64-cross: docker-image-debian10
+#
+# The build rule for hexagon-cross is special in so far for most of
+# the time we don't want to build it. While dockers caching does avoid
+# this most of the time sometimes we want to force the issue.
+#
+docker-image-debian-hexagon-cross: $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker
+ $(if $(NOCACHE), \
+ $(call quiet-command, \
+ $(DOCKER_SCRIPT) build -t qemu/debian-hexagon-cross -f $< \
+ $(if $V,,--quiet) --no-cache \
+ --registry $(DOCKER_REGISTRY) --extra-files \
+ $(DOCKER_FILES_DIR)/debian-hexagon-cross.docker.d/build-toolchain.sh, \
+ "BUILD", "debian-hexagon-cross"), \
+ $(call quiet-command, \
+ $(DOCKER_SCRIPT) fetch $(if $V,,--quiet) \
+ qemu/debian-hexagon-cross $(DOCKER_REGISTRY), \
+ "FETCH", "debian-hexagon-cross") \
+ $(call quiet-command, \
+ $(DOCKER_SCRIPT) update $(if $V,,--quiet) \
+ qemu/debian-hexagon-cross --add-current-user, \
+ "PREPARE", "debian-hexagon-cross"))
+
# Specialist build images, sometimes very limited tools
docker-image-debian-tricore-cross: docker-image-debian10
docker-image-debian-all-test-cross: docker-image-debian10
docker-image-debian-arm64-test-cross: docker-image-debian11
+docker-image-debian-powerpc-test-cross: docker-image-debian11
# These images may be good enough for building tests but not for test builds
DOCKER_PARTIAL_IMAGES += debian-alpha-cross
DOCKER_PARTIAL_IMAGES += debian-arm64-test-cross
+DOCKER_PARTIAL_IMAGES += debian-powerpc-test-cross
DOCKER_PARTIAL_IMAGES += debian-hppa-cross
DOCKER_PARTIAL_IMAGES += debian-m68k-cross debian-mips64-cross
-DOCKER_PARTIAL_IMAGES += debian-powerpc-cross debian-ppc64-cross
DOCKER_PARTIAL_IMAGES += debian-riscv64-cross
DOCKER_PARTIAL_IMAGES += debian-sh4-cross debian-sparc64-cross
DOCKER_PARTIAL_IMAGES += debian-tricore-cross
@@ -248,7 +269,7 @@ docker-run: docker-qemu-src
$(if $(EXECUTABLE), \
$(call quiet-command, \
$(DOCKER_SCRIPT) update \
- $(IMAGE) $(EXECUTABLE), \
+ $(IMAGE) --executable $(EXECUTABLE), \
" COPYING $(EXECUTABLE) to $(IMAGE)"))
$(call quiet-command, \
$(DOCKER_SCRIPT) run \
diff --git a/tests/docker/docker.py b/tests/docker/docker.py
index d28df4c140..4d9bb7c7ed 100755
--- a/tests/docker/docker.py
+++ b/tests/docker/docker.py
@@ -515,16 +515,36 @@ class BuildCommand(SubCommand):
return 0
+class FetchCommand(SubCommand):
+ """ Fetch a docker image from the registry. Args: <tag> <registry>"""
+ name = "fetch"
+
+ def args(self, parser):
+ parser.add_argument("tag",
+ help="Local tag for image")
+ parser.add_argument("registry",
+ help="Docker registry")
+
+ def run(self, args, argv):
+ dkr = Docker()
+ dkr.command(cmd="pull", quiet=args.quiet,
+ argv=["%s/%s" % (args.registry, args.tag)])
+ dkr.command(cmd="tag", quiet=args.quiet,
+ argv=["%s/%s" % (args.registry, args.tag), args.tag])
+
class UpdateCommand(SubCommand):
- """ Update a docker image with new executables. Args: <tag> <executable>"""
+ """ Update a docker image. Args: <tag> <actions>"""
name = "update"
def args(self, parser):
parser.add_argument("tag",
help="Image Tag")
- parser.add_argument("executable",
+ parser.add_argument("--executable",
help="Executable to copy")
+ parser.add_argument("--add-current-user", "-u", dest="user",
+ action="store_true",
+ help="Add the current user to image's passwd")
def run(self, args, argv):
# Create a temporary tarball with our whole build context and
@@ -532,28 +552,44 @@ class UpdateCommand(SubCommand):
tmp = tempfile.NamedTemporaryFile(suffix="dckr.tar.gz")
tmp_tar = TarFile(fileobj=tmp, mode='w')
- # Add the executable to the tarball, using the current
- # configured binfmt_misc path. If we don't get a path then we
- # only need the support libraries copied
- ff, enabled = _check_binfmt_misc(args.executable)
-
- if not enabled:
- print("binfmt_misc not enabled, update disabled")
- return 1
-
- if ff:
- tmp_tar.add(args.executable, arcname=ff)
-
- # Add any associated libraries
- libs = _get_so_libs(args.executable)
- if libs:
- for l in libs:
- tmp_tar.add(os.path.realpath(l), arcname=l)
-
# Create a Docker buildfile
df = StringIO()
df.write(u"FROM %s\n" % args.tag)
- df.write(u"ADD . /\n")
+
+ if args.executable:
+ # Add the executable to the tarball, using the current
+ # configured binfmt_misc path. If we don't get a path then we
+ # only need the support libraries copied
+ ff, enabled = _check_binfmt_misc(args.executable)
+
+ if not enabled:
+ print("binfmt_misc not enabled, update disabled")
+ return 1
+
+ if ff:
+ tmp_tar.add(args.executable, arcname=ff)
+
+ # Add any associated libraries
+ libs = _get_so_libs(args.executable)
+ if libs:
+ for l in libs:
+ so_path = os.path.dirname(l)
+ name = os.path.basename(l)
+ real_l = os.path.realpath(l)
+ try:
+ tmp_tar.add(real_l, arcname="%s/%s" % (so_path, name))
+ except FileNotFoundError:
+ print("Couldn't add %s/%s to archive" % (so_path, name))
+ pass
+
+ df.write(u"ADD . /\n")
+
+ if args.user:
+ uid = os.getuid()
+ uname = getpwuid(uid).pw_name
+ df.write("\n")
+ df.write("RUN id %s 2>/dev/null || useradd -u %d -U %s" %
+ (uname, uid, uname))
df_bytes = BytesIO(bytes(df.getvalue(), "UTF-8"))
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index d63a269aef..7eeecacc46 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -9,6 +9,7 @@ ENV PACKAGES \
alsa-lib-dev \
bash \
binutils \
+ ccache \
coreutils \
curl-dev \
g++ \
@@ -19,6 +20,7 @@ ENV PACKAGES \
gnutls-dev \
gtk+3.0-dev \
libaio-dev \
+ libbpf-dev \
libcap-ng-dev \
libjpeg-turbo-dev \
libnfs-dev \
@@ -39,6 +41,7 @@ ENV PACKAGES \
pulseaudio-dev \
python3 \
py3-sphinx \
+ py3-sphinx_rtd_theme \
shadow \
snappy-dev \
spice-dev \
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index a8c6c528b0..efc1349cc8 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -14,6 +14,7 @@ ENV PACKAGES \
git \
glib2-devel \
libaio-devel \
+ libbpf-devel \
libepoxy-devel \
libfdt-devel \
libgcrypt-devel \
diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker
new file mode 100644
index 0000000000..d5dc299dc1
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker
@@ -0,0 +1,45 @@
+#
+# Docker Hexagon cross-compiler target
+#
+# This docker target is used for building hexagon tests. As it also
+# needs to be able to build QEMU itself in CI we include it's
+# build-deps. It is also a "stand-alone" image so as not to be
+# triggered by re-builds on other base images given it takes a long
+# time to build.
+#
+FROM qemu/debian10
+
+# Install common build utilities
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ bison \
+ cmake \
+ flex \
+ lld \
+ rsync \
+ wget
+
+ENV TOOLCHAIN_INSTALL /usr/local
+ENV ROOTFS /usr/local
+
+ENV LLVM_URL https://github.com/llvm/llvm-project/archive/bfcd21876adc3498065e4da92799f613e730d475.tar.gz
+ENV MUSL_URL https://github.com/quic/musl/archive/aff74b395fbf59cd7e93b3691905aa1af6c0778c.tar.gz
+ENV LINUX_URL https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.18.tar.xz
+
+ADD build-toolchain.sh /root/hexagon-toolchain/build-toolchain.sh
+
+RUN cd /root/hexagon-toolchain && ./build-toolchain.sh
+
+FROM debian:buster-slim
+# Duplicate deb line as deb-src
+RUN cat /etc/apt/sources.list | sed "s/^deb\ /deb-src /" >> /etc/apt/sources.list
+# Install QEMU build deps for use in CI
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
+ DEBIAN_FRONTEND=noninteractive eatmydata apt install -yy git ninja-build && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt build-dep -yy --arch-only qemu
+COPY --from=0 /usr/local /usr/local
+ENV PATH $PATH:/usr/local/bin/
diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
new file mode 100755
index 0000000000..19b1c9f83e
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker.d/build-toolchain.sh
@@ -0,0 +1,141 @@
+#!/bin/bash
+
+set -e
+
+BASE=$(readlink -f ${PWD})
+
+TOOLCHAIN_INSTALL=$(readlink -f "$TOOLCHAIN_INSTALL")
+ROOTFS=$(readlink -f "$ROOTFS")
+
+TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin
+HEX_SYSROOT=${TOOLCHAIN_INSTALL}/hexagon-unknown-linux-musl
+HEX_TOOLS_TARGET_BASE=${HEX_SYSROOT}/usr
+
+function cdp() {
+ DIR="$1"
+ mkdir -p "$DIR"
+ cd "$DIR"
+}
+
+function fetch() {
+ DIR="$1"
+ URL="$2"
+ TEMP="$(readlink -f "$PWD/tmp.tar.gz")"
+ wget --quiet "$URL" -O "$TEMP"
+ cdp "$DIR"
+ tar xaf "$TEMP" --strip-components=1
+ rm "$TEMP"
+ cd -
+}
+
+build_llvm_clang() {
+ fetch "$BASE/llvm-project" "$LLVM_URL"
+ cdp "$BASE/build-llvm"
+
+ cmake -G Ninja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_INSTALL_PREFIX=${TOOLCHAIN_INSTALL} \
+ -DLLVM_ENABLE_LLD=ON \
+ -DLLVM_TARGETS_TO_BUILD="Hexagon" \
+ -DLLVM_ENABLE_PROJECTS="clang;lld" \
+ "$BASE/llvm-project/llvm"
+ ninja all install
+ cd ${TOOLCHAIN_BIN}
+ ln -sf clang hexagon-unknown-linux-musl-clang
+ ln -sf clang++ hexagon-unknown-linux-musl-clang++
+ ln -sf llvm-ar hexagon-unknown-linux-musl-ar
+ ln -sf llvm-objdump hexagon-unknown-linux-musl-objdump
+ ln -sf llvm-objcopy hexagon-unknown-linux-musl-objcopy
+ ln -sf llvm-readelf hexagon-unknown-linux-musl-readelf
+ ln -sf llvm-ranlib hexagon-unknown-linux-musl-ranlib
+
+ # workaround for now:
+ cat <<EOF > hexagon-unknown-linux-musl.cfg
+-G0 --sysroot=${HEX_SYSROOT}
+EOF
+}
+
+build_clang_rt() {
+ cdp "$BASE/build-clang_rt"
+ cmake -G Ninja \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_CONFIG_PATH="$BASE/build-llvm/bin/llvm-config" \
+ -DCMAKE_ASM_FLAGS="-G0 -mlong-calls -fno-pic --target=hexagon-unknown-linux-musl " \
+ -DCMAKE_SYSTEM_NAME=Linux \
+ -DCMAKE_C_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \
+ -DCMAKE_ASM_COMPILER="${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang" \
+ -DCMAKE_INSTALL_PREFIX=${HEX_TOOLS_TARGET_BASE} \
+ -DCMAKE_CROSSCOMPILING=ON \
+ -DCMAKE_C_COMPILER_FORCED=ON \
+ -DCMAKE_CXX_COMPILER_FORCED=ON \
+ -DCOMPILER_RT_BUILD_BUILTINS=ON \
+ -DCOMPILER_RT_BUILTINS_ENABLE_PIC=OFF \
+ -DCMAKE_SIZEOF_VOID_P=4 \
+ -DCOMPILER_RT_OS_DIR= \
+ -DCAN_TARGET_hexagon=1 \
+ -DCAN_TARGET_x86_64=0 \
+ -DCOMPILER_RT_SUPPORTED_ARCH=hexagon \
+ -DLLVM_ENABLE_PROJECTS="compiler-rt" \
+ "$BASE/llvm-project/compiler-rt"
+ ninja install-compiler-rt
+}
+
+build_musl_headers() {
+ fetch "$BASE/musl" "$MUSL_URL"
+ cd "$BASE/musl"
+ make clean
+ CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \
+ CROSS_COMPILE=hexagon-unknown-linux-musl \
+ LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \
+ CROSS_CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \
+ ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE}
+ PATH=${TOOLCHAIN_BIN}:$PATH make CROSS_COMPILE= install-headers
+
+ cd ${HEX_SYSROOT}/..
+ ln -sf hexagon-unknown-linux-musl hexagon
+}
+
+build_kernel_headers() {
+ fetch "$BASE/linux" "$LINUX_URL"
+ mkdir -p "$BASE/build-linux"
+ cd "$BASE/linux"
+ make O=../build-linux ARCH=hexagon \
+ KBUILD_CFLAGS_KERNEL="-mlong-calls" \
+ CC=${TOOLCHAIN_BIN}/hexagon-unknown-linux-musl-clang \
+ LD=${TOOLCHAIN_BIN}/ld.lld \
+ KBUILD_VERBOSE=1 comet_defconfig
+ make mrproper
+
+ cd "$BASE/build-linux"
+ make \
+ ARCH=hexagon \
+ CC=${TOOLCHAIN_BIN}/clang \
+ INSTALL_HDR_PATH=${HEX_TOOLS_TARGET_BASE} \
+ V=1 \
+ headers_install
+}
+
+build_musl() {
+ cd "$BASE/musl"
+ make clean
+ CROSS_COMPILE=hexagon-unknown-linux-musl- \
+ AR=llvm-ar \
+ RANLIB=llvm-ranlib \
+ STRIP=llvm-strip \
+ CC=clang \
+ LIBCC=${HEX_TOOLS_TARGET_BASE}/lib/libclang_rt.builtins-hexagon.a \
+ CFLAGS="-G0 -O0 -mv65 -fno-builtin -fno-rounding-math --target=hexagon-unknown-linux-musl" \
+ ./configure --target=hexagon --prefix=${HEX_TOOLS_TARGET_BASE}
+ PATH=${TOOLCHAIN_BIN}/:$PATH make CROSS_COMPILE= install
+ cd ${HEX_TOOLS_TARGET_BASE}/lib
+ ln -sf libc.so ld-musl-hexagon.so
+ ln -sf ld-musl-hexagon.so ld-musl-hexagon.so.1
+ cdp ${HEX_TOOLS_TARGET_BASE}/../lib
+ ln -sf ../usr/lib/ld-musl-hexagon.so.1
+}
+
+build_llvm_clang
+build_kernel_headers
+build_musl_headers
+build_clang_rt
+build_musl
diff --git a/tests/docker/dockerfiles/debian-powerpc-cross.docker b/tests/docker/dockerfiles/debian-powerpc-cross.docker
deleted file mode 100644
index 07e1789650..0000000000
--- a/tests/docker/dockerfiles/debian-powerpc-cross.docker
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Docker powerpc cross-compiler target
-#
-# This docker target builds on the debian Buster base image.
-#
-FROM qemu/debian10
-
-RUN apt update && \
- DEBIAN_FRONTEND=noninteractive eatmydata \
- apt install -y --no-install-recommends \
- gcc-powerpc-linux-gnu \
- libc6-dev-powerpc-cross
diff --git a/tests/docker/dockerfiles/debian-powerpc-test-cross.docker b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker
new file mode 100644
index 0000000000..36b336f709
--- /dev/null
+++ b/tests/docker/dockerfiles/debian-powerpc-test-cross.docker
@@ -0,0 +1,17 @@
+#
+# Docker powerpc/ppc64/ppc64le cross-compiler target
+#
+# This docker target builds on the debian Bullseye base image.
+#
+FROM qemu/debian11
+
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ gcc-powerpc-linux-gnu \
+ libc6-dev-powerpc-cross \
+ gcc-10-powerpc64-linux-gnu \
+ libc6-dev-ppc64-cross \
+ gcc-10-powerpc64le-linux-gnu \
+ libc6-dev-ppc64el-cross
+
diff --git a/tests/docker/dockerfiles/debian-ppc64-cross.docker b/tests/docker/dockerfiles/debian-ppc64-cross.docker
deleted file mode 100644
index 8efe68874e..0000000000
--- a/tests/docker/dockerfiles/debian-ppc64-cross.docker
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Docker ppc64 cross-compiler target
-#
-# This docker target builds on the debian Buster base image.
-FROM qemu/debian10
-
-RUN apt update && \
- DEBIAN_FRONTEND=noninteractive eatmydata \
- apt install -y --no-install-recommends \
- gcc-powerpc64-linux-gnu \
- libc6-dev-ppc64-cross
diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker
index d034acbd25..63cf835ec5 100644
--- a/tests/docker/dockerfiles/debian10.docker
+++ b/tests/docker/dockerfiles/debian10.docker
@@ -32,6 +32,7 @@ RUN apt update && \
psmisc \
python3 \
python3-sphinx \
+ python3-sphinx-rtd-theme \
$(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2)
ENV FEATURES docs
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index 966072c08e..66cdb06c19 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,6 +1,7 @@
FROM fedora:33
ENV PACKAGES \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index 81b5659e9c..3733df63e9 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -4,6 +4,7 @@ FROM fedora:33
ENV PACKAGES \
bc \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index bcb428e724..2564ce4979 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -4,6 +4,7 @@ FROM fedora:33
ENV PACKAGES \
bc \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 915fdc1845..0979c0e1f4 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -32,6 +32,7 @@ ENV PACKAGES \
libcurl-devel \
libepoxy-devel \
libfdt-devel \
+ libbpf-devel \
libiscsi-devel \
libjpeg-devel \
libpmem-devel \
@@ -92,6 +93,7 @@ ENV PACKAGES \
python3-pillow \
python3-pip \
python3-sphinx \
+ python3-sphinx_rtd_theme \
python3-virtualenv \
rdma-core-devel \
SDL2-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 0e64893e4a..f7e1cbfbe6 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -5,6 +5,7 @@ ENV PACKAGES \
bc \
brlapi-devel \
bzip2 \
+ ccache \
cyrus-sasl-devel \
gcc \
gcc-c++ \
diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker
index b5ef7a8198..98a527361c 100644
--- a/tests/docker/dockerfiles/ubuntu.docker
+++ b/tests/docker/dockerfiles/ubuntu.docker
@@ -63,6 +63,7 @@ ENV PACKAGES \
ninja-build \
python3-yaml \
python3-sphinx \
+ python3-sphinx-rtd-theme \
sparse \
xfslibs-dev
RUN apt-get update && \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 9b0a19ba5e..c0d3642507 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -48,6 +48,7 @@ ENV PACKAGES \
make \
python3-yaml \
python3-sphinx \
+ python3-sphinx-rtd-theme \
ninja-build \
sparse \
xfslibs-dev
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 9750016e51..f1e0ebad49 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -58,6 +58,7 @@ ENV PACKAGES flex bison \
python3-pil \
python3-pip \
python3-sphinx \
+ python3-sphinx-rtd-theme \
python3-venv \
python3-yaml \
rpm2cpio \
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
index 4ba5e1d2d4..c24baf8535 100644
--- a/tests/fp/fp-bench.c
+++ b/tests/fp/fp-bench.c
@@ -14,6 +14,7 @@
#include <math.h>
#include <fenv.h>
#include "qemu/timer.h"
+#include "qemu/int128.h"
#include "fpu/softfloat.h"
/* amortize the computation of random inputs */
@@ -50,8 +51,10 @@ static const char * const op_names[] = {
enum precision {
PREC_SINGLE,
PREC_DOUBLE,
+ PREC_QUAD,
PREC_FLOAT32,
PREC_FLOAT64,
+ PREC_FLOAT128,
PREC_MAX_NR,
};
@@ -89,6 +92,7 @@ union fp {
double d;
float32 f32;
float64 f64;
+ float128 f128;
uint64_t u64;
};
@@ -113,6 +117,10 @@ struct op_desc {
static uint64_t random_ops[MAX_OPERANDS] = {
SEED_A, SEED_B, SEED_C,
};
+
+static float128 random_quad_ops[MAX_OPERANDS] = {
+ {SEED_A, SEED_B}, {SEED_B, SEED_C}, {SEED_C, SEED_A},
+};
static float_status soft_status;
static enum precision precision;
static enum op operation;
@@ -141,25 +149,45 @@ 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];
switch (prec) {
case PREC_SINGLE:
case PREC_FLOAT32:
+ {
+ uint64_t r = random_ops[i];
do {
r = xorshift64star(r);
} while (!float32_is_normal(r));
+ random_ops[i] = r;
break;
+ }
case PREC_DOUBLE:
case PREC_FLOAT64:
+ {
+ uint64_t r = random_ops[i];
do {
r = xorshift64star(r);
} while (!float64_is_normal(r));
+ random_ops[i] = r;
break;
+ }
+ case PREC_QUAD:
+ case PREC_FLOAT128:
+ {
+ float128 r = random_quad_ops[i];
+ uint64_t hi = r.high;
+ uint64_t lo = r.low;
+ do {
+ hi = xorshift64star(hi);
+ lo = xorshift64star(lo);
+ r = make_float128(hi, lo);
+ } while (!float128_is_normal(r));
+ random_quad_ops[i] = r;
+ break;
+ }
default:
g_assert_not_reached();
}
- random_ops[i] = r;
}
}
@@ -184,6 +212,13 @@ static void fill_random(union fp *ops, int n_ops, enum precision prec,
ops[i].f64 = float64_chs(ops[i].f64);
}
break;
+ case PREC_QUAD:
+ case PREC_FLOAT128:
+ ops[i].f128 = random_quad_ops[i];
+ if (no_neg && float128_is_neg(ops[i].f128)) {
+ ops[i].f128 = float128_chs(ops[i].f128);
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -345,6 +380,41 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
}
}
break;
+ case PREC_FLOAT128:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ float128 a = ops[0].f128;
+ float128 b = ops[1].f128;
+ float128 c = ops[2].f128;
+
+ switch (op) {
+ case OP_ADD:
+ res.f128 = float128_add(a, b, &soft_status);
+ break;
+ case OP_SUB:
+ res.f128 = float128_sub(a, b, &soft_status);
+ break;
+ case OP_MUL:
+ res.f128 = float128_mul(a, b, &soft_status);
+ break;
+ case OP_DIV:
+ res.f128 = float128_div(a, b, &soft_status);
+ break;
+ case OP_FMA:
+ res.f128 = float128_muladd(a, b, c, 0, &soft_status);
+ break;
+ case OP_SQRT:
+ res.f128 = float128_sqrt(a, &soft_status);
+ break;
+ case OP_CMP:
+ res.u64 = float128_compare_quiet(a, b, &soft_status);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -369,7 +439,8 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
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(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _float128, float128, PREC_FLOAT128, op, n_ops)
GEN_BENCH_ALL_TYPES(add, OP_ADD, 2)
GEN_BENCH_ALL_TYPES(sub, OP_SUB, 2)
@@ -383,7 +454,8 @@ GEN_BENCH_ALL_TYPES(cmp, OP_CMP, 2)
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_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float128, float128, PREC_FLOAT128, op, n)
GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
#undef GEN_BENCH_ALL_TYPES_NO_NEG
@@ -397,6 +469,7 @@ GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
[PREC_DOUBLE] = bench_ ## opname ## _double, \
[PREC_FLOAT32] = bench_ ## opname ## _float32, \
[PREC_FLOAT64] = bench_ ## opname ## _float64, \
+ [PREC_FLOAT128] = bench_ ## opname ## _float128, \
}
static const bench_func_t bench_funcs[OP_MAX_NR][PREC_MAX_NR] = {
@@ -445,7 +518,7 @@ static void usage_complete(int argc, char *argv[])
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). "
+ fprintf(stderr, " -p = floating point precision (single, double, quad[soft only]). "
"Default: single\n");
fprintf(stderr, " -r = rounding mode (even, zero, down, up, tieaway). "
"Default: even\n");
@@ -565,6 +638,8 @@ static void parse_args(int argc, char *argv[])
precision = PREC_SINGLE;
} else if (!strcmp(optarg, "double")) {
precision = PREC_DOUBLE;
+ } else if (!strcmp(optarg, "quad")) {
+ precision = PREC_QUAD;
} else {
fprintf(stderr, "Unsupported precision '%s'\n", optarg);
exit(EXIT_FAILURE);
@@ -608,6 +683,9 @@ static void parse_args(int argc, char *argv[])
case PREC_DOUBLE:
precision = PREC_FLOAT64;
break;
+ case PREC_QUAD:
+ precision = PREC_FLOAT128;
+ break;
default:
g_assert_not_reached();
}
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 5a4cad8c8b..ff131afbde 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -717,7 +717,7 @@ static void do_testfloat(int op, int rmode, bool exact)
test_abz_f128(true_abz_f128M, subj_abz_f128M);
break;
case F128_MULADD:
- not_implemented();
+ test_abcz_f128(slow_f128M_mulAdd, qemu_f128M_mulAdd);
break;
case F128_SQRT:
test_az_f128(slow_f128M_sqrt, qemu_f128M_sqrt);
diff --git a/tests/fp/wrap.c.inc b/tests/fp/wrap.c.inc
index 0cbd20013e..cb1bb77e4c 100644
--- a/tests/fp/wrap.c.inc
+++ b/tests/fp/wrap.c.inc
@@ -574,6 +574,18 @@ WRAP_MULADD(qemu_f32_mulAdd, float32_muladd, float32)
WRAP_MULADD(qemu_f64_mulAdd, float64_muladd, float64)
#undef WRAP_MULADD
+static void qemu_f128M_mulAdd(const float128_t *ap, const float128_t *bp,
+ const float128_t *cp, float128_t *res)
+{
+ float128 a, b, c, ret;
+
+ a = soft_to_qemu128(*ap);
+ b = soft_to_qemu128(*bp);
+ c = soft_to_qemu128(*cp);
+ ret = float128_muladd(a, b, c, 0, &qsf);
+ *res = qemu_to_soft128(ret);
+}
+
#define WRAP_CMP16(name, func, retcond) \
static bool name(float16_t a, float16_t b) \
{ \
diff --git a/tests/migration/guestperf/comparison.py b/tests/migration/guestperf/comparison.py
index ba2edbe546..c03b3f6d7e 100644
--- a/tests/migration/guestperf/comparison.py
+++ b/tests/migration/guestperf/comparison.py
@@ -121,4 +121,18 @@ COMPARISONS = [
Scenario("compr-xbzrle-cache-50",
compression_xbzrle=True, compression_xbzrle_cache=50),
]),
+
+
+ # Looking at effect of multifd with
+ # varying numbers of channels
+ Comparison("compr-multifd", scenarios = [
+ Scenario("compr-multifd-channels-4",
+ multifd=True, multifd_channels=2),
+ Scenario("compr-multifd-channels-8",
+ multifd=True, multifd_channels=8),
+ Scenario("compr-multifd-channels-32",
+ multifd=True, multifd_channels=32),
+ Scenario("compr-multifd-channels-64",
+ multifd=True, multifd_channels=64),
+ ]),
]
diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py
index 6b49aed579..208e095794 100644
--- a/tests/migration/guestperf/engine.py
+++ b/tests/migration/guestperf/engine.py
@@ -188,6 +188,22 @@ class Engine(object):
1024 * 1024 * 1024 / 100 *
scenario._compression_xbzrle_cache))
+ if scenario._multifd:
+ resp = src.command("migrate-set-capabilities",
+ capabilities = [
+ { "capability": "multifd",
+ "state": True }
+ ])
+ resp = src.command("migrate-set-parameters",
+ multifd_channels=scenario._multifd_channels)
+ resp = dst.command("migrate-set-capabilities",
+ capabilities = [
+ { "capability": "multifd",
+ "state": True }
+ ])
+ resp = dst.command("migrate-set-parameters",
+ multifd_channels=scenario._multifd_channels)
+
resp = src.command("migrate", uri=connect_uri)
post_copy = False
diff --git a/tests/migration/guestperf/scenario.py b/tests/migration/guestperf/scenario.py
index 28ef36c26d..de70d9b2f5 100644
--- a/tests/migration/guestperf/scenario.py
+++ b/tests/migration/guestperf/scenario.py
@@ -29,7 +29,8 @@ class Scenario(object):
post_copy=False, post_copy_iters=5,
auto_converge=False, auto_converge_step=10,
compression_mt=False, compression_mt_threads=1,
- compression_xbzrle=False, compression_xbzrle_cache=10):
+ compression_xbzrle=False, compression_xbzrle_cache=10,
+ multifd=False, multifd_channels=2):
self._name = name
@@ -56,6 +57,9 @@ class Scenario(object):
self._compression_xbzrle = compression_xbzrle
self._compression_xbzrle_cache = compression_xbzrle_cache # percentage of guest RAM
+ self._multifd = multifd
+ self._multifd_channels = multifd_channels
+
def serialize(self):
return {
"name": self._name,
@@ -73,6 +77,8 @@ class Scenario(object):
"compression_mt_threads": self._compression_mt_threads,
"compression_xbzrle": self._compression_xbzrle,
"compression_xbzrle_cache": self._compression_xbzrle_cache,
+ "multifd": self._multifd,
+ "multifd_channels": self._multifd_channels,
}
@classmethod
@@ -92,4 +98,6 @@ class Scenario(object):
data["compression_mt"],
data["compression_mt_threads"],
data["compression_xbzrle"],
- data["compression_xbzrle_cache"])
+ data["compression_xbzrle_cache"],
+ data["multifd"],
+ data["multifd_channels"])
diff --git a/tests/migration/guestperf/shell.py b/tests/migration/guestperf/shell.py
index f838888809..8a809e3dda 100644
--- a/tests/migration/guestperf/shell.py
+++ b/tests/migration/guestperf/shell.py
@@ -122,6 +122,11 @@ class Shell(BaseShell):
parser.add_argument("--compression-xbzrle", dest="compression_xbzrle", default=False, action="store_true")
parser.add_argument("--compression-xbzrle-cache", dest="compression_xbzrle_cache", default=10, type=int)
+ parser.add_argument("--multifd", dest="multifd", default=False,
+ action="store_true")
+ parser.add_argument("--multifd-channels", dest="multifd_channels",
+ default=2, type=int)
+
def get_scenario(self, args):
return Scenario(name="perfreport",
downtime=args.downtime,
@@ -142,7 +147,10 @@ class Shell(BaseShell):
compression_mt_threads=args.compression_mt_threads,
compression_xbzrle=args.compression_xbzrle,
- compression_xbzrle_cache=args.compression_xbzrle_cache)
+ compression_xbzrle_cache=args.compression_xbzrle_cache,
+
+ multifd=args.multifd,
+ multifd_channels=args.multifd_channels)
def run(self, argv):
args = self._parser.parse_args(argv)
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
index 40e64a9a8f..ba377543b0 100755
--- a/tests/qemu-iotests/005
+++ b/tests/qemu-iotests/005
@@ -52,11 +52,6 @@ if [ "$IMGFMT" = "vpc" ]; then
_notrun "image format $IMGFMT does not support large image sizes"
fi
-# sheepdog image is limited to 4TB, so we can't test it here
-if [ "$IMGPROTO" = "sheepdog" ]; then
- _notrun "image protocol $IMGPROTO does not support large image sizes"
-fi
-
# Sanity check: For raw, we require a file system that permits the creation
# of a HUGE (but very sparse) file. Check we can create it before continuing.
if [ "$IMGFMT" = "raw" ]; then
diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025
index da77ed3154..80686a30d5 100755
--- a/tests/qemu-iotests/025
+++ b/tests/qemu-iotests/025
@@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.pattern
_supported_fmt raw qcow2 qed luks
-_supported_proto file sheepdog rbd nfs fuse
+_supported_proto file rbd nfs fuse
echo "=== Creating image"
echo
diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231
index 0f66d0ca36..8e6c6447c1 100755
--- a/tests/qemu-iotests/231
+++ b/tests/qemu-iotests/231
@@ -55,6 +55,10 @@ _filter_conf()
$QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf
$QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf
+# Regression test: the qemu-img invocation is expected to fail, but it should
+# not seg fault the parser.
+$QEMU_IMG create "rbd:rbd/aa\/bb:conf=${BOGUS_CONF}" 1M 2>&1 | _filter_conf
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out
index 579ba11c16..a785a6e859 100644
--- a/tests/qemu-iotests/231.out
+++ b/tests/qemu-iotests/231.out
@@ -1,9 +1,10 @@
QA output created by 231
-qemu-img: RBD options encoded in the filename as keyvalue pairs is deprecated. Future versions may cease to parse these options in the future.
+qemu-img: warning: RBD options encoded in the filename as keyvalue pairs is deprecated
unable to get monitor info from DNS SRV with service name: ceph-mon
-no monitors specified to connect to.
qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory
unable to get monitor info from DNS SRV with service name: ceph-mon
-no monitors specified to connect to.
qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory
+Formatting 'rbd:rbd/aa\/bb:conf=BOGUS_CONF', fmt=raw size=1048576
+unable to get monitor info from DNS SRV with service name: ceph-mon
+qemu-img: rbd:rbd/aa\/bb:conf=BOGUS_CONF: error connecting: No such file or directory
*** done
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
index e0982831ae..89ed25e506 100644
--- a/tests/qemu-iotests/240.out
+++ b/tests/qemu-iotests/240.out
@@ -15,7 +15,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach two SCSI disks using the same block device and the same iothread==
+.==Attach two SCSI disks using the same block device and the same iothread==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
@@ -32,7 +32,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach two SCSI disks using the same block device but different iothreads==
+.==Attach two SCSI disks using the same block device but different iothreads==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
@@ -55,7 +55,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach a SCSI disks using the same block device as a NBD server==
+.==Attach a SCSI disks using the same block device as a NBD server==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
@@ -68,7 +68,7 @@
{"return": {}}
{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
-....
+.
----------------------------------------------------------------------
Ran 4 tests
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 4b33dcaf5c..99c12f4f98 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -1,16 +1,16 @@
-{"execute": "job-finalize", "arguments": {"id": "commit0"}}
+..{"execute": "job-finalize", "arguments": {"id": "commit0"}}
{"return": {}}
{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+...{"execute": "job-finalize", "arguments": {"id": "stream0"}}
{"return": {}}
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+.{"execute": "job-finalize", "arguments": {"id": "stream0"}}
{"return": {}}
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-.....................
+...............
----------------------------------------------------------------------
Ran 21 tests
diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264
index 4f96825a22..bc431d1a19 100755
--- a/tests/qemu-iotests/264
+++ b/tests/qemu-iotests/264
@@ -95,7 +95,7 @@ class TestNbdReconnect(iotests.QMPTestCase):
self.assert_qmp(result, 'return', {})
def cancel_job(self):
- result = self.vm.qmp('block-job-cancel', device='drive0')
+ result = self.vm.qmp('block-job-cancel', device='drive0', force=True)
self.assert_qmp(result, 'return', {})
start_t = time.time()
diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out
index ad34b2ca2c..5ff91f116c 100644
--- a/tests/qemu-iotests/295.out
+++ b/tests/qemu-iotests/295.out
@@ -4,7 +4,7 @@
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
@@ -13,7 +13,7 @@ Job failed: Invalid password, cannot unlock any keyslot
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
@@ -33,7 +33,7 @@ Job failed: All the active keyslots match the (old) password that was given and
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
-...
+.
----------------------------------------------------------------------
Ran 3 tests
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
index cb2859a15c..6c69735604 100644
--- a/tests/qemu-iotests/296.out
+++ b/tests/qemu-iotests/296.out
@@ -13,7 +13,7 @@ Job failed: Failed to get shared "consistent read" lock
qemu-img: Failed to get shared "consistent read" lock
Is another process using the image [TEST_DIR/test.img]?
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
Job failed: Block node is read-only
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@@ -26,15 +26,15 @@ Job failed: Failed to get shared "consistent read" lock
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
{"return": {}}
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
{"return": {}}
{"return": {}}
-....
+.
----------------------------------------------------------------------
Ran 4 tests
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index d1c87ceaf1..2dd529eb75 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -19,6 +19,9 @@
import os
import sys
import argparse
+import shutil
+from pathlib import Path
+
from findtests import TestFinder
from testenv import TestEnv
from testrunner import TestRunner
@@ -65,8 +68,7 @@ def make_argparser() -> argparse.ArgumentParser:
mg.add_argument('-' + fmt, dest='imgfmt', action='store_const',
const=fmt, help=f'test {fmt}')
- protocol_list = ['file', 'rbd', 'sheepdog', 'nbd', 'ssh', 'nfs',
- 'fuse']
+ protocol_list = ['file', 'rbd', 'nbd', 'ssh', 'nfs', 'fuse']
g_prt = p.add_argument_group(
' image protocol options',
'The following options set the IMGPROTO environment variable. '
@@ -101,7 +103,7 @@ def make_argparser() -> argparse.ArgumentParser:
'rerun failed ./check command, starting from the '
'middle of the process.')
g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*',
- help='tests to run')
+ help='tests to run, or "--" followed by a command')
return p
@@ -114,6 +116,20 @@ if __name__ == '__main__':
imgopts=args.imgopts, misalign=args.misalign,
debug=args.debug, valgrind=args.valgrind)
+ if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--':
+ if not args.tests:
+ sys.exit("missing command after '--'")
+ cmd = args.tests
+ env.print_env()
+ exec_pathstr = shutil.which(cmd[0])
+ if exec_pathstr is None:
+ sys.exit('command not found: ' + cmd[0])
+ exec_path = Path(exec_pathstr).resolve()
+ cmd[0] = str(exec_path)
+ full_env = env.prepare_subprocess(cmd)
+ os.chdir(exec_path.parent)
+ os.execve(cmd[0], cmd, full_env)
+
testfinder = TestFinder(test_dir=env.source_iotests)
groups = args.groups.split(',') if args.groups else None
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 7f49c9716d..cbbf6d7c7f 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -641,10 +641,6 @@ _cleanup_test_img()
rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null
;;
- sheepdog)
- collie vdi delete "$TEST_DIR/t.$IMGFMT"
- ;;
-
esac
}
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 5af0182895..777fa2ec0e 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -20,7 +20,6 @@ import atexit
import bz2
from collections import OrderedDict
import faulthandler
-import io
import json
import logging
import os
@@ -32,7 +31,7 @@ import subprocess
import sys
import time
from typing import (Any, Callable, Dict, Iterable,
- List, Optional, Sequence, Tuple, TypeVar)
+ List, Optional, Sequence, TextIO, Tuple, Type, TypeVar)
import unittest
from contextlib import contextmanager
@@ -113,15 +112,14 @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
Run a tool and return both its output and its exit code
"""
stderr = subprocess.STDOUT if connect_stderr else None
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=stderr,
- universal_newlines=True)
- output = subp.communicate()[0]
- if subp.returncode < 0:
- cmd = ' '.join(args)
- sys.stderr.write(f'{tool} received signal {-subp.returncode}: {cmd}\n')
- return (output, subp.returncode)
+ with subprocess.Popen(args, stdout=subprocess.PIPE,
+ stderr=stderr, universal_newlines=True) as subp:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
+ cmd = ' '.join(args)
+ sys.stderr.write(f'{tool} received signal \
+ {-subp.returncode}: {cmd}\n')
+ return (output, subp.returncode)
def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
"""
@@ -237,6 +235,9 @@ def qemu_io_silent_check(*args):
class QemuIoInteractive:
def __init__(self, *args):
self.args = qemu_io_args_no_fmt + list(args)
+ # We need to keep the Popen objext around, and not
+ # close it immediately. Therefore, disable the pylint check:
+ # pylint: disable=consider-using-with
self._p = subprocess.Popen(self.args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -310,22 +311,22 @@ def qemu_nbd_popen(*args):
cmd.extend(args)
log('Start NBD server')
- p = subprocess.Popen(cmd)
- try:
- while not os.path.exists(pid_file):
- if p.poll() is not None:
- raise RuntimeError(
- "qemu-nbd terminated with exit code {}: {}"
- .format(p.returncode, ' '.join(cmd)))
-
- time.sleep(0.01)
- yield
- finally:
- if os.path.exists(pid_file):
- os.remove(pid_file)
- log('Kill NBD server')
- p.kill()
- p.wait()
+ with subprocess.Popen(cmd) as p:
+ try:
+ while not os.path.exists(pid_file):
+ if p.poll() is not None:
+ raise RuntimeError(
+ "qemu-nbd terminated with exit code {}: {}"
+ .format(p.returncode, ' '.join(cmd)))
+
+ time.sleep(0.01)
+ yield
+ finally:
+ if os.path.exists(pid_file):
+ os.remove(pid_file)
+ log('Kill NBD server')
+ p.kill()
+ p.wait()
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
'''Return True if two image files are identical'''
@@ -334,13 +335,12 @@ def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
def create_image(name, size):
'''Create a fully-allocated raw image with sector markers'''
- file = open(name, 'wb')
- i = 0
- while i < size:
- sector = struct.pack('>l504xl', i // 512, i // 512)
- file.write(sector)
- i = i + 512
- file.close()
+ with open(name, 'wb') as file:
+ i = 0
+ while i < size:
+ sector = struct.pack('>l504xl', i // 512, i // 512)
+ file.write(sector)
+ i = i + 512
def image_size(img):
'''Return image's virtual size'''
@@ -1271,37 +1271,54 @@ def skip_if_user_is_root(func):
return func(*args, **kwargs)
return func_wrapper
-def execute_unittest(debug=False):
+# We need to filter out the time taken from the output so that
+# qemu-iotest can reliably diff the results against master output,
+# and hide skipped tests from the reference output.
+
+class ReproducibleTestResult(unittest.TextTestResult):
+ def addSkip(self, test, reason):
+ # Same as TextTestResult, but print dot instead of "s"
+ unittest.TestResult.addSkip(self, test, reason)
+ if self.showAll:
+ self.stream.writeln("skipped {0!r}".format(reason))
+ elif self.dots:
+ self.stream.write(".")
+ self.stream.flush()
+
+class ReproducibleStreamWrapper:
+ def __init__(self, stream: TextIO):
+ self.stream = stream
+
+ def __getattr__(self, attr):
+ if attr in ('stream', '__getstate__'):
+ raise AttributeError(attr)
+ return getattr(self.stream, attr)
+
+ def write(self, arg=None):
+ arg = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', arg)
+ arg = re.sub(r' \(skipped=\d+\)', r'', arg)
+ self.stream.write(arg)
+
+class ReproducibleTestRunner(unittest.TextTestRunner):
+ def __init__(self, stream: Optional[TextIO] = None,
+ resultclass: Type[unittest.TestResult] = ReproducibleTestResult,
+ **kwargs: Any) -> None:
+ rstream = ReproducibleStreamWrapper(stream or sys.stdout)
+ super().__init__(stream=rstream, # type: ignore
+ descriptions=True,
+ resultclass=resultclass,
+ **kwargs)
+
+def execute_unittest(argv: List[str], debug: bool = False) -> None:
"""Executes unittests within the calling module."""
- verbosity = 2 if debug else 1
-
- if debug:
- output = sys.stdout
- else:
- # We need to filter out the time taken from the output so that
- # qemu-iotest can reliably diff the results against master output.
- output = io.StringIO()
-
- runner = unittest.TextTestRunner(stream=output, descriptions=True,
- verbosity=verbosity)
- try:
- # unittest.main() will use sys.exit(); so expect a SystemExit
- # exception
- unittest.main(testRunner=runner)
- finally:
- # We need to filter out the time taken from the output so that
- # qemu-iotest can reliably diff the results against master output.
- if not debug:
- out = output.getvalue()
- out = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', out)
-
- # Hide skipped tests from the reference output
- out = re.sub(r'OK \(skipped=\d+\)', 'OK', out)
- out_first_line, out_rest = out.split('\n', 1)
- out = out_first_line.replace('s', '.') + '\n' + out_rest
-
- sys.stderr.write(out)
+ # Some tests have warnings, especially ResourceWarnings for unclosed
+ # files and sockets. Ignore them for now to ensure reproducibility of
+ # the test output.
+ unittest.main(argv=argv,
+ testRunner=ReproducibleTestRunner,
+ verbosity=2 if debug else 1,
+ warnings=None if sys.warnoptions else 'ignore')
def execute_setup_common(supported_fmts: Sequence[str] = (),
supported_platforms: Sequence[str] = (),
@@ -1338,7 +1355,7 @@ def execute_test(*args, test_function=None, **kwargs):
debug = execute_setup_common(*args, **kwargs)
if not test_function:
- execute_unittest(debug)
+ execute_unittest(sys.argv, debug)
else:
test_function()
diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc
index 7a6c0a9474..f2c0b522ac 100644
--- a/tests/qemu-iotests/pylintrc
+++ b/tests/qemu-iotests/pylintrc
@@ -19,6 +19,9 @@ disable=invalid-name,
too-many-public-methods,
# pylint warns about Optional[] etc. as unsubscriptable in 3.9
unsubscriptable-object,
+ # Sometimes we need to disable a newly introduced pylint warning.
+ # Doing so should not produce a warning in older versions of pylint.
+ bad-option-value,
# These are temporary, and should be removed:
missing-docstring,
too-many-return-statements,
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index 6d27712617..0c3fe75636 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -25,7 +25,7 @@ import collections
import random
import subprocess
import glob
-from typing import Dict, Any, Optional, ContextManager
+from typing import List, Dict, Any, Optional, ContextManager
def isxfile(path: str) -> bool:
@@ -74,6 +74,21 @@ class TestEnv(ContextManager['TestEnv']):
'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX',
'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_']
+ def prepare_subprocess(self, args: List[str]) -> Dict[str, str]:
+ if self.debug:
+ args.append('-d')
+
+ with open(args[0], encoding="utf-8") as f:
+ try:
+ if f.readline().rstrip() == '#!/usr/bin/env python3':
+ args.insert(0, self.python)
+ except UnicodeDecodeError: # binary test? for future.
+ pass
+
+ os_env = os.environ.copy()
+ os_env.update(self.get_env())
+ return os_env
+
def get_env(self) -> Dict[str, str]:
env = {}
for v in self.env_variables:
@@ -105,7 +120,7 @@ class TestEnv(ContextManager['TestEnv']):
try:
self.sock_dir = os.environ['SOCK_DIR']
self.tmp_sock_dir = False
- Path(self.test_dir).mkdir(parents=True, exist_ok=True)
+ Path(self.sock_dir).mkdir(parents=True, exist_ok=True)
except KeyError:
self.sock_dir = tempfile.mkdtemp()
self.tmp_sock_dir = True
@@ -269,7 +284,8 @@ IMGPROTO -- {IMGPROTO}
PLATFORM -- {platform}
TEST_DIR -- {TEST_DIR}
SOCK_DIR -- {SOCK_DIR}
-SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}"""
+SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}
+"""
args = collections.defaultdict(str, self.get_env())
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index 1fc61fcaa3..4a6ec421ed 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -129,7 +129,6 @@ class TestRunner(ContextManager['TestRunner']):
def __init__(self, env: TestEnv, makecheck: bool = False,
color: str = 'auto') -> None:
self.env = env
- self.test_run_env = self.env.get_env()
self.makecheck = makecheck
self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env)
@@ -243,32 +242,21 @@ class TestRunner(ContextManager['TestRunner']):
silent_unlink(p)
args = [str(f_test.resolve())]
- if self.env.debug:
- args.append('-d')
-
- with f_test.open(encoding="utf-8") as f:
- try:
- if f.readline().rstrip() == '#!/usr/bin/env python3':
- args.insert(0, self.env.python)
- except UnicodeDecodeError: # binary test? for future.
- pass
-
- env = os.environ.copy()
- env.update(self.test_run_env)
+ env = self.env.prepare_subprocess(args)
t0 = time.time()
with f_bad.open('w', encoding="utf-8") as f:
- proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env,
- stdout=f, stderr=subprocess.STDOUT)
- try:
- proc.wait()
- except KeyboardInterrupt:
- proc.terminate()
- proc.wait()
- return TestResult(status='not run',
- description='Interrupted by user',
- interrupted=True)
- ret = proc.returncode
+ with subprocess.Popen(args, cwd=str(f_test.parent), env=env,
+ stdout=f, stderr=subprocess.STDOUT) as proc:
+ try:
+ proc.wait()
+ except KeyboardInterrupt:
+ proc.terminate()
+ proc.wait()
+ return TestResult(status='not run',
+ description='Interrupted by user',
+ interrupted=True)
+ ret = proc.returncode
elapsed = round(time.time() - t0, 1)
@@ -328,7 +316,6 @@ class TestRunner(ContextManager['TestRunner']):
if not self.makecheck:
self.env.print_env()
- print()
test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c
index 5e1954852e..8073ccc205 100644
--- a/tests/qtest/ahci-test.c
+++ b/tests/qtest/ahci-test.c
@@ -1491,14 +1491,14 @@ static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd,
char *iso;
int fd;
AHCIOpts opts = {
- .size = (ATAPI_SECTOR_SIZE * nsectors),
+ .size = ((uint64_t)ATAPI_SECTOR_SIZE * nsectors),
.atapi = true,
.atapi_dma = dma,
.post_cb = ahci_cb_cmp_buff,
.set_bcl = override_bcl,
.bcl = bcl,
};
- uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
+ uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * (nsectors + 1);
/* Prepare ISO and fill 'tx' buffer */
fd = prepare_iso(iso_size, &tx, &iso);
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
index d74509b1c5..d40adddafa 100644
--- a/tests/qtest/boot-serial-test.c
+++ b/tests/qtest/boot-serial-test.c
@@ -61,13 +61,6 @@ static const uint8_t kernel_plml605[] = {
0xfc, 0xff, 0x00, 0xb8 /* bri -4 loop */
};
-static const uint8_t bios_moxiesim[] = {
- 0x20, 0x10, 0x00, 0x00, 0x03, 0xf8, /* ldi.s r1,0x3f8 */
- 0x1b, 0x20, 0x00, 0x00, 0x00, 0x54, /* ldi.b r2,'T' */
- 0x1e, 0x12, /* st.b r1,r2 */
- 0x1a, 0x00, 0x00, 0x00, 0x10, 0x00 /* jmpa 0x1000 */
-};
-
static const uint8_t bios_raspi2[] = {
0x08, 0x30, 0x9f, 0xe5, /* ldr r3,[pc,#8] Get base */
0x54, 0x20, 0xa0, 0xe3, /* mov r2,#'T' */
@@ -145,7 +138,6 @@ static testdef_t tests[] = {
sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 },
{ "microblazeel", "petalogix-ml605", "", "TT",
sizeof(kernel_plml605), kernel_plml605 },
- { "moxie", "moxiesim", "", "TT", sizeof(bios_moxiesim), 0, bios_moxiesim },
{ "arm", "raspi2", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 },
/* For hppa, force bios to output to serial by disabling graphics. */
{ "hppa", "hppa", "-vga none", "SeaBIOS wants SYSTEM HALT" },
diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c
index a42207d416..8492f02a9c 100644
--- a/tests/qtest/ipmi-bt-test.c
+++ b/tests/qtest/ipmi-bt-test.c
@@ -98,7 +98,8 @@ static void bt_wait_b_busy(void)
{
unsigned int count = 1000;
while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
usleep(100);
}
}
@@ -107,7 +108,8 @@ static void bt_wait_b2h_atn(void)
{
unsigned int count = 1000;
while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
usleep(100);
}
}
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index fc0a918c8d..afc24dd3e4 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -73,7 +73,8 @@ static void kcs_wait_ibf(void)
{
unsigned int count = 1000;
while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
}
}
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 1cddf5bdaa..1f5c8f1053 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -32,6 +32,7 @@ libqos_srcs = files('../libqtest.c',
'virtio-9p.c',
'virtio-balloon.c',
'virtio-blk.c',
+ 'vhost-user-blk.c',
'virtio-mmio.c',
'virtio-net.c',
'virtio-pci.c',
diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
index b3b1a31f81..d1dc491930 100644
--- a/tests/qtest/libqos/qgraph.c
+++ b/tests/qtest/libqos/qgraph.c
@@ -844,7 +844,7 @@ void qos_dump_graph(void)
}
qos_printf_literal("type=%d cmd_line='%s' [%s]\n",
node->type, node->command_line,
- node->available ? "available" : "UNAVAILBLE"
+ node->available ? "available" : "UNAVAILABLE"
);
}
g_list_free(keys);
diff --git a/tests/qtest/libqos/vhost-user-blk.c b/tests/qtest/libqos/vhost-user-blk.c
new file mode 100644
index 0000000000..568c3426ed
--- /dev/null
+++ b/tests/qtest/libqos/vhost-user-blk.c
@@ -0,0 +1,130 @@
+/*
+ * libqos driver framework
+ *
+ * Based on tests/qtest/libqos/virtio-blk.c
+ *
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * 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 "libqtest.h"
+#include "qemu/module.h"
+#include "standard-headers/linux/virtio_blk.h"
+#include "vhost-user-blk.h"
+
+#define PCI_SLOT 0x04
+#define PCI_FN 0x00
+
+/* virtio-blk-device */
+static void *qvhost_user_blk_get_driver(QVhostUserBlk *v_blk,
+ const char *interface)
+{
+ if (!g_strcmp0(interface, "vhost-user-blk")) {
+ return v_blk;
+ }
+ if (!g_strcmp0(interface, "virtio")) {
+ return v_blk->vdev;
+ }
+
+ fprintf(stderr, "%s not present in vhost-user-blk-device\n", interface);
+ g_assert_not_reached();
+}
+
+static void *qvhost_user_blk_device_get_driver(void *object,
+ const char *interface)
+{
+ QVhostUserBlkDevice *v_blk = object;
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
+}
+
+static void *vhost_user_blk_device_create(void *virtio_dev,
+ QGuestAllocator *t_alloc,
+ void *addr)
+{
+ QVhostUserBlkDevice *vhost_user_blk = g_new0(QVhostUserBlkDevice, 1);
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
+
+ interface->vdev = virtio_dev;
+
+ vhost_user_blk->obj.get_driver = qvhost_user_blk_device_get_driver;
+
+ return &vhost_user_blk->obj;
+}
+
+/* virtio-blk-pci */
+static void *qvhost_user_blk_pci_get_driver(void *object, const char *interface)
+{
+ QVhostUserBlkPCI *v_blk = object;
+ if (!g_strcmp0(interface, "pci-device")) {
+ return v_blk->pci_vdev.pdev;
+ }
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
+}
+
+static void *vhost_user_blk_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
+ void *addr)
+{
+ QVhostUserBlkPCI *vhost_user_blk = g_new0(QVhostUserBlkPCI, 1);
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
+ QOSGraphObject *obj = &vhost_user_blk->pci_vdev.obj;
+
+ virtio_pci_init(&vhost_user_blk->pci_vdev, pci_bus, addr);
+ interface->vdev = &vhost_user_blk->pci_vdev.vdev;
+
+ g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_BLOCK);
+
+ obj->get_driver = qvhost_user_blk_pci_get_driver;
+
+ return obj;
+}
+
+static void vhost_user_blk_register_nodes(void)
+{
+ /*
+ * FIXME: every test using these two nodes needs to setup a
+ * -drive,id=drive0 otherwise QEMU is not going to start.
+ * Therefore, we do not include "produces" edge for virtio
+ * and pci-device yet.
+ */
+
+ char *arg = g_strdup_printf("id=drv0,chardev=char1,addr=%x.%x",
+ PCI_SLOT, PCI_FN);
+
+ QPCIAddress addr = {
+ .devfn = QPCI_DEVFN(PCI_SLOT, PCI_FN),
+ };
+
+ QOSGraphEdgeOptions opts = { };
+
+ /* virtio-blk-device */
+ /** opts.extra_device_opts = "drive=drive0"; */
+ qos_node_create_driver("vhost-user-blk-device",
+ vhost_user_blk_device_create);
+ qos_node_consumes("vhost-user-blk-device", "virtio-bus", &opts);
+ qos_node_produces("vhost-user-blk-device", "vhost-user-blk");
+
+ /* virtio-blk-pci */
+ opts.extra_device_opts = arg;
+ add_qpci_address(&opts, &addr);
+ qos_node_create_driver("vhost-user-blk-pci", vhost_user_blk_pci_create);
+ qos_node_consumes("vhost-user-blk-pci", "pci-bus", &opts);
+ qos_node_produces("vhost-user-blk-pci", "vhost-user-blk");
+
+ g_free(arg);
+}
+
+libqos_init(vhost_user_blk_register_nodes);
diff --git a/tests/qtest/libqos/vhost-user-blk.h b/tests/qtest/libqos/vhost-user-blk.h
new file mode 100644
index 0000000000..2a03456a45
--- /dev/null
+++ b/tests/qtest/libqos/vhost-user-blk.h
@@ -0,0 +1,48 @@
+/*
+ * libqos driver framework
+ *
+ * Based on tests/qtest/libqos/virtio-blk.c
+ *
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef TESTS_LIBQOS_VHOST_USER_BLK_H
+#define TESTS_LIBQOS_VHOST_USER_BLK_H
+
+#include "qgraph.h"
+#include "virtio.h"
+#include "virtio-pci.h"
+
+typedef struct QVhostUserBlk QVhostUserBlk;
+typedef struct QVhostUserBlkPCI QVhostUserBlkPCI;
+typedef struct QVhostUserBlkDevice QVhostUserBlkDevice;
+
+struct QVhostUserBlk {
+ QVirtioDevice *vdev;
+};
+
+struct QVhostUserBlkPCI {
+ QVirtioPCIDevice pci_vdev;
+ QVhostUserBlk blk;
+};
+
+struct QVhostUserBlkDevice {
+ QOSGraphObject obj;
+ QVhostUserBlk blk;
+};
+
+#endif
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 71e359efcd..825b13a44c 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -907,7 +907,14 @@ const char *qtest_get_arch(void)
if (!end) {
fprintf(stderr, "Can't determine architecture from binary name.\n");
- abort();
+ exit(1);
+ }
+
+ if (!strstr(qemu, "-system-")) {
+ fprintf(stderr, "QTEST_QEMU_BINARY must end with *-system-<arch> "
+ "where 'arch' is the target\narchitecture (x86_64, aarch64, "
+ "etc).\n");
+ exit(1);
}
return end + 1;
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
index aab06b9fc2..138101b46a 100644
--- a/tests/qtest/machine-none-test.c
+++ b/tests/qtest/machine-none-test.c
@@ -32,7 +32,6 @@ static struct arch2cpu cpus_map[] = {
{ "i386", "qemu32,apic-id=0" },
{ "alpha", "ev67" },
{ "cris", "crisv32" },
- { "lm32", "lm32-full" },
{ "m68k", "m5206" },
{ "microblaze", "any" },
{ "microblazeel", "any" },
@@ -40,7 +39,6 @@ static struct arch2cpu cpus_map[] = {
{ "mipsel", "I7200" },
{ "mips64", "20Kc" },
{ "mips64el", "I6500" },
- { "moxie", "MoxieLite" },
{ "nios2", "FIXME" },
{ "or1k", "or1200" },
{ "ppc", "604" },
@@ -51,7 +49,6 @@ static struct arch2cpu cpus_map[] = {
{ "sparc", "LEON2" },
{ "sparc64", "Fujitsu Sparc64" },
{ "tricore", "tc1796" },
- { "unicore32", "UniCore-II" },
{ "xtensa", "dc233c" },
{ "xtensaeb", "fsf" },
{ "hppa", "hppa" },
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 966bc93efa..c3a223a83d 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -126,8 +126,6 @@ qtests_mips64el = \
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
(config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
-qtests_moxie = [ 'boot-serial-test' ]
-
qtests_ppc = \
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
(config_all_devices.has_key('CONFIG_M48T59') ? ['m48t59-test'] : []) + \
@@ -233,6 +231,9 @@ if have_virtfs
qos_test_ss.add(files('virtio-9p-test.c'))
endif
qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c'))
+if have_tools and have_vhost_user_blk_server
+ qos_test_ss.add(files('vhost-user-blk-test.c'))
+endif
tpmemu_files = ['tpm-emu.c', 'tpm-util.c', 'tpm-tests.c']
@@ -271,6 +272,7 @@ foreach dir : target_dirs
endif
qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh')
qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base)
+ qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon')
foreach test : target_qtests
# Executables are shared across targets, declare them only the first time we
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 3a711bb492..2b028df687 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -110,13 +110,12 @@ static void init_bootfile(const char *bootpath, void *content, size_t len)
*/
static void wait_for_serial(const char *side)
{
- char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
+ g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
FILE *serialfile = fopen(serialpath, "r");
const char *arch = qtest_get_arch();
int started = (strcmp(side, "src_serial") == 0 &&
strcmp(arch, "ppc64") == 0) ? 0 : 1;
- g_free(serialpath);
do {
int readvalue = fgetc(serialfile);
@@ -274,10 +273,9 @@ static void check_guests_ram(QTestState *who)
static void cleanup(const char *filename)
{
- char *path = g_strdup_printf("%s/%s", tmpfs, filename);
+ g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename);
unlink(path);
- g_free(path);
}
static char *SocketAddress_to_str(SocketAddress *addr)
@@ -374,11 +372,8 @@ static char *migrate_get_parameter_str(QTestState *who,
static void migrate_check_parameter_str(QTestState *who, const char *parameter,
const char *value)
{
- char *result;
-
- result = migrate_get_parameter_str(who, parameter);
+ g_autofree char *result = migrate_get_parameter_str(who, parameter);
g_assert_cmpstr(result, ==, value);
- g_free(result);
}
static void migrate_set_parameter_str(QTestState *who, const char *parameter,
@@ -495,12 +490,14 @@ static void migrate_start_destroy(MigrateStart *args)
static int test_migrate_start(QTestState **from, QTestState **to,
const char *uri, MigrateStart *args)
{
- gchar *arch_source, *arch_target;
- gchar *cmd_source, *cmd_target;
+ g_autofree gchar *arch_source = NULL;
+ g_autofree gchar *arch_target = NULL;
+ g_autofree gchar *cmd_source = NULL;
+ g_autofree gchar *cmd_target = NULL;
const gchar *ignore_stderr;
- char *bootpath = NULL;
- char *shmem_opts;
- char *shmem_path;
+ g_autofree char *bootpath = NULL;
+ g_autofree char *shmem_opts = NULL;
+ g_autofree char *shmem_path = NULL;
const char *arch = qtest_get_arch();
const char *machine_opts = NULL;
const char *memory_size;
@@ -559,8 +556,6 @@ static int test_migrate_start(QTestState **from, QTestState **to,
g_assert_not_reached();
}
- g_free(bootpath);
-
if (!getenv("QTEST_LOG") && args->hide_stderr) {
ignore_stderr = "2>/dev/null";
} else {
@@ -588,11 +583,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
memory_size, tmpfs,
arch_source, shmem_opts, args->opts_source,
ignore_stderr);
- g_free(arch_source);
if (!args->only_target) {
*from = qtest_init(cmd_source);
}
- g_free(cmd_source);
cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s "
"-name target,debug-threads=on "
@@ -605,18 +598,14 @@ static int test_migrate_start(QTestState **from, QTestState **to,
memory_size, tmpfs, uri,
arch_target, shmem_opts,
args->opts_target, ignore_stderr);
- g_free(arch_target);
*to = qtest_init(cmd_target);
- g_free(cmd_target);
- g_free(shmem_opts);
/*
* Remove shmem file immediately to avoid memory leak in test failed case.
* It's valid becase QEMU has already opened this file
*/
if (args->use_shmem) {
unlink(shmem_path);
- g_free(shmem_path);
}
out:
@@ -662,7 +651,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
QTestState **to_ptr,
MigrateStart *args)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
if (test_migrate_start(&from, &to, uri, args)) {
@@ -684,7 +673,6 @@ static int migrate_postcopy_prepare(QTestState **from_ptr,
wait_for_serial("src_serial");
migrate_qmp(from, uri, "{}");
- g_free(uri);
wait_for_migration_pass(from);
@@ -724,7 +712,7 @@ static void test_postcopy_recovery(void)
{
MigrateStart *args = migrate_start_new();
QTestState *from, *to;
- char *uri;
+ g_autofree char *uri = NULL;
args->hide_stderr = true;
@@ -775,7 +763,6 @@ static void test_postcopy_recovery(void)
(const char * []) { "failed", "active",
"completed", NULL });
migrate_qmp(from, uri, "{'resume': true}");
- g_free(uri);
/* Restore the postcopy bandwidth to unlimited */
migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0);
@@ -800,7 +787,7 @@ static void test_baddest(void)
static void test_precopy_unix(void)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
MigrateStart *args = migrate_start_new();
QTestState *from, *to;
@@ -836,14 +823,13 @@ static void test_precopy_unix(void)
wait_for_migration_complete(from);
test_migrate_end(from, to, true);
- g_free(uri);
}
#if 0
/* Currently upset on aarch64 TCG */
static void test_ignore_shared(void)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) {
@@ -873,7 +859,6 @@ static void test_ignore_shared(void)
g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024);
test_migrate_end(from, to, true);
- g_free(uri);
}
#endif
@@ -898,8 +883,8 @@ static void test_xbzrle(const char *uri)
migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432);
- migrate_set_capability(from, "xbzrle", "true");
- migrate_set_capability(to, "xbzrle", "true");
+ migrate_set_capability(from, "xbzrle", true);
+ migrate_set_capability(to, "xbzrle", true);
/* Wait for the first serial output from the source */
wait_for_serial("src_serial");
@@ -925,16 +910,15 @@ static void test_xbzrle(const char *uri)
static void test_xbzrle_unix(void)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
test_xbzrle(uri);
- g_free(uri);
}
static void test_precopy_tcp(void)
{
MigrateStart *args = migrate_start_new();
- char *uri;
+ g_autofree char *uri = NULL;
QTestState *from, *to;
if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) {
@@ -971,7 +955,6 @@ static void test_precopy_tcp(void)
wait_for_migration_complete(from);
test_migrate_end(from, to, true);
- g_free(uri);
}
static void test_migrate_fd_proto(void)
@@ -1060,7 +1043,7 @@ static void test_migrate_fd_proto(void)
static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
if (test_migrate_start(&from, &to, uri, args)) {
@@ -1088,7 +1071,6 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail)
}
test_migrate_end(from, to, false);
- g_free(uri);
}
static void test_validate_uuid(void)
@@ -1136,7 +1118,7 @@ static void test_validate_uuid_dst_not_set(void)
static void test_migrate_auto_converge(void)
{
- char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
MigrateStart *args = migrate_start_new();
QTestState *from, *to;
int64_t remaining, percentage;
@@ -1214,7 +1196,6 @@ static void test_migrate_auto_converge(void)
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
- g_free(uri);
test_migrate_end(from, to, true);
}
@@ -1224,7 +1205,7 @@ static void test_multifd_tcp(const char *method)
MigrateStart *args = migrate_start_new();
QTestState *from, *to;
QDict *rsp;
- char *uri;
+ g_autofree char *uri = NULL;
if (test_migrate_start(&from, &to, "defer", args)) {
return;
@@ -1246,8 +1227,8 @@ static void test_multifd_tcp(const char *method)
migrate_set_parameter_str(from, "multifd-compression", method);
migrate_set_parameter_str(to, "multifd-compression", method);
- migrate_set_capability(from, "multifd", "true");
- migrate_set_capability(to, "multifd", "true");
+ migrate_set_capability(from, "multifd", true);
+ migrate_set_capability(to, "multifd", true);
/* Start incoming migration from the 1st socket */
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
@@ -1273,7 +1254,6 @@ static void test_multifd_tcp(const char *method)
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
test_migrate_end(from, to, true);
- g_free(uri);
}
static void test_multifd_tcp_none(void)
@@ -1309,7 +1289,7 @@ static void test_multifd_tcp_cancel(void)
MigrateStart *args = migrate_start_new();
QTestState *from, *to, *to2;
QDict *rsp;
- char *uri;
+ g_autofree char *uri = NULL;
args->hide_stderr = true;
@@ -1330,8 +1310,8 @@ static void test_multifd_tcp_cancel(void)
migrate_set_parameter_int(from, "multifd-channels", 16);
migrate_set_parameter_int(to, "multifd-channels", 16);
- migrate_set_capability(from, "multifd", "true");
- migrate_set_capability(to, "multifd", "true");
+ migrate_set_capability(from, "multifd", true);
+ migrate_set_capability(to, "multifd", true);
/* Start incoming migration from the 1st socket */
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
@@ -1358,7 +1338,7 @@ static void test_multifd_tcp_cancel(void)
migrate_set_parameter_int(to2, "multifd-channels", 16);
- migrate_set_capability(to2, "multifd", "true");
+ migrate_set_capability(to2, "multifd", true);
/* Start incoming migration from the 1st socket */
rsp = wait_command(to2, "{ 'execute': 'migrate-incoming',"
@@ -1387,7 +1367,6 @@ static void test_multifd_tcp_cancel(void)
wait_for_serial("dest_serial");
wait_for_migration_complete(from);
test_migrate_end(from, to2, true);
- g_free(uri);
}
int main(int argc, char **argv)
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
index bd15a1c294..a54fd70d27 100644
--- a/tests/qtest/npcm7xx_pwm-test.c
+++ b/tests/qtest/npcm7xx_pwm-test.c
@@ -201,7 +201,7 @@ static int pwm_module_index(const PWMModule *module)
{
ptrdiff_t diff = module - pwm_module_list;
- g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
return diff;
}
@@ -211,7 +211,7 @@ static int pwm_index(const PWM *pwm)
{
ptrdiff_t diff = pwm - pwm_list;
- g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
return diff;
}
diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c
index 402ce2c609..8126ab1bdb 100644
--- a/tests/qtest/rtc-test.c
+++ b/tests/qtest/rtc-test.c
@@ -686,7 +686,7 @@ static void periodic_timer(void)
int main(int argc, char **argv)
{
- QTestState *s = NULL;
+ QTestState *s;
int ret;
g_test_init(&argc, &argv, NULL);
@@ -712,9 +712,7 @@ int main(int argc, char **argv)
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
+ qtest_quit(s);
return ret;
}
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index b70cc32d60..3a40ff3f96 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -289,6 +289,6 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
*dst_qemu = qtest_init(dst_qemu_args);
- free(src_qemu_args);
- free(dst_qemu_args);
+ g_free(src_qemu_args);
+ g_free(dst_qemu_args);
}
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
new file mode 100644
index 0000000000..8796c74ca4
--- /dev/null
+++ b/tests/qtest/vhost-user-blk-test.c
@@ -0,0 +1,989 @@
+/*
+ * QTest testcase for Vhost-user Block Device
+ *
+ * Based on tests/qtest//virtio-blk-test.c
+
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ * Copyright (c) 2014 Marc Marí
+ * Copyright (c) 2020 Coiby Xu
+ *
+ * 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 "libqtest-single.h"
+#include "qemu/bswap.h"
+#include "qemu/module.h"
+#include "standard-headers/linux/virtio_blk.h"
+#include "standard-headers/linux/virtio_pci.h"
+#include "libqos/qgraph.h"
+#include "libqos/vhost-user-blk.h"
+#include "libqos/libqos-pc.h"
+
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
+#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
+#define PCI_SLOT_HP 0x06
+
+typedef struct {
+ pid_t pid;
+} QemuStorageDaemonState;
+
+typedef struct QVirtioBlkReq {
+ uint32_t type;
+ uint32_t ioprio;
+ uint64_t sector;
+ char *data;
+ uint8_t status;
+} QVirtioBlkReq;
+
+#ifdef HOST_WORDS_BIGENDIAN
+static const bool host_is_big_endian = true;
+#else
+static const bool host_is_big_endian; /* false */
+#endif
+
+static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
+{
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
+ req->type = bswap32(req->type);
+ req->ioprio = bswap32(req->ioprio);
+ req->sector = bswap64(req->sector);
+ }
+}
+
+static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
+ struct virtio_blk_discard_write_zeroes *dwz_hdr)
+{
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
+ dwz_hdr->sector = bswap64(dwz_hdr->sector);
+ dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
+ dwz_hdr->flags = bswap32(dwz_hdr->flags);
+ }
+}
+
+static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
+ QVirtioBlkReq *req, uint64_t data_size)
+{
+ uint64_t addr;
+ uint8_t status = 0xFF;
+ QTestState *qts = global_qtest;
+
+ switch (req->type) {
+ case VIRTIO_BLK_T_IN:
+ case VIRTIO_BLK_T_OUT:
+ g_assert_cmpuint(data_size % 512, ==, 0);
+ break;
+ case VIRTIO_BLK_T_DISCARD:
+ case VIRTIO_BLK_T_WRITE_ZEROES:
+ g_assert_cmpuint(data_size %
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
+ break;
+ default:
+ g_assert_cmpuint(data_size, ==, 0);
+ }
+
+ addr = guest_alloc(alloc, sizeof(*req) + data_size);
+
+ virtio_blk_fix_request(d, req);
+
+ qtest_memwrite(qts, addr, req, 16);
+ qtest_memwrite(qts, addr + 16, req->data, data_size);
+ qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
+
+ return addr;
+}
+
+static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
+ QGuestAllocator *alloc,
+ QTestState *qts,
+ QVirtQueue *vq,
+ uint32_t type)
+{
+ QVirtioBlkReq req;
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
+ struct virtio_blk_discard_write_zeroes dwz_hdr2[2];
+ uint64_t req_addr;
+ uint32_t free_head;
+ uint8_t status;
+
+ /* More than one dwz is not supported */
+ req.type = type;
+ req.data = (char *) dwz_hdr2;
+ dwz_hdr2[0].sector = 0;
+ dwz_hdr2[0].num_sectors = 1;
+ dwz_hdr2[0].flags = 0;
+ dwz_hdr2[1].sector = 1;
+ dwz_hdr2[1].num_sectors = 1;
+ dwz_hdr2[1].flags = 0;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true,
+ false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr2));
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
+
+ guest_free(alloc, req_addr);
+
+ /* num_sectors must be less than config->max_write_zeroes_sectors */
+ req.type = type;
+ req.data = (char *) &dwz_hdr;
+ dwz_hdr.sector = 0;
+ dwz_hdr.num_sectors = 0xffffffff;
+ dwz_hdr.flags = 0;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
+ false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
+
+ guest_free(alloc, req_addr);
+
+ /* sector must be less than the device capacity */
+ req.type = type;
+ req.data = (char *) &dwz_hdr;
+ dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1;
+ dwz_hdr.num_sectors = 1;
+ dwz_hdr.flags = 0;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
+ false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
+
+ guest_free(alloc, req_addr);
+
+ /* reserved flag bits must be zero */
+ req.type = type;
+ req.data = (char *) &dwz_hdr;
+ dwz_hdr.sector = 0;
+ dwz_hdr.num_sectors = 1;
+ dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
+ false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
+ g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
+
+ guest_free(alloc, req_addr);
+}
+
+/* Returns the request virtqueue so the caller can perform further tests */
+static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
+{
+ QVirtioBlkReq req;
+ uint64_t req_addr;
+ uint64_t capacity;
+ uint64_t features;
+ uint32_t free_head;
+ uint8_t status;
+ char *data;
+ QTestState *qts = global_qtest;
+ QVirtQueue *vq;
+
+ features = qvirtio_get_features(dev);
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
+ (1u << VIRTIO_BLK_F_SCSI));
+ qvirtio_set_features(dev, features);
+
+ capacity = qvirtio_config_readq(dev, 0);
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+ vq = qvirtqueue_setup(dev, alloc, 0);
+
+ qvirtio_set_driver_ok(dev);
+
+ /* Write and read with 3 descriptor layout */
+ /* Write request */
+ req.type = VIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ guest_free(alloc, req_addr);
+
+ /* Read request */
+ req.type = VIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ data = g_malloc0(512);
+ qtest_memread(qts, req_addr + 16, data, 512);
+ g_assert_cmpstr(data, ==, "TEST");
+ g_free(data);
+
+ guest_free(alloc, req_addr);
+
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
+ void *expected;
+
+ /*
+ * WRITE_ZEROES request on the same sector of previous test where
+ * we wrote "TEST".
+ */
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
+ req.data = (char *) &dwz_hdr;
+ dwz_hdr.sector = 0;
+ dwz_hdr.num_sectors = 1;
+ dwz_hdr.flags = 0;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
+ false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
+ g_assert_cmpint(status, ==, 0);
+
+ guest_free(alloc, req_addr);
+
+ /* Read request to check if the sector contains all zeroes */
+ req.type = VIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ data = g_malloc(512);
+ expected = g_malloc0(512);
+ qtest_memread(qts, req_addr + 16, data, 512);
+ g_assert_cmpmem(data, 512, expected, 512);
+ g_free(expected);
+ g_free(data);
+
+ guest_free(alloc, req_addr);
+
+ test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
+ VIRTIO_BLK_T_WRITE_ZEROES);
+ }
+
+ if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
+
+ req.type = VIRTIO_BLK_T_DISCARD;
+ req.data = (char *) &dwz_hdr;
+ dwz_hdr.sector = 0;
+ dwz_hdr.num_sectors = 1;
+ dwz_hdr.flags = 0;
+
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
+ 1, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
+ g_assert_cmpint(status, ==, 0);
+
+ guest_free(alloc, req_addr);
+
+ test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
+ VIRTIO_BLK_T_DISCARD);
+ }
+
+ if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
+ /* Write and read with 2 descriptor layout */
+ /* Write request */
+ req.type = VIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ guest_free(alloc, req_addr);
+
+ /* Read request */
+ req.type = VIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
+
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ data = g_malloc0(512);
+ qtest_memread(qts, req_addr + 16, data, 512);
+ g_assert_cmpstr(data, ==, "TEST");
+ g_free(data);
+
+ guest_free(alloc, req_addr);
+ }
+
+ return vq;
+}
+
+static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+ QVhostUserBlk *blk_if = obj;
+ QVirtQueue *vq;
+
+ vq = test_basic(blk_if->vdev, t_alloc);
+ qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
+
+}
+
+static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
+{
+ QVirtQueue *vq;
+ QVhostUserBlk *blk_if = obj;
+ QVirtioDevice *dev = blk_if->vdev;
+ QVirtioBlkReq req;
+ QVRingIndirectDesc *indirect;
+ uint64_t req_addr;
+ uint64_t capacity;
+ uint64_t features;
+ uint32_t free_head;
+ uint8_t status;
+ char *data;
+ QTestState *qts = global_qtest;
+
+ features = qvirtio_get_features(dev);
+ g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
+ (1u << VIRTIO_BLK_F_SCSI));
+ qvirtio_set_features(dev, features);
+
+ capacity = qvirtio_config_readq(dev, 0);
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
+ qvirtio_set_driver_ok(dev);
+
+ /* Write request */
+ req.type = VIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ g_free(indirect);
+ guest_free(t_alloc, req_addr);
+
+ /* Read request */
+ req.type = VIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ data = g_malloc0(512);
+ qtest_memread(qts, req_addr + 16, data, 512);
+ g_assert_cmpstr(data, ==, "TEST");
+ g_free(data);
+
+ g_free(indirect);
+ guest_free(t_alloc, req_addr);
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+}
+
+static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
+{
+ QVirtQueue *vq;
+ QVhostUserBlkPCI *blk = obj;
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
+ QVirtioDevice *dev = &pdev->vdev;
+ QVirtioBlkReq req;
+ uint64_t req_addr;
+ uint64_t capacity;
+ uint64_t features;
+ uint32_t free_head;
+ uint32_t write_head;
+ uint32_t desc_idx;
+ uint8_t status;
+ char *data;
+ QOSGraphObject *blk_object = obj;
+ QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
+ QTestState *qts = global_qtest;
+
+ if (qpci_check_buggy_msi(pci_dev)) {
+ return;
+ }
+
+ qpci_msix_enable(pdev->pdev);
+ qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
+
+ features = qvirtio_get_features(dev);
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
+ (1u << VIRTIO_BLK_F_SCSI));
+ qvirtio_set_features(dev, features);
+
+ capacity = qvirtio_config_readq(dev, 0);
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
+
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
+ qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
+
+ qvirtio_set_driver_ok(dev);
+
+ /*
+ * libvhost-user signals the call fd in VHOST_USER_SET_VRING_CALL, make
+ * sure to wait for the isr here so we don't race and confuse it later on.
+ */
+ qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+
+ /* Write request */
+ req.type = VIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 0;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+
+ /* Write request */
+ req.type = VIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
+
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ /* Notify after processing the third request */
+ qvirtqueue_set_used_event(qts, vq, 2);
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+ qvirtqueue_kick(qts, dev, vq, free_head);
+ write_head = free_head;
+
+ /* No notification expected */
+ status = qvirtio_wait_status_byte_no_isr(qts, dev,
+ vq, req_addr + 528,
+ QVIRTIO_BLK_TIMEOUT_US);
+ g_assert_cmpint(status, ==, 0);
+
+ guest_free(t_alloc, req_addr);
+
+ /* Read request */
+ req.type = VIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
+
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
+
+ g_free(req.data);
+
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
+
+ qvirtqueue_kick(qts, dev, vq, free_head);
+
+ /* We get just one notification for both requests */
+ qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
+ QVIRTIO_BLK_TIMEOUT_US);
+ g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
+ g_assert_cmpint(desc_idx, ==, free_head);
+
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
+
+ data = g_malloc0(512);
+ qtest_memread(qts, req_addr + 16, data, 512);
+ g_assert_cmpstr(data, ==, "TEST");
+ g_free(data);
+
+ guest_free(t_alloc, req_addr);
+
+ /* End test */
+ qpci_msix_disable(pdev->pdev);
+
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
+}
+
+static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+ QVirtioPCIDevice *dev1 = obj;
+ QVirtioPCIDevice *dev;
+ QTestState *qts = dev1->pdev->bus->qts;
+
+ /* plug secondary disk */
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
+ "{'addr': %s, 'chardev': 'char2'}",
+ stringify(PCI_SLOT_HP) ".0");
+
+ dev = virtio_pci_new(dev1->pdev->bus,
+ &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
+ });
+ g_assert_nonnull(dev);
+ g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
+ qvirtio_pci_device_disable(dev);
+ qos_object_destroy((QOSGraphObject *)dev);
+
+ /* unplug secondary disk */
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
+}
+
+static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
+{
+ QVirtioPCIDevice *pdev1 = obj;
+ QVirtioDevice *dev1 = &pdev1->vdev;
+ QVirtioPCIDevice *pdev8;
+ QVirtioDevice *dev8;
+ QTestState *qts = pdev1->pdev->bus->qts;
+ uint64_t features;
+ uint16_t num_queues;
+
+ /*
+ * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
+ * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
+ * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
+ * is also spec-compliant).
+ */
+ features = qvirtio_get_features(dev1);
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
+ (1u << VIRTIO_BLK_F_SCSI));
+ qvirtio_set_features(dev1, features);
+
+ /* Hotplug a secondary device with 8 queues */
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
+ "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
+ stringify(PCI_SLOT_HP) ".0");
+
+ pdev8 = virtio_pci_new(pdev1->pdev->bus,
+ &(QPCIAddress) {
+ .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
+ });
+ g_assert_nonnull(pdev8);
+ g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
+
+ qos_object_start_hw(&pdev8->obj);
+
+ dev8 = &pdev8->vdev;
+ features = qvirtio_get_features(dev8);
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
+ ==,
+ (1u << VIRTIO_BLK_F_MQ));
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
+ (1u << VIRTIO_BLK_F_SCSI) |
+ (1u << VIRTIO_BLK_F_MQ));
+ qvirtio_set_features(dev8, features);
+
+ num_queues = qvirtio_config_readw(dev8,
+ offsetof(struct virtio_blk_config, num_queues));
+ g_assert_cmpint(num_queues, ==, 8);
+
+ qvirtio_pci_device_disable(pdev8);
+ qos_object_destroy(&pdev8->obj);
+
+ /* unplug secondary disk */
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
+}
+
+/*
+ * Check that setting the vring addr on a non-existent virtqueue does
+ * not crash.
+ */
+static void test_nonexistent_virtqueue(void *obj, void *data,
+ QGuestAllocator *t_alloc)
+{
+ QVhostUserBlkPCI *blk = obj;
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
+ QPCIBar bar0;
+ QPCIDevice *dev;
+
+ dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
+ g_assert(dev != NULL);
+ qpci_device_enable(dev);
+
+ bar0 = qpci_iomap(dev, 0, NULL);
+
+ qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
+ qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
+
+ g_free(dev);
+}
+
+static const char *qtest_qemu_storage_daemon_binary(void)
+{
+ const char *qemu_storage_daemon_bin;
+
+ qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
+ if (!qemu_storage_daemon_bin) {
+ fprintf(stderr, "Environment variable "
+ "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
+ exit(0);
+ }
+
+ return qemu_storage_daemon_bin;
+}
+
+/* g_test_queue_destroy() cleanup function for files */
+static void destroy_file(void *path)
+{
+ unlink(path);
+ g_free(path);
+ qos_invalidate_command_line();
+}
+
+static char *drive_create(void)
+{
+ int fd, ret;
+ /** vhost-user-blk won't recognize drive located in /tmp */
+ char *t_path = g_strdup("qtest.XXXXXX");
+
+ /** Create a temporary raw image */
+ fd = mkstemp(t_path);
+ g_assert_cmpint(fd, >=, 0);
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
+ g_assert_cmpint(ret, ==, 0);
+ close(fd);
+
+ g_test_queue_destroy(destroy_file, t_path);
+ return t_path;
+}
+
+static char *create_listen_socket(int *fd)
+{
+ int tmp_fd;
+ char *path;
+
+ /* No race because our pid makes the path unique */
+ path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid());
+ tmp_fd = mkstemp(path);
+ g_assert_cmpint(tmp_fd, >=, 0);
+ close(tmp_fd);
+ unlink(path);
+
+ *fd = qtest_socket_server(path);
+ g_test_queue_destroy(destroy_file, path);
+ return path;
+}
+
+/*
+ * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
+ * qemu-storage-daemon.
+ */
+static void quit_storage_daemon(void *data)
+{
+ QemuStorageDaemonState *qsd = data;
+ int wstatus;
+ pid_t pid;
+
+ /*
+ * If we were invoked as a g_test_queue_destroy() cleanup function we need
+ * to remove the abrt handler to avoid being called again if the code below
+ * aborts. Also, we must not leave the abrt handler installed after
+ * cleanup.
+ */
+ qtest_remove_abrt_handler(data);
+
+ /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
+ qtest_kill_qemu(global_qtest);
+
+ kill(qsd->pid, SIGTERM);
+ pid = waitpid(qsd->pid, &wstatus, 0);
+ g_assert_cmpint(pid, ==, qsd->pid);
+ if (!WIFEXITED(wstatus)) {
+ fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
+ __func__);
+ abort();
+ }
+ if (WEXITSTATUS(wstatus) != 0) {
+ fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
+ "successfully, got %d\n",
+ __func__, WEXITSTATUS(wstatus));
+ abort();
+ }
+
+ g_free(data);
+}
+
+static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
+ int num_queues)
+{
+ const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
+ int i;
+ gchar *img_path;
+ GString *storage_daemon_command = g_string_new(NULL);
+ QemuStorageDaemonState *qsd;
+
+ g_string_append_printf(storage_daemon_command,
+ "exec %s ",
+ vhost_user_blk_bin);
+
+ g_string_append_printf(cmd_line,
+ " -object memory-backend-memfd,id=mem,size=256M,share=on "
+ " -M memory-backend=mem -m 256M ");
+
+ for (i = 0; i < vus_instances; i++) {
+ int fd;
+ char *sock_path = create_listen_socket(&fd);
+
+ /* create image file */
+ img_path = drive_create();
+ g_string_append_printf(storage_daemon_command,
+ "--blockdev driver=file,node-name=disk%d,filename=%s "
+ "--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
+ "node-name=disk%i,writable=on,num-queues=%d ",
+ i, img_path, i, sock_path, i, num_queues);
+
+ g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
+ i + 1, sock_path);
+ }
+
+ g_test_message("starting vhost-user backend: %s",
+ storage_daemon_command->str);
+ pid_t pid = fork();
+ if (pid == 0) {
+ /*
+ * Close standard file descriptors so tap-driver.pl pipe detects when
+ * our parent terminates.
+ */
+ close(0);
+ close(1);
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_WRONLY);
+
+ execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
+ exit(1);
+ }
+ g_string_free(storage_daemon_command, true);
+
+ qsd = g_new(QemuStorageDaemonState, 1);
+ qsd->pid = pid;
+
+ /* Make sure qemu-storage-daemon is stopped */
+ qtest_add_abrt_handler(quit_storage_daemon, qsd);
+ g_test_queue_destroy(quit_storage_daemon, qsd);
+}
+
+static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
+{
+ start_vhost_user_blk(cmd_line, 1, 1);
+ return arg;
+}
+
+/*
+ * Setup for hotplug.
+ *
+ * Since vhost-user server only serves one vhost-user client one time,
+ * another exprot
+ *
+ */
+static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
+{
+ /* "-chardev socket,id=char2" is used for pci_hotplug*/
+ start_vhost_user_blk(cmd_line, 2, 1);
+ return arg;
+}
+
+static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
+{
+ start_vhost_user_blk(cmd_line, 2, 8);
+ return arg;
+}
+
+static void register_vhost_user_blk_test(void)
+{
+ QOSGraphTestOptions opts = {
+ .before = vhost_user_blk_test_setup,
+ };
+
+ /*
+ * tests for vhost-user-blk and vhost-user-blk-pci
+ * The tests are borrowed from tests/virtio-blk-test.c. But some tests
+ * regarding block_resize don't work for vhost-user-blk.
+ * vhost-user-blk device doesn't have -drive, so tests containing
+ * block_resize are also abandoned,
+ * - config
+ * - resize
+ */
+ qos_add_test("basic", "vhost-user-blk", basic, &opts);
+ qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
+ qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
+ qos_add_test("nxvirtq", "vhost-user-blk-pci",
+ test_nonexistent_virtqueue, &opts);
+
+ opts.before = vhost_user_blk_hotplug_test_setup;
+ qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
+
+ opts.before = vhost_user_blk_multiqueue_test_setup;
+ qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
+}
+
+libqos_init(register_vhost_user_blk_test);
diff --git a/tests/tcg/Makefile.qemu b/tests/tcg/Makefile.qemu
index a56564660c..84c8543878 100644
--- a/tests/tcg/Makefile.qemu
+++ b/tests/tcg/Makefile.qemu
@@ -22,6 +22,8 @@ quiet-@ = $(if $(V),,@)
quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
CROSS_CC_GUEST:=
+CROSS_AS_GUEST:=
+CROSS_LD_GUEST:=
DOCKER_IMAGE:=
-include tests/tcg/config-$(TARGET).mak
@@ -42,6 +44,8 @@ cross-build-guest-tests:
$(call quiet-command, \
(mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \
$(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC="$(CROSS_CC_GUEST)" \
+ $(if $(CROSS_AS_GUEST),AS="$(CROSS_AS_GUEST)") \
+ $(if $(CROSS_LD_GUEST),LD="$(CROSS_LD_GUEST)") \
SRC_PATH="$(SRC_PATH)" BUILD_STATIC=$(CROSS_CC_GUEST_STATIC) \
EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \
"BUILD","$(TARGET) guest-tests with $(CROSS_CC_GUEST)")
@@ -59,11 +63,24 @@ DOCKER_COMPILE_CMD="$(DOCKER_SCRIPT) cc \
-i qemu/$(DOCKER_IMAGE) \
-s $(SRC_PATH) -- "
+DOCKER_AS_CMD=$(if $(DOCKER_CROSS_AS_GUEST),"$(DOCKER_SCRIPT) cc \
+ --cc $(DOCKER_CROSS_AS_GUEST) \
+ -i qemu/$(DOCKER_IMAGE) \
+ -s $(SRC_PATH) -- ")
+
+DOCKER_LD_CMD=$(if $(DOCKER_CROSS_LD_GUEST),"$(DOCKER_SCRIPT) cc \
+ --cc $(DOCKER_CROSS_LD_GUEST) \
+ -i qemu/$(DOCKER_IMAGE) \
+ -s $(SRC_PATH) -- ")
+
+
.PHONY: docker-build-guest-tests
docker-build-guest-tests: docker-image-$(DOCKER_IMAGE)
$(call quiet-command, \
(mkdir -p tests/tcg/$(TARGET) && cd tests/tcg/$(TARGET) && \
$(MAKE) -f $(TCG_MAKE) TARGET="$(TARGET)" CC=$(DOCKER_COMPILE_CMD) \
+ $(if $(DOCKER_AS_CMD),AS=$(DOCKER_AS_CMD)) \
+ $(if $(DOCKER_LD_CMD),LD=$(DOCKER_LD_CMD)) \
SRC_PATH="$(SRC_PATH)" BUILD_STATIC=y \
EXTRA_CFLAGS="$(CROSS_CC_GUEST_CFLAGS)"), \
"BUILD","$(TARGET) guest-tests with docker qemu/$(DOCKER_IMAGE)")
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index cab8c6b3a2..b29fae4630 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -43,9 +43,10 @@ quiet-command = $(if $(V),$1,$(if $(2),@printf " %-7s %s\n" $2 $3 && $1, @$1))
# $1 = test name, $2 = cmd, $3 = desc
ifdef CONFIG_USER_ONLY
-run-test = $(call quiet-command, timeout $(TIMEOUT) $2 > $1.out,"TEST",$3)
+run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2 > $1.out, \
+ "TEST",$3)
else
-run-test = $(call quiet-command, timeout $(TIMEOUT) $2,"TEST",$3)
+run-test = $(call quiet-command, timeout --foreground $(TIMEOUT) $2,"TEST",$3)
endif
# $1 = test name, $2 = reference
diff --git a/tests/tcg/README b/tests/tcg/README
index 2a58f9a058..706bb185b4 100644
--- a/tests/tcg/README
+++ b/tests/tcg/README
@@ -7,9 +7,3 @@ CRIS
====
The testsuite for CRIS is in tests/tcg/cris. You can run it
with "make test-cris".
-
-LM32
-====
-The testsuite for LM32 is in tests/tcg/lm32. You can run it
-with "make test-lm32".
-
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
index fa1a4261a4..ed6492ce59 100755
--- a/tests/tcg/configure.sh
+++ b/tests/tcg/configure.sh
@@ -74,37 +74,17 @@ fi
for target in $target_list; do
arch=${target%%-*}
- case $arch in
- arm|armeb)
- arches=arm
- ;;
- aarch64|aarch64_be)
- arches="aarch64 arm"
- ;;
- mips*)
- arches=mips
- ;;
- ppc*)
- arches=ppc
- ;;
- sh4|sh4eb)
- arches=sh4
- ;;
- x86_64)
- arches="x86_64 i386"
- ;;
- xtensa|xtensaeb)
- arches=xtensa
- ;;
- alpha|cris|hexagon|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
- arches=$target
- ;;
- *)
- continue
- ;;
- esac
+ # reset all container fields
container_image=
+ container_hosts=
+ container_cross_cc=
+ container_cross_as=
+ container_cross_ld=
+
+ # suppress clang
+ supress_clang=
+
case $target in
aarch64-*)
# We don't have any bigendian build tools so we only use this for AArch64
@@ -128,6 +108,11 @@ for target in $target_list; do
container_image=fedora-cris-cross
container_cross_cc=cris-linux-gnu-gcc
;;
+ hexagon-*)
+ container_hosts=x86_64
+ container_image=debian-hexagon-cross
+ container_cross_cc=hexagon-unknown-linux-musl-clang
+ ;;
hppa-*)
container_hosts=x86_64
container_image=debian-hppa-cross
@@ -137,6 +122,7 @@ for target in $target_list; do
container_hosts=x86_64
container_image=fedora-i386-cross
container_cross_cc=gcc
+ supress_clang=yes
;;
m68k-*)
container_hosts=x86_64
@@ -165,18 +151,14 @@ for target in $target_list; do
;;
ppc-*|ppc64abi32-*)
container_hosts=x86_64
- container_image=debian-powerpc-cross
- container_cross_cc=powerpc-linux-gnu-gcc
- ;;
- ppc64-*)
- container_hosts=x86_64
- container_image=debian-ppc64-cross
- container_cross_cc=powerpc64-linux-gnu-gcc
+ container_image=debian-powerpc-test-cross
+ container_cross_cc=powerpc-linux-gnu-gcc-10
;;
- ppc64le-*)
+ ppc64-*|ppc64le-*)
container_hosts=x86_64
- container_image=debian-ppc64el-cross
- container_cross_cc=powerpc64le-linux-gnu-gcc
+ container_image=debian-powerpc-test-cross
+ container_cross_cc=${target%%-*}-linux-gnu-gcc-10
+ container_cross_cc=powerpc${container_cross_cc#ppc}
;;
riscv64-*)
container_hosts=x86_64
@@ -198,10 +180,17 @@ for target in $target_list; do
container_image=debian-sparc64-cross
container_cross_cc=sparc64-linux-gnu-gcc
;;
+ tricore-softmmu)
+ container_hosts=x86_64
+ container_image=debian-tricore-cross
+ container_cross_as=tricore-as
+ container_cross_ld=tricore-ld
+ ;;
x86_64-*)
container_hosts="aarch64 ppc64el x86_64"
container_image=debian-amd64-cross
container_cross_cc=x86_64-linux-gnu-gcc
+ supress_clang=yes
;;
xtensa*-softmmu)
container_hosts=x86_64
@@ -216,6 +205,7 @@ for target in $target_list; do
echo "# Automatically generated by configure - do not modify" > $config_target_mak
echo "TARGET_NAME=$arch" >> $config_target_mak
+ echo "target=$target" >> $config_target_mak
case $target in
*-linux-user | *-bsd-user)
echo "CONFIG_USER_ONLY=y" >> $config_target_mak
@@ -231,74 +221,91 @@ for target in $target_list; do
echo "CROSS_CC_GUEST_CFLAGS=$target_compiler_cflags" >> $config_target_mak
got_cross_cc=no
- for i in $arch $arches; do
- if eval test "x\${cross_cc_$i+yes}" != xyes; then
- continue
- fi
- eval "target_compiler=\${cross_cc_$i}"
- if ! has $target_compiler; then
- continue
- fi
- write_c_skeleton
- if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC -static ; then
- # For host systems we might get away with building without -static
- if ! do_compiler "$target_compiler" $target_compiler_cflags -o $TMPE $TMPC ; then
- continue
- fi
- echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
- else
- echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
- fi
- echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak
+ if eval test "x\${cross_cc_$arch}" != xyes; then
+ eval "target_compiler=\${cross_cc_$arch}"
- # Test for compiler features for optional tests. We only do this
- # for cross compilers because ensuring the docker containers based
- # compilers is a requirememt for adding a new test that needs a
- # compiler feature.
- case $target in
- aarch64-*)
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -march=armv8.1-a+sve -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak
- fi
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -march=armv8.3-a -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
- fi
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -mbranch-protection=standard -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
- fi
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -march=armv8.5-a+memtag -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak
- fi
- ;;
- ppc*)
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -mpower8-vector -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak
- fi
- ;;
- i386-linux-user)
- if do_compiler "$target_compiler" $target_compiler_cflags \
- -Werror -fno-pie -o $TMPE $TMPC; then
- echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak
- fi
- ;;
- esac
+ if has "$target_compiler"; then
+ if test "$supress_clang" = yes &&
+ $target_compiler --version | grep -qi "clang"; then
+ got_cross_cc=no
+ else
+ write_c_skeleton
+ if ! do_compiler "$target_compiler" $target_compiler_cflags \
+ -o $TMPE $TMPC -static ; then
+ # For host systems we might get away with building without -static
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -o $TMPE $TMPC ; then
+ got_cross_cc=yes
+ echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
+ echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak
+ fi
+ else
+ got_cross_cc=yes
+ echo "CROSS_CC_GUEST_STATIC=y" >> $config_target_mak
+ echo "CROSS_CC_GUEST=$target_compiler" >> $config_target_mak
+ fi
+ fi
+ fi
+ fi
- enabled_cross_compilers="$enabled_cross_compilers $target_compiler"
- got_cross_cc=yes
- break
- done
+ if test $got_cross_cc = yes; then
+ # Test for compiler features for optional tests. We only do this
+ # for cross compilers because ensuring the docker containers based
+ # compilers is a requirememt for adding a new test that needs a
+ # compiler feature.
- if test $got_cross_cc = no && test "$container" != no && test -n "$container_image"; then
+ case $target in
+ aarch64-*)
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -march=armv8.1-a+sve -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_SVE=y" >> $config_target_mak
+ fi
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -march=armv8.3-a -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
+ fi
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -mbranch-protection=standard -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
+ fi
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -march=armv8.5-a+memtag -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak
+ fi
+ ;;
+ ppc*)
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -mpower8-vector -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak
+ fi
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -mpower10 -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_POWER10=y" >> $config_target_mak
+ fi
+ ;;
+ i386-linux-user)
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -Werror -fno-pie -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_I386_NOPIE=y" >> $config_target_mak
+ fi
+ ;;
+ esac
+ elif test $got_cross_cc = no && test "$container" != no && \
+ test -n "$container_image"; then
for host in $container_hosts; do
if test "$host" = "$ARCH"; then
echo "DOCKER_IMAGE=$container_image" >> $config_target_mak
- echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> $config_target_mak
+ echo "DOCKER_CROSS_CC_GUEST=$container_cross_cc" >> \
+ $config_target_mak
+ if test -n "$container_cross_as"; then
+ echo "DOCKER_CROSS_AS_GUEST=$container_cross_as" >> \
+ $config_target_mak
+ fi
+ if test -n "$container_cross_ld"; then
+ echo "DOCKER_CROSS_LD_GUEST=$container_cross_ld" >> \
+ $config_target_mak
+ fi
fi
done
fi
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
deleted file mode 100644
index 57e7363b2c..0000000000
--- a/tests/tcg/lm32/Makefile
+++ /dev/null
@@ -1,106 +0,0 @@
--include ../../../config-host.mak
-
-CROSS=lm32-elf-
-
-SIM = qemu-system-lm32
-SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel
-
-CC = $(CROSS)gcc
-AS = $(CROSS)as
-AS = $(CC) -x assembler
-SIZE = $(CROSS)size
-LD = $(CC)
-OBJCOPY = $(CROSS)objcopy
-
-TSRC_PATH = $(SRC_PATH)/tests/tcg/lm32
-
-LDFLAGS = -T$(TSRC_PATH)/linker.ld
-ASFLAGS += -Wa,-I,$(TSRC_PATH)/
-
-CRT = crt.o
-HELPER = helper.o
-TESTCASES += test_add.tst
-TESTCASES += test_addi.tst
-TESTCASES += test_and.tst
-TESTCASES += test_andhi.tst
-TESTCASES += test_andi.tst
-TESTCASES += test_b.tst
-TESTCASES += test_be.tst
-TESTCASES += test_bg.tst
-TESTCASES += test_bge.tst
-TESTCASES += test_bgeu.tst
-TESTCASES += test_bgu.tst
-TESTCASES += test_bi.tst
-TESTCASES += test_bne.tst
-TESTCASES += test_break.tst
-TESTCASES += test_bret.tst
-TESTCASES += test_call.tst
-TESTCASES += test_calli.tst
-TESTCASES += test_cmpe.tst
-TESTCASES += test_cmpei.tst
-TESTCASES += test_cmpg.tst
-TESTCASES += test_cmpgi.tst
-TESTCASES += test_cmpge.tst
-TESTCASES += test_cmpgei.tst
-TESTCASES += test_cmpgeu.tst
-TESTCASES += test_cmpgeui.tst
-TESTCASES += test_cmpgu.tst
-TESTCASES += test_cmpgui.tst
-TESTCASES += test_cmpne.tst
-TESTCASES += test_cmpnei.tst
-TESTCASES += test_divu.tst
-TESTCASES += test_eret.tst
-TESTCASES += test_lb.tst
-TESTCASES += test_lbu.tst
-TESTCASES += test_lh.tst
-TESTCASES += test_lhu.tst
-TESTCASES += test_lw.tst
-TESTCASES += test_modu.tst
-TESTCASES += test_mul.tst
-TESTCASES += test_muli.tst
-TESTCASES += test_nor.tst
-TESTCASES += test_nori.tst
-TESTCASES += test_or.tst
-TESTCASES += test_ori.tst
-TESTCASES += test_orhi.tst
-#TESTCASES += test_rcsr.tst
-TESTCASES += test_ret.tst
-TESTCASES += test_sb.tst
-TESTCASES += test_scall.tst
-TESTCASES += test_sextb.tst
-TESTCASES += test_sexth.tst
-TESTCASES += test_sh.tst
-TESTCASES += test_sl.tst
-TESTCASES += test_sli.tst
-TESTCASES += test_sr.tst
-TESTCASES += test_sri.tst
-TESTCASES += test_sru.tst
-TESTCASES += test_srui.tst
-TESTCASES += test_sub.tst
-TESTCASES += test_sw.tst
-#TESTCASES += test_wcsr.tst
-TESTCASES += test_xnor.tst
-TESTCASES += test_xnori.tst
-TESTCASES += test_xor.tst
-TESTCASES += test_xori.tst
-
-all: build
-
-%.o: $(TSRC_PATH)/%.c
- $(CC) $(CFLAGS) -c $< -o $@
-
-%.o: $(TSRC_PATH)/%.S
- $(AS) $(ASFLAGS) -c $< -o $@
-
-%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER)
- $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@
-
-build: $(TESTCASES)
-
-check: $(TESTCASES:test_%.tst=check_%)
-
-check_%: test_%.tst
- @$(SIM) $(SIMFLAGS) $<
-
-clean:
- $(RM) -fr $(TESTCASES) $(CRT) $(HELPER)
diff --git a/tests/tcg/lm32/crt.S b/tests/tcg/lm32/crt.S
deleted file mode 100644
index fc437a3de1..0000000000
--- a/tests/tcg/lm32/crt.S
+++ /dev/null
@@ -1,84 +0,0 @@
-.text
-.global _start
-
-_start:
-_reset_handler:
- xor r0, r0, r0
- mvhi r1, hi(_start)
- ori r1, r1, lo(_start)
- wcsr eba, r1
- wcsr deba, r1
- mvhi sp, hi(_fstack)
- ori sp, sp, lo(_fstack)
- bi _main
-
-_breakpoint_handler:
- ori r25, r25, 1
- addi ra, ba, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_instruction_bus_error_handler:
- ori r25, r25, 2
- addi ra, ea, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_watchpoint_handler:
- ori r25, r25, 4
- addi ra, ba, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_data_bus_error_handler:
- ori r25, r25, 8
- addi ra, ea, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_divide_by_zero_handler:
- ori r25, r25, 16
- addi ra, ea, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_interrupt_handler:
- ori r25, r25, 32
- addi ra, ea, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
-_system_call_handler:
- ori r25, r25, 64
- addi ra, ea, 4
- ret
- nop
- nop
- nop
- nop
- nop
-
diff --git a/tests/tcg/lm32/helper.S b/tests/tcg/lm32/helper.S
deleted file mode 100644
index 3351d41e84..0000000000
--- a/tests/tcg/lm32/helper.S
+++ /dev/null
@@ -1,65 +0,0 @@
-.text
-.global _start, _write, _exit
-.global _tc_fail, _tc_pass
-
-_write:
- addi sp, sp, -4
- sw (sp+4), r8
- mvi r8, 5
- scall
- lw r8, (sp+4)
- addi sp, sp, 4
- ret
-
-_exit:
- mvi r8, 1
- scall
-1:
- bi 1b
-
-_tc_pass:
-.data
-1:
- .ascii "OK\n"
-2:
-.text
- addi sp, sp, -16
- sw (sp+4), ra
- sw (sp+8), r1
- sw (sp+12), r2
- sw (sp+16), r3
- mvi r1, 1
- mvhi r2, hi(1b)
- ori r2, r2, lo(1b)
- mvi r3, (2b - 1b)
- calli _write
- lw r3, (sp+16)
- lw r2, (sp+12)
- lw r1, (sp+8)
- lw ra, (sp+4)
- addi sp, sp, 16
- ret
-
-_tc_fail:
-.data
-1:
- .ascii "FAILED\n"
-2:
-.text
- addi sp, sp, -16
- sw (sp+4), ra
- sw (sp+8), r1
- sw (sp+12), r2
- sw (sp+16), r3
- sw (sp+4), ra
- mvi r1, 1
- mvhi r2, hi(1b)
- ori r2, r2, lo(1b)
- mvi r3, (2b - 1b)
- calli _write
- lw r3, (sp+16)
- lw r2, (sp+12)
- lw r1, (sp+8)
- lw ra, (sp+4)
- addi sp, sp, 16
- ret
diff --git a/tests/tcg/lm32/linker.ld b/tests/tcg/lm32/linker.ld
deleted file mode 100644
index 52d43a4c74..0000000000
--- a/tests/tcg/lm32/linker.ld
+++ /dev/null
@@ -1,55 +0,0 @@
-OUTPUT_FORMAT("elf32-lm32")
-ENTRY(_start)
-
-__DYNAMIC = 0;
-
-MEMORY {
- ram : ORIGIN = 0x08000000, LENGTH = 0x04000000 /* 64M */
-}
-
-SECTIONS
-{
- .text :
- {
- _ftext = .;
- *(.text .stub .text.* .gnu.linkonce.t.*)
- _etext = .;
- } > ram
-
- .rodata :
- {
- . = ALIGN(4);
- _frodata = .;
- *(.rodata .rodata.* .gnu.linkonce.r.*)
- *(.rodata1)
- _erodata = .;
- } > ram
-
- .data :
- {
- . = ALIGN(4);
- _fdata = .;
- *(.data .data.* .gnu.linkonce.d.*)
- *(.data1)
- _gp = ALIGN(16);
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- _edata = .;
- } > ram
-
- .bss :
- {
- . = ALIGN(4);
- _fbss = .;
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- _ebss = .;
- _end = .;
- } > ram
-}
-
-PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
-
diff --git a/tests/tcg/lm32/macros.inc b/tests/tcg/lm32/macros.inc
deleted file mode 100644
index 360ad53c9f..0000000000
--- a/tests/tcg/lm32/macros.inc
+++ /dev/null
@@ -1,90 +0,0 @@
-
-.equ MAX_TESTNAME_LEN, 32
-.macro test_name name
- .data
-tn_\name:
- .ascii "\name"
- .space MAX_TESTNAME_LEN - (. - tn_\name), ' '
- .text
- .global \name
-\name:
- addi sp, sp, -12
- sw (sp+4), r1
- sw (sp+8), r2
- sw (sp+12), r3
- mvi r1, 1
- mvhi r2, hi(tn_\name)
- ori r2, r2, lo(tn_\name)
- mvi r3, MAX_TESTNAME_LEN
- calli _write
- lw r3, (sp+12)
- lw r2, (sp+8)
- lw r1, (sp+4)
- addi sp, sp, 12
-.endm
-
-.macro load reg val
- mvhi \reg, hi(\val)
- ori \reg, \reg, lo(\val)
-.endm
-
-.macro tc_pass
- calli _tc_pass
-.endm
-
-.macro tc_fail
- addi r12, r12, 1
- calli _tc_fail
-.endm
-
-.macro check_r3 val
- mvhi r13, hi(\val)
- ori r13, r13, lo(\val)
- be r3, r13, 1f
- tc_fail
- bi 2f
-1:
- tc_pass
-2:
-.endm
-
-.macro check_mem adr val
- mvhi r13, hi(\adr)
- ori r13, r13, lo(\adr)
- mvhi r14, hi(\val)
- ori r14, r14, lo(\val)
- lw r13, (r13+0)
- be r13, r14, 1f
- tc_fail
- bi 2f
-1:
- tc_pass
-2:
-.endm
-
-.macro check_excp excp
- andi r13, r25, \excp
- bne r13, r0, 1f
- tc_fail
- bi 2f
-1:
- tc_pass
-2:
-.endm
-
-.macro start
- .global _main
- .text
-_main:
- mvi r12, 0
-.endm
-
-.macro end
- mv r1, r12
- calli _exit
-.endm
-
-# base +
-# 0 ctrl
-# 4 pass/fail
-# 8 ptr to test name
diff --git a/tests/tcg/lm32/test_add.S b/tests/tcg/lm32/test_add.S
deleted file mode 100644
index 030ad197bb..0000000000
--- a/tests/tcg/lm32/test_add.S
+++ /dev/null
@@ -1,75 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ADD_1
-mvi r1, 0
-mvi r2, 0
-add r3, r1, r2
-check_r3 0
-
-test_name ADD_2
-mvi r1, 0
-mvi r2, 1
-add r3, r1, r2
-check_r3 1
-
-test_name ADD_3
-mvi r1, 1
-mvi r2, 0
-add r3, r1, r2
-check_r3 1
-
-test_name ADD_4
-mvi r1, 1
-mvi r2, -1
-add r3, r1, r2
-check_r3 0
-
-test_name ADD_5
-mvi r1, -1
-mvi r2, 1
-add r3, r1, r2
-check_r3 0
-
-test_name ADD_6
-mvi r1, -1
-mvi r2, 0
-add r3, r1, r2
-check_r3 -1
-
-test_name ADD_7
-mvi r1, 0
-mvi r2, -1
-add r3, r1, r2
-check_r3 -1
-
-test_name ADD_8
-mvi r3, 2
-add r3, r3, r3
-check_r3 4
-
-test_name ADD_9
-mvi r1, 4
-mvi r3, 2
-add r3, r1, r3
-check_r3 6
-
-test_name ADD_10
-mvi r1, 4
-mvi r3, 2
-add r3, r3, r1
-check_r3 6
-
-test_name ADD_11
-mvi r1, 4
-add r3, r1, r1
-check_r3 8
-
-test_name ADD_12
-load r1 0x12345678
-load r2 0xabcdef97
-add r3, r1, r2
-check_r3 0xbe02460f
-
-end
diff --git a/tests/tcg/lm32/test_addi.S b/tests/tcg/lm32/test_addi.S
deleted file mode 100644
index 68e766d1e5..0000000000
--- a/tests/tcg/lm32/test_addi.S
+++ /dev/null
@@ -1,56 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ADDI_1
-mvi r1, 0
-addi r3, r1, 0
-check_r3 0
-
-test_name ADDI_2
-mvi r1, 0
-addi r3, r1, 1
-check_r3 1
-
-test_name ADDI_3
-mvi r1, 1
-addi r3, r1, 0
-check_r3 1
-
-test_name ADDI_4
-mvi r1, 1
-addi r3, r1, -1
-check_r3 0
-
-test_name ADDI_5
-mvi r1, -1
-addi r3, r1, 1
-check_r3 0
-
-test_name ADDI_6
-mvi r1, -1
-addi r3, r1, 0
-check_r3 -1
-
-test_name ADDI_7
-mvi r1, 0
-addi r3, r1, -1
-check_r3 -1
-
-test_name ADDI_8
-mvi r3, 4
-addi r3, r3, 4
-check_r3 8
-
-test_name ADDI_9
-mvi r3, 4
-addi r3, r3, -4
-check_r3 0
-
-test_name ADDI_10
-mvi r3, 4
-addi r3, r3, -5
-check_r3 -1
-
-end
-
diff --git a/tests/tcg/lm32/test_and.S b/tests/tcg/lm32/test_and.S
deleted file mode 100644
index 80962ce7a2..0000000000
--- a/tests/tcg/lm32/test_and.S
+++ /dev/null
@@ -1,45 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name AND_1
-mvi r1, 0
-mvi r2, 0
-and r3, r1, r2
-check_r3 0
-
-test_name AND_2
-mvi r1, 0
-mvi r2, 1
-and r3, r1, r2
-check_r3 0
-
-test_name AND_3
-mvi r1, 1
-mvi r2, 1
-and r3, r1, r2
-check_r3 1
-
-test_name AND_4
-mvi r3, 7
-and r3, r3, r3
-check_r3 7
-
-test_name AND_5
-mvi r1, 7
-and r3, r1, r1
-check_r3 7
-
-test_name AND_6
-mvi r1, 7
-mvi r3, 0
-and r3, r1, r3
-check_r3 0
-
-test_name AND_7
-load r1 0xaa55aa55
-load r2 0x55aa55aa
-and r3, r1, r2
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_andhi.S b/tests/tcg/lm32/test_andhi.S
deleted file mode 100644
index 4f73af550b..0000000000
--- a/tests/tcg/lm32/test_andhi.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ANDHI_1
-mvi r1, 0
-andhi r3, r1, 0
-check_r3 0
-
-test_name ANDHI_2
-mvi r1, 1
-andhi r3, r1, 1
-check_r3 0
-
-test_name ANDHI_3
-load r1 0x000f0000
-andhi r3, r1, 1
-check_r3 0x00010000
-
-test_name ANDHI_4
-load r1 0xffffffff
-andhi r3, r1, 0xffff
-check_r3 0xffff0000
-
-test_name ANDHI_5
-load r1 0xffffffff
-andhi r3, r1, 0
-check_r3 0
-
-test_name ANDHI_6
-load r3 0x55aaffff
-andhi r3, r3, 0xaaaa
-check_r3 0x00aa0000
-
-end
diff --git a/tests/tcg/lm32/test_andi.S b/tests/tcg/lm32/test_andi.S
deleted file mode 100644
index da1b0a32f7..0000000000
--- a/tests/tcg/lm32/test_andi.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ANDI_1
-mvi r1, 0
-andi r3, r1, 0
-check_r3 0
-
-test_name ANDI_2
-mvi r1, 1
-andi r3, r1, 1
-check_r3 1
-
-test_name ANDI_3
-load r1 0x000f0000
-andi r3, r1, 1
-check_r3 0
-
-test_name ANDI_4
-load r1 0xffffffff
-andi r3, r1, 0xffff
-check_r3 0xffff
-
-test_name ANDI_5
-load r1 0xffffffff
-andi r3, r1, 0
-check_r3 0
-
-test_name ANDI_6
-load r3 0xffff55aa
-andi r3, r3, 0xaaaa
-check_r3 0x000000aa
-
-end
diff --git a/tests/tcg/lm32/test_b.S b/tests/tcg/lm32/test_b.S
deleted file mode 100644
index 98172d8a95..0000000000
--- a/tests/tcg/lm32/test_b.S
+++ /dev/null
@@ -1,13 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name B_1
-load r1 jump
-b r1
-tc_fail
-end
-
-jump:
-tc_pass
-end
diff --git a/tests/tcg/lm32/test_be.S b/tests/tcg/lm32/test_be.S
deleted file mode 100644
index 635cabacad..0000000000
--- a/tests/tcg/lm32/test_be.S
+++ /dev/null
@@ -1,48 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BE_1
-mvi r1, 0
-mvi r2, 0
-be r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BE_2
-mvi r1, 1
-mvi r2, 0
-be r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BE_3
-mvi r1, 0
-mvi r2, 1
-be r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-bi 2f
-1:
-tc_pass
-bi 3f
-2:
-test_name BE_4
-mvi r1, 1
-mvi r2, 1
-be r1, r2, 1b
-tc_fail
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_bg.S b/tests/tcg/lm32/test_bg.S
deleted file mode 100644
index 81823c2304..0000000000
--- a/tests/tcg/lm32/test_bg.S
+++ /dev/null
@@ -1,78 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BG_1
-mvi r1, 0
-mvi r2, 0
-bg r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BG_2
-mvi r1, 1
-mvi r2, 0
-bg r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BG_3
-mvi r1, 0
-mvi r2, 1
-bg r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BG_4
-mvi r1, 0
-mvi r2, -1
-bg r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BG_5
-mvi r1, -1
-mvi r2, 0
-bg r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BG_6
-mvi r1, -1
-mvi r2, -1
-bg r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-bi 2f
-1:
-tc_pass
-bi 3f
-2:
-test_name BG_7
-mvi r1, 1
-mvi r2, 0
-bg r1, r2, 1b
-tc_fail
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_bge.S b/tests/tcg/lm32/test_bge.S
deleted file mode 100644
index 6684d15a55..0000000000
--- a/tests/tcg/lm32/test_bge.S
+++ /dev/null
@@ -1,78 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BGE_1
-mvi r1, 0
-mvi r2, 0
-bge r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGE_2
-mvi r1, 1
-mvi r2, 0
-bge r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGE_3
-mvi r1, 0
-mvi r2, 1
-bge r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGE_4
-mvi r1, 0
-mvi r2, -1
-bge r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGE_5
-mvi r1, -1
-mvi r2, 0
-bge r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGE_6
-mvi r1, -1
-mvi r2, -1
-bge r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-bi 2f
-1:
-tc_pass
-bi 3f
-2:
-test_name BGE_7
-mvi r1, 1
-mvi r2, 0
-bge r1, r2, 1b
-tc_fail
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_bgeu.S b/tests/tcg/lm32/test_bgeu.S
deleted file mode 100644
index be440308fd..0000000000
--- a/tests/tcg/lm32/test_bgeu.S
+++ /dev/null
@@ -1,78 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BGEU_1
-mvi r1, 0
-mvi r2, 0
-bgeu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGEU_2
-mvi r1, 1
-mvi r2, 0
-bgeu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGEU_3
-mvi r1, 0
-mvi r2, 1
-bgeu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGEU_4
-mvi r1, 0
-mvi r2, -1
-bgeu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGEU_5
-mvi r1, -1
-mvi r2, 0
-bgeu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGEU_6
-mvi r1, -1
-mvi r2, -1
-bgeu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-bi 2f
-1:
-tc_pass
-bi 3f
-2:
-test_name BGEU_7
-mvi r1, 1
-mvi r2, 0
-bgeu r1, r2, 1b
-tc_fail
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_bgu.S b/tests/tcg/lm32/test_bgu.S
deleted file mode 100644
index 8cc695b310..0000000000
--- a/tests/tcg/lm32/test_bgu.S
+++ /dev/null
@@ -1,78 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BGU_1
-mvi r1, 0
-mvi r2, 0
-bgu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGU_2
-mvi r1, 1
-mvi r2, 0
-bgu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGU_3
-mvi r1, 0
-mvi r2, 1
-bgu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGU_4
-mvi r1, 0
-mvi r2, -1
-bgu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BGU_5
-mvi r1, -1
-mvi r2, 0
-bgu r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BGU_6
-mvi r1, -1
-mvi r2, -1
-bgu r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-bi 2f
-1:
-tc_pass
-bi 3f
-2:
-test_name BGU_7
-mvi r1, 1
-mvi r2, 0
-bgu r1, r2, 1b
-tc_fail
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_bi.S b/tests/tcg/lm32/test_bi.S
deleted file mode 100644
index a1fbd6fc07..0000000000
--- a/tests/tcg/lm32/test_bi.S
+++ /dev/null
@@ -1,23 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BI_1
-bi jump
-tc_fail
-end
-
-jump_back:
-tc_pass
-end
-
-jump:
-tc_pass
-
-test_name BI_2
-bi jump_back
-tc_fail
-
-end
-
-
diff --git a/tests/tcg/lm32/test_bne.S b/tests/tcg/lm32/test_bne.S
deleted file mode 100644
index 871a006755..0000000000
--- a/tests/tcg/lm32/test_bne.S
+++ /dev/null
@@ -1,48 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BNE_1
-mvi r1, 0
-mvi r2, 0
-bne r1, r2, 1f
-tc_pass
-bi 2f
-1:
-tc_fail
-2:
-
-test_name BNE_2
-mvi r1, 1
-mvi r2, 0
-bne r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-test_name BNE_3
-mvi r1, 0
-mvi r2, 1
-bne r1, r2, 1f
-tc_fail
-bi 2f
-1:
-tc_pass
-2:
-
-bi 2f
-1:
-tc_fail
-bi 3f
-2:
-test_name BNE_4
-mvi r1, 1
-mvi r2, 1
-bne r1, r2, 1b
-tc_pass
-3:
-
-end
-
diff --git a/tests/tcg/lm32/test_break.S b/tests/tcg/lm32/test_break.S
deleted file mode 100644
index 0384fc6128..0000000000
--- a/tests/tcg/lm32/test_break.S
+++ /dev/null
@@ -1,20 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BREAK_1
-mvi r1, 1
-wcsr IE, r1
-insn:
-break
-check_excp 1
-
-test_name BREAK_2
-mv r3, ba
-check_r3 insn
-
-test_name BREAK_3
-rcsr r3, IE
-check_r3 4
-
-end
diff --git a/tests/tcg/lm32/test_bret.S b/tests/tcg/lm32/test_bret.S
deleted file mode 100644
index 645210e434..0000000000
--- a/tests/tcg/lm32/test_bret.S
+++ /dev/null
@@ -1,38 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name BRET_1
-mvi r1, 4
-wcsr IE, r1
-load ba mark
-bret
-tc_fail
-bi 1f
-
-mark:
-tc_pass
-
-1:
-test_name BRET_2
-rcsr r3, IE
-check_r3 5
-
-test_name BRET_3
-mvi r1, 0
-wcsr IE, r1
-load ba mark2
-bret
-tc_fail
-bi 1f
-
-mark2:
-tc_pass
-
-1:
-test_name BRET_4
-rcsr r3, IE
-check_r3 0
-
-end
-
diff --git a/tests/tcg/lm32/test_call.S b/tests/tcg/lm32/test_call.S
deleted file mode 100644
index 1b91a5f2be..0000000000
--- a/tests/tcg/lm32/test_call.S
+++ /dev/null
@@ -1,16 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CALL_1
-load r1 mark
-call r1
-return:
-
-tc_fail
-end
-
-mark:
-mv r3, ra
-check_r3 return
-end
diff --git a/tests/tcg/lm32/test_calli.S b/tests/tcg/lm32/test_calli.S
deleted file mode 100644
index 1d87ae6e21..0000000000
--- a/tests/tcg/lm32/test_calli.S
+++ /dev/null
@@ -1,15 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CALLI_1
-calli mark
-return:
-
-tc_fail
-end
-
-mark:
-mv r3, ra
-check_r3 return
-end
diff --git a/tests/tcg/lm32/test_cmpe.S b/tests/tcg/lm32/test_cmpe.S
deleted file mode 100644
index 60a885500b..0000000000
--- a/tests/tcg/lm32/test_cmpe.S
+++ /dev/null
@@ -1,40 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPE_1
-mvi r1, 0
-mvi r2, 0
-cmpe r3, r1, r2
-check_r3 1
-
-test_name CMPE_2
-mvi r1, 0
-mvi r2, 1
-cmpe r3, r1, r2
-check_r3 0
-
-test_name CMPE_3
-mvi r1, 1
-mvi r2, 0
-cmpe r3, r1, r2
-check_r3 0
-
-test_name CMPE_4
-mvi r3, 0
-mvi r2, 1
-cmpe r3, r3, r2
-check_r3 0
-
-test_name CMPE_5
-mvi r3, 0
-mvi r2, 0
-cmpe r3, r3, r2
-check_r3 1
-
-test_name CMPE_6
-mvi r3, 0
-cmpe r3, r3, r3
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_cmpei.S b/tests/tcg/lm32/test_cmpei.S
deleted file mode 100644
index c3d3566ad3..0000000000
--- a/tests/tcg/lm32/test_cmpei.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPEI_1
-mvi r1, 0
-cmpei r3, r1, 0
-check_r3 1
-
-test_name CMPEI_2
-mvi r1, 0
-cmpei r3, r1, 1
-check_r3 0
-
-test_name CMPEI_3
-mvi r1, 1
-cmpei r3, r1, 0
-check_r3 0
-
-test_name CMPEI_4
-load r1 0xffffffff
-cmpei r3, r1, -1
-check_r3 1
-
-test_name CMPEI_5
-mvi r3, 0
-cmpei r3, r3, 0
-check_r3 1
-
-test_name CMPEI_6
-mvi r3, 0
-cmpei r3, r3, 1
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpg.S b/tests/tcg/lm32/test_cmpg.S
deleted file mode 100644
index 012407874c..0000000000
--- a/tests/tcg/lm32/test_cmpg.S
+++ /dev/null
@@ -1,64 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPG_1
-mvi r1, 0
-mvi r2, 0
-cmpg r3, r1, r2
-check_r3 0
-
-test_name CMPG_2
-mvi r1, 0
-mvi r2, 1
-cmpg r3, r1, r2
-check_r3 0
-
-test_name CMPG_3
-mvi r1, 1
-mvi r2, 0
-cmpg r3, r1, r2
-check_r3 1
-
-test_name CMPG_4
-mvi r1, 1
-mvi r2, 1
-cmpg r3, r1, r2
-check_r3 0
-
-test_name CMPG_5
-mvi r1, 0
-mvi r2, -1
-cmpg r3, r1, r2
-check_r3 1
-
-test_name CMPG_6
-mvi r1, -1
-mvi r2, 0
-cmpg r3, r1, r2
-check_r3 0
-
-test_name CMPG_7
-mvi r1, -1
-mvi r2, -1
-cmpg r3, r1, r2
-check_r3 0
-
-test_name CMPG_8
-mvi r3, 0
-mvi r2, 1
-cmpg r3, r3, r2
-check_r3 0
-
-test_name CMPG_9
-mvi r3, 1
-mvi r2, 0
-cmpg r3, r3, r2
-check_r3 1
-
-test_name CMPG_10
-mvi r3, 0
-cmpg r3, r3, r3
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpge.S b/tests/tcg/lm32/test_cmpge.S
deleted file mode 100644
index 84620a00e3..0000000000
--- a/tests/tcg/lm32/test_cmpge.S
+++ /dev/null
@@ -1,64 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGE_1
-mvi r1, 0
-mvi r2, 0
-cmpge r3, r1, r2
-check_r3 1
-
-test_name CMPGE_2
-mvi r1, 0
-mvi r2, 1
-cmpge r3, r1, r2
-check_r3 0
-
-test_name CMPGE_3
-mvi r1, 1
-mvi r2, 0
-cmpge r3, r1, r2
-check_r3 1
-
-test_name CMPGE_4
-mvi r1, 1
-mvi r2, 1
-cmpge r3, r1, r2
-check_r3 1
-
-test_name CMPGE_5
-mvi r1, 0
-mvi r2, -1
-cmpge r3, r1, r2
-check_r3 1
-
-test_name CMPGE_6
-mvi r1, -1
-mvi r2, 0
-cmpge r3, r1, r2
-check_r3 0
-
-test_name CMPGE_7
-mvi r1, -1
-mvi r2, -1
-cmpge r3, r1, r2
-check_r3 1
-
-test_name CMPGE_8
-mvi r3, 0
-mvi r2, 1
-cmpge r3, r3, r2
-check_r3 0
-
-test_name CMPGE_9
-mvi r3, 1
-mvi r2, 0
-cmpge r3, r3, r2
-check_r3 1
-
-test_name CMPGE_10
-mvi r3, 0
-cmpge r3, r3, r3
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_cmpgei.S b/tests/tcg/lm32/test_cmpgei.S
deleted file mode 100644
index 6e388a2a35..0000000000
--- a/tests/tcg/lm32/test_cmpgei.S
+++ /dev/null
@@ -1,70 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGEI_1
-mvi r1, 0
-cmpgei r3, r1, 0
-check_r3 1
-
-test_name CMPGEI_2
-mvi r1, 0
-cmpgei r3, r1, 1
-check_r3 0
-
-test_name CMPGEI_3
-mvi r1, 1
-cmpgei r3, r1, 0
-check_r3 1
-
-test_name CMPGEI_4
-mvi r1, 1
-cmpgei r3, r1, 1
-check_r3 1
-
-test_name CMPGEI_5
-mvi r1, 0
-cmpgei r3, r1, -1
-check_r3 1
-
-test_name CMPGEI_6
-mvi r1, -1
-cmpgei r3, r1, 0
-check_r3 0
-
-test_name CMPGEI_7
-mvi r1, -1
-cmpgei r3, r1, -1
-check_r3 1
-
-test_name CMPGEI_8
-mvi r3, 0
-cmpgei r3, r3, 1
-check_r3 0
-
-test_name CMPGEI_9
-mvi r3, 1
-cmpgei r3, r3, 0
-check_r3 1
-
-test_name CMPGEI_10
-mvi r3, 0
-cmpgei r3, r3, 0
-check_r3 1
-
-test_name CMPGEI_11
-mvi r1, 0
-cmpgei r3, r1, -32768
-check_r3 1
-
-test_name CMPGEI_12
-mvi r1, -1
-cmpgei r3, r1, -32768
-check_r3 1
-
-test_name CMPGEI_13
-mvi r1, -32768
-cmpgei r3, r1, -32768
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_cmpgeu.S b/tests/tcg/lm32/test_cmpgeu.S
deleted file mode 100644
index 2110ccb6b7..0000000000
--- a/tests/tcg/lm32/test_cmpgeu.S
+++ /dev/null
@@ -1,64 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGEU_1
-mvi r1, 0
-mvi r2, 0
-cmpgeu r3, r1, r2
-check_r3 1
-
-test_name CMPGEU_2
-mvi r1, 0
-mvi r2, 1
-cmpgeu r3, r1, r2
-check_r3 0
-
-test_name CMPGEU_3
-mvi r1, 1
-mvi r2, 0
-cmpgeu r3, r1, r2
-check_r3 1
-
-test_name CMPGEU_4
-mvi r1, 1
-mvi r2, 1
-cmpgeu r3, r1, r2
-check_r3 1
-
-test_name CMPGEU_5
-mvi r1, 0
-mvi r2, -1
-cmpgeu r3, r1, r2
-check_r3 0
-
-test_name CMPGEU_6
-mvi r1, -1
-mvi r2, 0
-cmpgeu r3, r1, r2
-check_r3 1
-
-test_name CMPGEU_7
-mvi r1, -1
-mvi r2, -1
-cmpgeu r3, r1, r2
-check_r3 1
-
-test_name CMPGEU_8
-mvi r3, 0
-mvi r2, 1
-cmpgeu r3, r3, r2
-check_r3 0
-
-test_name CMPGEU_9
-mvi r3, 1
-mvi r2, 0
-cmpgeu r3, r3, r2
-check_r3 1
-
-test_name CMPGEU_10
-mvi r3, 0
-cmpgeu r3, r3, r3
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_cmpgeui.S b/tests/tcg/lm32/test_cmpgeui.S
deleted file mode 100644
index 3866d96cb7..0000000000
--- a/tests/tcg/lm32/test_cmpgeui.S
+++ /dev/null
@@ -1,70 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGEUI_1
-mvi r1, 0
-cmpgeui r3, r1, 0
-check_r3 1
-
-test_name CMPGEUI_2
-mvi r1, 0
-cmpgeui r3, r1, 1
-check_r3 0
-
-test_name CMPGEUI_3
-mvi r1, 1
-cmpgeui r3, r1, 0
-check_r3 1
-
-test_name CMPGEUI_4
-mvi r1, 1
-cmpgeui r3, r1, 1
-check_r3 1
-
-test_name CMPGEUI_5
-mvi r1, 0
-cmpgeui r3, r1, 0xffff
-check_r3 0
-
-test_name CMPGEUI_6
-mvi r1, -1
-cmpgeui r3, r1, 0
-check_r3 1
-
-test_name CMPGEUI_7
-mvi r1, -1
-cmpgeui r3, r1, 0xffff
-check_r3 1
-
-test_name CMPGEUI_8
-mvi r3, 0
-cmpgeui r3, r3, 1
-check_r3 0
-
-test_name CMPGEUI_9
-mvi r3, 1
-cmpgeui r3, r3, 0
-check_r3 1
-
-test_name CMPGEUI_10
-mvi r3, 0
-cmpgeui r3, r3, 0
-check_r3 1
-
-test_name CMPGEUI_11
-mvi r1, 0
-cmpgeui r3, r1, 0x8000
-check_r3 0
-
-test_name CMPGEUI_12
-mvi r1, -1
-cmpgeui r3, r1, 0x8000
-check_r3 1
-
-test_name CMPGEUI_13
-ori r1, r0, 0x8000
-cmpgeui r3, r1, 0x8000
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_cmpgi.S b/tests/tcg/lm32/test_cmpgi.S
deleted file mode 100644
index 21695f97ab..0000000000
--- a/tests/tcg/lm32/test_cmpgi.S
+++ /dev/null
@@ -1,70 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGI_1
-mvi r1, 0
-cmpgi r3, r1, 0
-check_r3 0
-
-test_name CMPGI_2
-mvi r1, 0
-cmpgi r3, r1, 1
-check_r3 0
-
-test_name CMPGI_3
-mvi r1, 1
-cmpgi r3, r1, 0
-check_r3 1
-
-test_name CMPGI_4
-mvi r1, 1
-cmpgi r3, r1, 1
-check_r3 0
-
-test_name CMPGI_5
-mvi r1, 0
-cmpgi r3, r1, -1
-check_r3 1
-
-test_name CMPGI_6
-mvi r1, -1
-cmpgi r3, r1, 0
-check_r3 0
-
-test_name CMPGI_7
-mvi r1, -1
-cmpgi r3, r1, -1
-check_r3 0
-
-test_name CMPGI_8
-mvi r3, 0
-cmpgi r3, r3, 1
-check_r3 0
-
-test_name CMPGI_9
-mvi r3, 1
-cmpgi r3, r3, 0
-check_r3 1
-
-test_name CMPGI_10
-mvi r3, 0
-cmpgi r3, r3, 0
-check_r3 0
-
-test_name CMPGI_11
-mvi r1, 0
-cmpgi r3, r1, -32768
-check_r3 1
-
-test_name CMPGI_12
-mvi r1, -1
-cmpgi r3, r1, -32768
-check_r3 1
-
-test_name CMPGI_13
-mvi r1, -32768
-cmpgi r3, r1, -32768
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpgu.S b/tests/tcg/lm32/test_cmpgu.S
deleted file mode 100644
index dd465471ea..0000000000
--- a/tests/tcg/lm32/test_cmpgu.S
+++ /dev/null
@@ -1,64 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGU_1
-mvi r1, 0
-mvi r2, 0
-cmpgu r3, r1, r2
-check_r3 0
-
-test_name CMPGU_2
-mvi r1, 0
-mvi r2, 1
-cmpgu r3, r1, r2
-check_r3 0
-
-test_name CMPGU_3
-mvi r1, 1
-mvi r2, 0
-cmpgu r3, r1, r2
-check_r3 1
-
-test_name CMPGU_4
-mvi r1, 1
-mvi r2, 1
-cmpgu r3, r1, r2
-check_r3 0
-
-test_name CMPGU_5
-mvi r1, 0
-mvi r2, -1
-cmpgu r3, r1, r2
-check_r3 0
-
-test_name CMPGU_6
-mvi r1, -1
-mvi r2, 0
-cmpgu r3, r1, r2
-check_r3 1
-
-test_name CMPGU_7
-mvi r1, -1
-mvi r2, -1
-cmpgu r3, r1, r2
-check_r3 0
-
-test_name CMPGU_8
-mvi r3, 0
-mvi r2, 1
-cmpgu r3, r3, r2
-check_r3 0
-
-test_name CMPGU_9
-mvi r3, 1
-mvi r2, 0
-cmpgu r3, r3, r2
-check_r3 1
-
-test_name CMPGU_10
-mvi r3, 0
-cmpgu r3, r3, r3
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpgui.S b/tests/tcg/lm32/test_cmpgui.S
deleted file mode 100644
index dd94001492..0000000000
--- a/tests/tcg/lm32/test_cmpgui.S
+++ /dev/null
@@ -1,70 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPGUI_1
-mvi r1, 0
-cmpgui r3, r1, 0
-check_r3 0
-
-test_name CMPGUI_2
-mvi r1, 0
-cmpgui r3, r1, 1
-check_r3 0
-
-test_name CMPGUI_3
-mvi r1, 1
-cmpgui r3, r1, 0
-check_r3 1
-
-test_name CMPGUI_4
-mvi r1, 1
-cmpgui r3, r1, 1
-check_r3 0
-
-test_name CMPGUI_5
-mvi r1, 0
-cmpgui r3, r1, 0xffff
-check_r3 0
-
-test_name CMPGUI_6
-mvi r1, -1
-cmpgui r3, r1, 0
-check_r3 1
-
-test_name CMPGUI_7
-mvi r1, -1
-cmpgui r3, r1, 0xffff
-check_r3 1
-
-test_name CMPGUI_8
-mvi r3, 0
-cmpgui r3, r3, 1
-check_r3 0
-
-test_name CMPGUI_9
-mvi r3, 1
-cmpgui r3, r3, 0
-check_r3 1
-
-test_name CMPGUI_10
-mvi r3, 0
-cmpgui r3, r3, 0
-check_r3 0
-
-test_name CMPGUI_11
-mvi r1, 0
-cmpgui r3, r1, 0x8000
-check_r3 0
-
-test_name CMPGUI_12
-mvi r1, -1
-cmpgui r3, r1, 0x8000
-check_r3 1
-
-test_name CMPGUI_13
-ori r1, r0, 0x8000
-cmpgui r3, r1, 0x8000
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpne.S b/tests/tcg/lm32/test_cmpne.S
deleted file mode 100644
index 0f1078114c..0000000000
--- a/tests/tcg/lm32/test_cmpne.S
+++ /dev/null
@@ -1,40 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPNE_1
-mvi r1, 0
-mvi r2, 0
-cmpne r3, r1, r2
-check_r3 0
-
-test_name CMPNE_2
-mvi r1, 0
-mvi r2, 1
-cmpne r3, r1, r2
-check_r3 1
-
-test_name CMPNE_3
-mvi r1, 1
-mvi r2, 0
-cmpne r3, r1, r2
-check_r3 1
-
-test_name CMPNE_4
-mvi r3, 0
-mvi r2, 1
-cmpne r3, r3, r2
-check_r3 1
-
-test_name CMPNE_5
-mvi r3, 0
-mvi r2, 0
-cmpne r3, r3, r2
-check_r3 0
-
-test_name CMPNE_6
-mvi r3, 0
-cmpne r3, r3, r3
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_cmpnei.S b/tests/tcg/lm32/test_cmpnei.S
deleted file mode 100644
index 060dd9d394..0000000000
--- a/tests/tcg/lm32/test_cmpnei.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name CMPNEI_1
-mvi r1, 0
-cmpnei r3, r1, 0
-check_r3 0
-
-test_name CMPNEI_2
-mvi r1, 0
-cmpnei r3, r1, 1
-check_r3 1
-
-test_name CMPNEI_3
-mvi r1, 1
-cmpnei r3, r1, 0
-check_r3 1
-
-test_name CMPNEI_4
-load r1 0xffffffff
-cmpnei r3, r1, -1
-check_r3 0
-
-test_name CMPNEI_5
-mvi r3, 0
-cmpnei r3, r3, 0
-check_r3 0
-
-test_name CMPNEI_6
-mvi r3, 0
-cmpnei r3, r3, 1
-check_r3 1
-
-end
diff --git a/tests/tcg/lm32/test_divu.S b/tests/tcg/lm32/test_divu.S
deleted file mode 100644
index f381d095c5..0000000000
--- a/tests/tcg/lm32/test_divu.S
+++ /dev/null
@@ -1,29 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name DIVU_1
-mvi r1, 0
-mvi r2, 1
-divu r3, r1, r2
-check_r3 0
-
-test_name DIVU_2
-mvi r1, 1
-mvi r2, 1
-divu r3, r1, r2
-check_r3 1
-
-test_name DIVU_3
-mvi r1, 0
-mvi r2, 0
-divu r3, r1, r2
-check_excp 16
-
-test_name DIVU_4
-load r1 0xabcdef12
-load r2 0x12345
-divu r3, r1, r2
-check_r3 0x9700
-
-end
diff --git a/tests/tcg/lm32/test_eret.S b/tests/tcg/lm32/test_eret.S
deleted file mode 100644
index 6830bd1abf..0000000000
--- a/tests/tcg/lm32/test_eret.S
+++ /dev/null
@@ -1,38 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ERET_1
-mvi r1, 2
-wcsr IE, r1
-load ea mark
-eret
-tc_fail
-bi 1f
-
-mark:
-tc_pass
-
-1:
-test_name ERET_2
-rcsr r3, IE
-check_r3 3
-
-test_name ERET_3
-mvi r1, 0
-wcsr IE, r1
-load ea mark2
-eret
-tc_fail
-bi 1f
-
-mark2:
-tc_pass
-
-1:
-test_name ERET_4
-rcsr r3, IE
-check_r3 0
-
-end
-
diff --git a/tests/tcg/lm32/test_lb.S b/tests/tcg/lm32/test_lb.S
deleted file mode 100644
index d677eea4c4..0000000000
--- a/tests/tcg/lm32/test_lb.S
+++ /dev/null
@@ -1,49 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name LB_1
-load r1 data
-lb r3, (r1+0)
-check_r3 0x7e
-
-test_name LB_2
-load r1 data
-lb r3, (r1+1)
-check_r3 0x7f
-
-test_name LB_3
-load r1 data
-lb r3, (r1+-1)
-check_r3 0x7d
-
-test_name LB_4
-load r1 data_msb
-lb r3, (r1+0)
-check_r3 0xfffffffe
-
-test_name LB_5
-load r1 data_msb
-lb r3, (r1+1)
-check_r3 0xffffffff
-
-test_name LB_6
-load r1 data_msb
-lb r3, (r1+-1)
-check_r3 0xfffffffd
-
-test_name LB_7
-load r3 data
-lb r3, (r3+0)
-check_r3 0x7e
-
-end
-
-.data
- .align 4
- .byte 0x7a, 0x7b, 0x7c, 0x7d
-data:
- .byte 0x7e, 0x7f, 0x70, 0x71
- .byte 0xfa, 0xfb, 0xfc, 0xfd
-data_msb:
- .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/tcg/lm32/test_lbu.S b/tests/tcg/lm32/test_lbu.S
deleted file mode 100644
index dc5d5f67d3..0000000000
--- a/tests/tcg/lm32/test_lbu.S
+++ /dev/null
@@ -1,49 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name LBU_1
-load r1 data
-lbu r3, (r1+0)
-check_r3 0x7e
-
-test_name LBU_2
-load r1 data
-lbu r3, (r1+1)
-check_r3 0x7f
-
-test_name LBU_3
-load r1 data
-lbu r3, (r1+-1)
-check_r3 0x7d
-
-test_name LBU_4
-load r1 data_msb
-lbu r3, (r1+0)
-check_r3 0xfe
-
-test_name LBU_5
-load r1 data_msb
-lbu r3, (r1+1)
-check_r3 0xff
-
-test_name LBU_6
-load r1 data_msb
-lbu r3, (r1+-1)
-check_r3 0xfd
-
-test_name LBU_7
-load r3 data
-lbu r3, (r3+0)
-check_r3 0x7e
-
-end
-
-.data
- .align 4
- .byte 0x7a, 0x7b, 0x7c, 0x7d
-data:
- .byte 0x7e, 0x7f, 0x70, 0x71
- .byte 0xfa, 0xfb, 0xfc, 0xfd
-data_msb:
- .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/tcg/lm32/test_lh.S b/tests/tcg/lm32/test_lh.S
deleted file mode 100644
index 397996bddd..0000000000
--- a/tests/tcg/lm32/test_lh.S
+++ /dev/null
@@ -1,49 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name LH_1
-load r1 data
-lh r3, (r1+0)
-check_r3 0x7e7f
-
-test_name LH_2
-load r1 data
-lh r3, (r1+2)
-check_r3 0x7071
-
-test_name LH_3
-load r1 data
-lh r3, (r1+-2)
-check_r3 0x7c7d
-
-test_name LH_4
-load r1 data_msb
-lh r3, (r1+0)
-check_r3 0xfffffeff
-
-test_name LH_5
-load r1 data_msb
-lh r3, (r1+2)
-check_r3 0xfffff0f1
-
-test_name LH_6
-load r1 data_msb
-lh r3, (r1+-2)
-check_r3 0xfffffcfd
-
-test_name LH_7
-load r3 data
-lh r3, (r3+0)
-check_r3 0x7e7f
-
-end
-
-.data
- .align 4
- .byte 0x7a, 0x7b, 0x7c, 0x7d
-data:
- .byte 0x7e, 0x7f, 0x70, 0x71
- .byte 0xfa, 0xfb, 0xfc, 0xfd
-data_msb:
- .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/tcg/lm32/test_lhu.S b/tests/tcg/lm32/test_lhu.S
deleted file mode 100644
index 8de7c52560..0000000000
--- a/tests/tcg/lm32/test_lhu.S
+++ /dev/null
@@ -1,49 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name LHU_1
-load r1 data
-lhu r3, (r1+0)
-check_r3 0x7e7f
-
-test_name LHU_2
-load r1 data
-lhu r3, (r1+2)
-check_r3 0x7071
-
-test_name LHU_3
-load r1 data
-lhu r3, (r1+-2)
-check_r3 0x7c7d
-
-test_name LHU_4
-load r1 data_msb
-lhu r3, (r1+0)
-check_r3 0xfeff
-
-test_name LHU_5
-load r1 data_msb
-lhu r3, (r1+2)
-check_r3 0xf0f1
-
-test_name LHU_6
-load r1 data_msb
-lhu r3, (r1+-2)
-check_r3 0xfcfd
-
-test_name LHU_7
-load r3 data
-lhu r3, (r3+0)
-check_r3 0x7e7f
-
-end
-
-.data
- .align 4
- .byte 0x7a, 0x7b, 0x7c, 0x7d
-data:
- .byte 0x7e, 0x7f, 0x70, 0x71
- .byte 0xfa, 0xfb, 0xfc, 0xfd
-data_msb:
- .byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/tcg/lm32/test_lw.S b/tests/tcg/lm32/test_lw.S
deleted file mode 100644
index 996e5f8c88..0000000000
--- a/tests/tcg/lm32/test_lw.S
+++ /dev/null
@@ -1,32 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name LW_1
-load r1 data
-lw r3, (r1+0)
-check_r3 0x7e7f7071
-
-test_name LW_2
-load r1 data
-lw r3, (r1+4)
-check_r3 0x72737475
-
-test_name LW_3
-load r1 data
-lw r3, (r1+-4)
-check_r3 0x7a7b7c7d
-
-test_name LW_4
-load r3 data
-lw r3, (r3+0)
-check_r3 0x7e7f7071
-
-end
-
-.data
- .align 4
- .byte 0x7a, 0x7b, 0x7c, 0x7d
-data:
- .byte 0x7e, 0x7f, 0x70, 0x71
- .byte 0x72, 0x73, 0x74, 0x75
diff --git a/tests/tcg/lm32/test_modu.S b/tests/tcg/lm32/test_modu.S
deleted file mode 100644
index 42486900b4..0000000000
--- a/tests/tcg/lm32/test_modu.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name MODU_1
-mvi r1, 0
-mvi r2, 1
-modu r3, r1, r2
-check_r3 0
-
-test_name MODU_2
-mvi r1, 1
-mvi r2, 1
-modu r3, r1, r2
-check_r3 0
-
-test_name MODU_3
-mvi r1, 3
-mvi r2, 2
-modu r3, r1, r2
-check_r3 1
-
-test_name MODU_4
-mvi r1, 0
-mvi r2, 0
-modu r3, r1, r2
-check_excp 16
-
-test_name MODU_5
-load r1 0xabcdef12
-load r2 0x12345
-modu r3, r1, r2
-check_r3 0x3c12
-
-end
diff --git a/tests/tcg/lm32/test_mul.S b/tests/tcg/lm32/test_mul.S
deleted file mode 100644
index e9b937e648..0000000000
--- a/tests/tcg/lm32/test_mul.S
+++ /dev/null
@@ -1,70 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name MUL_1
-mvi r1, 0
-mvi r2, 0
-mul r3, r1, r2
-check_r3 0
-
-test_name MUL_2
-mvi r1, 1
-mvi r2, 0
-mul r3, r1, r2
-check_r3 0
-
-test_name MUL_3
-mvi r1, 0
-mvi r2, 1
-mul r3, r1, r2
-check_r3 0
-
-test_name MUL_4
-mvi r1, 1
-mvi r2, 1
-mul r3, r1, r2
-check_r3 1
-
-test_name MUL_5
-mvi r1, 2
-mvi r2, -1
-mul r3, r1, r2
-check_r3 -2
-
-test_name MUL_6
-mvi r1, -2
-mvi r2, -1
-mul r3, r1, r2
-check_r3 2
-
-test_name MUL_7
-mvi r1, 0x1234
-mvi r2, 0x789
-mul r3, r1, r2
-check_r3 0x8929d4
-
-test_name MUL_8
-mvi r3, 4
-mul r3, r3, r3
-check_r3 16
-
-test_name MUL_9
-mvi r2, 2
-mvi r3, 4
-mul r3, r3, r2
-check_r3 8
-
-test_name MUL_10
-load r1 0x12345678
-load r2 0x7bcdef12
-mul r3, r1, r2
-check_r3 0xa801c70
-
-test_name MUL_11
-load r1 0x12345678
-load r2 0xabcdef12
-mul r3, r1, r2
-check_r3 0x8a801c70
-
-end
diff --git a/tests/tcg/lm32/test_muli.S b/tests/tcg/lm32/test_muli.S
deleted file mode 100644
index d6dd4a0f7e..0000000000
--- a/tests/tcg/lm32/test_muli.S
+++ /dev/null
@@ -1,45 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name MULI_1
-mvi r1, 0
-muli r3, r1, 0
-check_r3 0
-
-test_name MULI_2
-mvi r1, 1
-muli r3, r1, 0
-check_r3 0
-
-test_name MULI_3
-mvi r1, 0
-muli r3, r1, 1
-check_r3 0
-
-test_name MULI_4
-mvi r1, 1
-muli r3, r1, 1
-check_r3 1
-
-test_name MULI_5
-mvi r1, 2
-muli r3, r1, -1
-check_r3 -2
-
-test_name MULI_6
-mvi r1, -2
-muli r3, r1, -1
-check_r3 2
-
-test_name MULI_7
-mvi r1, 0x1234
-muli r3, r1, 0x789
-check_r3 0x8929d4
-
-test_name MULI_8
-mvi r3, 4
-muli r3, r3, 4
-check_r3 16
-
-end
diff --git a/tests/tcg/lm32/test_nor.S b/tests/tcg/lm32/test_nor.S
deleted file mode 100644
index 74d7592565..0000000000
--- a/tests/tcg/lm32/test_nor.S
+++ /dev/null
@@ -1,51 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name NOR_1
-mvi r1, 0
-mvi r2, 0
-nor r3, r1, r2
-check_r3 0xffffffff
-
-test_name NOR_2
-mvi r1, 0
-mvi r2, 1
-nor r3, r1, r2
-check_r3 0xfffffffe
-
-test_name NOR_3
-mvi r1, 1
-mvi r2, 1
-nor r3, r1, r2
-check_r3 0xfffffffe
-
-test_name NOR_4
-mvi r1, 1
-mvi r2, 0
-nor r3, r1, r2
-check_r3 0xfffffffe
-
-test_name NOR_5
-load r1 0xaa55aa55
-load r2 0x55aa55aa
-nor r3, r1, r2
-check_r3 0
-
-test_name NOR_6
-load r1 0xaa550000
-load r2 0x0000aa55
-nor r3, r1, r2
-check_r3 0x55aa55aa
-
-test_name NOR_7
-load r1 0xaa55aa55
-nor r3, r1, r1
-check_r3 0x55aa55aa
-
-test_name NOR_8
-load r3 0xaa55aa55
-nor r3, r3, r3
-check_r3 0x55aa55aa
-
-end
diff --git a/tests/tcg/lm32/test_nori.S b/tests/tcg/lm32/test_nori.S
deleted file mode 100644
index d00309c73e..0000000000
--- a/tests/tcg/lm32/test_nori.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name NORI_1
-mvi r1, 0
-nori r3, r1, 0
-check_r3 0xffffffff
-
-test_name NORI_2
-mvi r1, 0
-nori r3, r1, 1
-check_r3 0xfffffffe
-
-test_name NORI_3
-mvi r1, 1
-nori r3, r1, 1
-check_r3 0xfffffffe
-
-test_name NORI_4
-mvi r1, 1
-nori r3, r1, 0
-check_r3 0xfffffffe
-
-test_name NORI_5
-load r1 0xaa55aa55
-nori r3, r1, 0x55aa
-check_r3 0x55aa0000
-
-test_name NORI_6
-load r3 0xaa55aa55
-nori r3, r3, 0x55aa
-check_r3 0x55aa0000
-
-end
diff --git a/tests/tcg/lm32/test_or.S b/tests/tcg/lm32/test_or.S
deleted file mode 100644
index 4ed292330e..0000000000
--- a/tests/tcg/lm32/test_or.S
+++ /dev/null
@@ -1,51 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name OR_1
-mvi r1, 0
-mvi r2, 0
-or r3, r1, r2
-check_r3 0
-
-test_name OR_2
-mvi r1, 0
-mvi r2, 1
-or r3, r1, r2
-check_r3 1
-
-test_name OR_3
-mvi r1, 1
-mvi r2, 1
-or r3, r1, r2
-check_r3 1
-
-test_name OR_4
-mvi r1, 1
-mvi r2, 0
-or r3, r1, r2
-check_r3 1
-
-test_name OR_5
-load r1 0xaa55aa55
-load r2 0x55aa55aa
-or r3, r1, r2
-check_r3 0xffffffff
-
-test_name OR_6
-load r1 0xaa550000
-load r2 0x0000aa55
-or r3, r1, r2
-check_r3 0xaa55aa55
-
-test_name OR_7
-load r1 0xaa55aa55
-or r3, r1, r1
-check_r3 0xaa55aa55
-
-test_name OR_8
-load r3 0xaa55aa55
-or r3, r3, r3
-check_r3 0xaa55aa55
-
-end
diff --git a/tests/tcg/lm32/test_orhi.S b/tests/tcg/lm32/test_orhi.S
deleted file mode 100644
index 78b7600e03..0000000000
--- a/tests/tcg/lm32/test_orhi.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ORHI_1
-mvi r1, 0
-orhi r3, r1, 0
-check_r3 0
-
-test_name ORHI_2
-mvi r1, 0
-orhi r3, r1, 1
-check_r3 0x00010000
-
-test_name ORHI_3
-load r1 0x00010000
-orhi r3, r1, 1
-check_r3 0x00010000
-
-test_name ORHI_4
-mvi r1, 1
-orhi r3, r1, 0
-check_r3 1
-
-test_name ORHI_5
-load r1 0xaa55aa55
-orhi r3, r1, 0x55aa
-check_r3 0xffffaa55
-
-test_name ORHI_6
-load r3 0xaa55aa55
-orhi r3, r3, 0x55aa
-check_r3 0xffffaa55
-
-end
diff --git a/tests/tcg/lm32/test_ori.S b/tests/tcg/lm32/test_ori.S
deleted file mode 100644
index 3d576cdb8b..0000000000
--- a/tests/tcg/lm32/test_ori.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name ORI_1
-mvi r1, 0
-ori r3, r1, 0
-check_r3 0
-
-test_name ORI_2
-mvi r1, 0
-ori r3, r1, 1
-check_r3 1
-
-test_name ORI_3
-mvi r1, 1
-ori r3, r1, 1
-check_r3 1
-
-test_name ORI_4
-mvi r1, 1
-ori r3, r1, 0
-check_r3 1
-
-test_name ORI_5
-load r1 0xaa55aa55
-ori r3, r1, 0x55aa
-check_r3 0xaa55ffff
-
-test_name ORI_6
-load r3 0xaa55aa55
-ori r3, r3, 0x55aa
-check_r3 0xaa55ffff
-
-end
diff --git a/tests/tcg/lm32/test_ret.S b/tests/tcg/lm32/test_ret.S
deleted file mode 100644
index 320264f148..0000000000
--- a/tests/tcg/lm32/test_ret.S
+++ /dev/null
@@ -1,14 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name RET_1
-load ra mark
-ret
-
-tc_fail
-end
-
-mark:
-tc_pass
-end
diff --git a/tests/tcg/lm32/test_sb.S b/tests/tcg/lm32/test_sb.S
deleted file mode 100644
index b15a89d342..0000000000
--- a/tests/tcg/lm32/test_sb.S
+++ /dev/null
@@ -1,32 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SB_1
-load r1 data
-load r2 0xf0f1f2aa
-sb (r1+0), r2
-check_mem data 0xaa000000
-
-test_name SB_2
-load r1 data
-load r2 0xf0f1f2bb
-sb (r1+1), r2
-check_mem data 0xaabb0000
-
-test_name SB_3
-load r1 data
-load r2 0xf0f1f2cc
-sb (r1+-1), r2
-check_mem data0 0x000000cc
-
-end
-
-.data
- .align 4
-data0:
- .byte 0, 0, 0, 0
-data:
- .byte 0, 0, 0, 0
-data1:
- .byte 0, 0, 0, 0
diff --git a/tests/tcg/lm32/test_scall.S b/tests/tcg/lm32/test_scall.S
deleted file mode 100644
index 46032f841d..0000000000
--- a/tests/tcg/lm32/test_scall.S
+++ /dev/null
@@ -1,24 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SCALL_1
-mvi r1, 1
-wcsr IE, r1
-# we are running in a semi hosted environment
-# therefore we have to set r8 to some unused system
-# call
-mvi r8, 0
-insn:
-scall
-check_excp 64
-
-test_name SCALL_2
-mv r3, ea
-check_r3 insn
-
-test_name SCALL_3
-rcsr r3, IE
-check_r3 2
-
-end
diff --git a/tests/tcg/lm32/test_sextb.S b/tests/tcg/lm32/test_sextb.S
deleted file mode 100644
index 58db8ee8b9..0000000000
--- a/tests/tcg/lm32/test_sextb.S
+++ /dev/null
@@ -1,20 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SEXTB_1
-mvi r1, 0
-sextb r3, r1
-check_r3 0
-
-test_name SEXTB_2
-mvi r1, 0x7f
-sextb r3, r1
-check_r3 0x0000007f
-
-test_name SEXTB_3
-mvi r1, 0x80
-sextb r3, r1
-check_r3 0xffffff80
-
-end
diff --git a/tests/tcg/lm32/test_sexth.S b/tests/tcg/lm32/test_sexth.S
deleted file mode 100644
index a059ec3ee6..0000000000
--- a/tests/tcg/lm32/test_sexth.S
+++ /dev/null
@@ -1,20 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SEXTH_1
-mvi r1, 0
-sexth r3, r1
-check_r3 0
-
-test_name SEXTH_2
-load r1 0x7fff
-sexth r3, r1
-check_r3 0x00007fff
-
-test_name SEXTH_3
-load r1 0x8000
-sexth r3, r1
-check_r3 0xffff8000
-
-end
diff --git a/tests/tcg/lm32/test_sh.S b/tests/tcg/lm32/test_sh.S
deleted file mode 100644
index bba10224f6..0000000000
--- a/tests/tcg/lm32/test_sh.S
+++ /dev/null
@@ -1,32 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SH_1
-load r1 data
-load r2 0xf0f1aaaa
-sh (r1+0), r2
-check_mem data 0xaaaa0000
-
-test_name SH_2
-load r1 data
-load r2 0xf0f1bbbb
-sh (r1+2), r2
-check_mem data 0xaaaabbbb
-
-test_name SH_3
-load r1 data
-load r2 0xf0f1cccc
-sh (r1+-2), r2
-check_mem data0 0x0000cccc
-
-end
-
-.data
- .align 4
-data0:
- .byte 0, 0, 0, 0
-data:
- .byte 0, 0, 0, 0
-data1:
- .byte 0, 0, 0, 0
diff --git a/tests/tcg/lm32/test_sl.S b/tests/tcg/lm32/test_sl.S
deleted file mode 100644
index 0aee17fdb8..0000000000
--- a/tests/tcg/lm32/test_sl.S
+++ /dev/null
@@ -1,45 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SL_1
-mvi r1, 1
-mvi r2, 0
-sl r3, r1, r2
-check_r3 1
-
-test_name SL_2
-mvi r1, 0
-mvi r2, 1
-sl r3, r1, r2
-check_r3 0
-
-test_name SL_3
-mvi r1, 1
-mvi r2, 31
-sl r3, r1, r2
-check_r3 0x80000000
-
-test_name SL_4
-mvi r1, 16
-mvi r2, 31
-sl r3, r1, r2
-check_r3 0
-
-test_name SL_5
-mvi r1, 1
-mvi r2, 34
-sl r3, r1, r2
-check_r3 4
-
-test_name SL_6
-mvi r1, 2
-sl r3, r1, r1
-check_r3 8
-
-test_name SL_7
-mvi r3, 2
-sl r3, r3, r3
-check_r3 8
-
-end
diff --git a/tests/tcg/lm32/test_sli.S b/tests/tcg/lm32/test_sli.S
deleted file mode 100644
index a421de9014..0000000000
--- a/tests/tcg/lm32/test_sli.S
+++ /dev/null
@@ -1,30 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SLI_1
-mvi r1, 1
-sli r3, r1, 0
-check_r3 1
-
-test_name SLI_2
-mvi r1, 0
-sli r3, r1, 1
-check_r3 0
-
-test_name SLI_3
-mvi r1, 1
-sli r3, r1, 31
-check_r3 0x80000000
-
-test_name SLI_4
-mvi r1, 16
-sli r3, r1, 31
-check_r3 0
-
-test_name SLI_7
-mvi r3, 2
-sli r3, r3, 2
-check_r3 8
-
-end
diff --git a/tests/tcg/lm32/test_sr.S b/tests/tcg/lm32/test_sr.S
deleted file mode 100644
index 62431a9864..0000000000
--- a/tests/tcg/lm32/test_sr.S
+++ /dev/null
@@ -1,57 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SR_1
-mvi r1, 1
-mvi r2, 0
-sr r3, r1, r2
-check_r3 1
-
-test_name SR_2
-mvi r1, 0
-mvi r2, 1
-sr r3, r1, r2
-check_r3 0
-
-test_name SR_3
-load r1 0x40000000
-mvi r2, 30
-sr r3, r1, r2
-check_r3 1
-
-test_name SR_4
-load r1 0x40000000
-mvi r2, 31
-sr r3, r1, r2
-check_r3 0
-
-test_name SR_5
-mvi r1, 16
-mvi r2, 34
-sr r3, r1, r2
-check_r3 4
-
-test_name SR_6
-mvi r1, 2
-sr r3, r1, r1
-check_r3 0
-
-test_name SR_7
-mvi r3, 2
-sr r3, r3, r3
-check_r3 0
-
-test_name SR_8
-mvi r1, 0xfffffff0
-mvi r2, 2
-sr r3, r1, r2
-check_r3 0xfffffffc
-
-test_name SR_9
-mvi r1, 0xfffffff0
-mvi r2, 4
-sr r3, r1, r2
-check_r3 0xffffffff
-
-end
diff --git a/tests/tcg/lm32/test_sri.S b/tests/tcg/lm32/test_sri.S
deleted file mode 100644
index c1be907b5b..0000000000
--- a/tests/tcg/lm32/test_sri.S
+++ /dev/null
@@ -1,40 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SRI_1
-mvi r1, 1
-sri r3, r1, 0
-check_r3 1
-
-test_name SRI_2
-mvi r1, 0
-sri r3, r1, 1
-check_r3 0
-
-test_name SRI_3
-load r1 0x40000000
-sri r3, r1, 30
-check_r3 1
-
-test_name SRI_4
-load r1 0x40000000
-sri r3, r1, 31
-check_r3 0
-
-test_name SRI_5
-mvi r3, 2
-sri r3, r3, 2
-check_r3 0
-
-test_name SRI_6
-mvi r1, 0xfffffff0
-sri r3, r1, 2
-check_r3 0xfffffffc
-
-test_name SRI_7
-mvi r1, 0xfffffff0
-sri r3, r1, 4
-check_r3 0xffffffff
-
-end
diff --git a/tests/tcg/lm32/test_sru.S b/tests/tcg/lm32/test_sru.S
deleted file mode 100644
index 2ab0b54c77..0000000000
--- a/tests/tcg/lm32/test_sru.S
+++ /dev/null
@@ -1,57 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SRU_1
-mvi r1, 1
-mvi r2, 0
-sru r3, r1, r2
-check_r3 1
-
-test_name SRU_2
-mvi r1, 0
-mvi r2, 1
-sru r3, r1, r2
-check_r3 0
-
-test_name SRU_3
-load r1 0x40000000
-mvi r2, 30
-sru r3, r1, r2
-check_r3 1
-
-test_name SRU_4
-load r1 0x40000000
-mvi r2, 31
-sru r3, r1, r2
-check_r3 0
-
-test_name SRU_5
-mvi r1, 16
-mvi r2, 34
-sru r3, r1, r2
-check_r3 4
-
-test_name SRU_6
-mvi r1, 2
-sru r3, r1, r1
-check_r3 0
-
-test_name SRU_7
-mvi r3, 2
-sru r3, r3, r3
-check_r3 0
-
-test_name SRU_8
-mvi r1, 0xfffffff0
-mvi r2, 2
-sru r3, r1, r2
-check_r3 0x3ffffffc
-
-test_name SRU_9
-mvi r1, 0xfffffff0
-mvi r2, 4
-sru r3, r1, r2
-check_r3 0x0fffffff
-
-end
diff --git a/tests/tcg/lm32/test_srui.S b/tests/tcg/lm32/test_srui.S
deleted file mode 100644
index 872c374121..0000000000
--- a/tests/tcg/lm32/test_srui.S
+++ /dev/null
@@ -1,40 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SRUI_1
-mvi r1, 1
-srui r3, r1, 0
-check_r3 1
-
-test_name SRUI_2
-mvi r1, 0
-srui r3, r1, 1
-check_r3 0
-
-test_name SRUI_3
-load r1 0x40000000
-srui r3, r1, 30
-check_r3 1
-
-test_name SRUI_4
-load r1 0x40000000
-srui r3, r1, 31
-check_r3 0
-
-test_name SRUI_5
-mvi r3, 2
-srui r3, r3, 2
-check_r3 0
-
-test_name SRUI_6
-mvi r1, 0xfffffff0
-srui r3, r1, 2
-check_r3 0x3ffffffc
-
-test_name SRUI_7
-mvi r1, 0xfffffff0
-srui r3, r1, 4
-check_r3 0x0fffffff
-
-end
diff --git a/tests/tcg/lm32/test_sub.S b/tests/tcg/lm32/test_sub.S
deleted file mode 100644
index 44b74a9e10..0000000000
--- a/tests/tcg/lm32/test_sub.S
+++ /dev/null
@@ -1,75 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SUB_1
-mvi r1, 0
-mvi r2, 0
-sub r3, r1, r2
-check_r3 0
-
-test_name SUB_2
-mvi r1, 0
-mvi r2, 1
-sub r3, r1, r2
-check_r3 -1
-
-test_name SUB_3
-mvi r1, 1
-mvi r2, 0
-sub r3, r1, r2
-check_r3 1
-
-test_name SUB_4
-mvi r1, 1
-mvi r2, -1
-sub r3, r1, r2
-check_r3 2
-
-test_name SUB_5
-mvi r1, -1
-mvi r2, 1
-sub r3, r1, r2
-check_r3 -2
-
-test_name SUB_6
-mvi r1, -1
-mvi r2, 0
-sub r3, r1, r2
-check_r3 -1
-
-test_name SUB_7
-mvi r1, 0
-mvi r2, -1
-sub r3, r1, r2
-check_r3 1
-
-test_name SUB_8
-mvi r3, 2
-sub r3, r3, r3
-check_r3 0
-
-test_name SUB_9
-mvi r1, 4
-mvi r3, 2
-sub r3, r1, r3
-check_r3 2
-
-test_name SUB_10
-mvi r1, 4
-mvi r3, 2
-sub r3, r3, r1
-check_r3 -2
-
-test_name SUB_11
-mvi r1, 4
-sub r3, r1, r1
-check_r3 0
-
-test_name SUB_12
-load r1 0x12345678
-load r2 0xabcdef97
-sub r3, r1, r2
-check_r3 0x666666e1
-
-end
diff --git a/tests/tcg/lm32/test_sw.S b/tests/tcg/lm32/test_sw.S
deleted file mode 100644
index 2b1c017e7b..0000000000
--- a/tests/tcg/lm32/test_sw.S
+++ /dev/null
@@ -1,38 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name SW_1
-load r1 data
-load r2 0xaabbccdd
-sw (r1+0), r2
-check_mem data 0xaabbccdd
-
-test_name SW_2
-load r1 data
-load r2 0x00112233
-sw (r1+4), r2
-check_mem data1 0x00112233
-
-test_name SW_3
-load r1 data
-load r2 0x44556677
-sw (r1+-4), r2
-check_mem data0 0x44556677
-
-test_name SW_4
-load r1 data
-sw (r1+0), r1
-lw r3, (r1+0)
-check_r3 data
-
-end
-
-.data
- .align 4
-data0:
- .byte 0, 0, 0, 0
-data:
- .byte 0, 0, 0, 0
-data1:
- .byte 0, 0, 0, 0
diff --git a/tests/tcg/lm32/test_xnor.S b/tests/tcg/lm32/test_xnor.S
deleted file mode 100644
index 14a62075f6..0000000000
--- a/tests/tcg/lm32/test_xnor.S
+++ /dev/null
@@ -1,51 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name XNOR_1
-mvi r1, 0
-mvi r2, 0
-xnor r3, r1, r2
-check_r3 0xffffffff
-
-test_name XNOR_2
-mvi r1, 0
-mvi r2, 1
-xnor r3, r1, r2
-check_r3 0xfffffffe
-
-test_name XNOR_3
-mvi r1, 1
-mvi r2, 1
-xnor r3, r1, r2
-check_r3 0xffffffff
-
-test_name XNOR_4
-mvi r1, 1
-mvi r2, 0
-xnor r3, r1, r2
-check_r3 0xfffffffe
-
-test_name XNOR_5
-load r1 0xaa55aa55
-load r2 0x55aa55aa
-xnor r3, r1, r2
-check_r3 0
-
-test_name XNOR_6
-load r1 0xaa550000
-load r2 0x0000aa55
-xnor r3, r1, r2
-check_r3 0x55aa55aa
-
-test_name XNOR_7
-load r1 0xaa55aa55
-xnor r3, r1, r1
-check_r3 0xffffffff
-
-test_name XNOR_8
-load r3 0xaa55aa55
-xnor r3, r3, r3
-check_r3 0xffffffff
-
-end
diff --git a/tests/tcg/lm32/test_xnori.S b/tests/tcg/lm32/test_xnori.S
deleted file mode 100644
index 9d9c3c6780..0000000000
--- a/tests/tcg/lm32/test_xnori.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name XNORI_1
-mvi r1, 0
-xnori r3, r1, 0
-check_r3 0xffffffff
-
-test_name XNORI_2
-mvi r1, 0
-xnori r3, r1, 1
-check_r3 0xfffffffe
-
-test_name XNORI_3
-mvi r1, 1
-xnori r3, r1, 1
-check_r3 0xffffffff
-
-test_name XNORI_4
-mvi r1, 1
-xnori r3, r1, 0
-check_r3 0xfffffffe
-
-test_name XNORI_5
-load r1 0xaa55aa55
-xnori r3, r1, 0x5555
-check_r3 0x55aa00ff
-
-test_name XNORI_6
-load r3 0xaa55aa55
-xnori r3, r3, 0x5555
-check_r3 0x55aa00ff
-
-end
diff --git a/tests/tcg/lm32/test_xor.S b/tests/tcg/lm32/test_xor.S
deleted file mode 100644
index 6c6e712bae..0000000000
--- a/tests/tcg/lm32/test_xor.S
+++ /dev/null
@@ -1,51 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name XOR_1
-mvi r1, 0
-mvi r2, 0
-xor r3, r1, r2
-check_r3 0
-
-test_name XOR_2
-mvi r1, 0
-mvi r2, 1
-xor r3, r1, r2
-check_r3 1
-
-test_name XOR_3
-mvi r1, 1
-mvi r2, 1
-xor r3, r1, r2
-check_r3 0
-
-test_name XOR_4
-mvi r1, 1
-mvi r2, 0
-xor r3, r1, r2
-check_r3 1
-
-test_name XOR_5
-load r1 0xaa55aa55
-load r2 0x55aa55aa
-xor r3, r1, r2
-check_r3 0xffffffff
-
-test_name XOR_6
-load r1 0xaa550000
-load r2 0x0000aa55
-xor r3, r1, r2
-check_r3 0xaa55aa55
-
-test_name XOR_7
-load r1 0xaa55aa55
-xor r3, r1, r1
-check_r3 0
-
-test_name XOR_8
-load r3 0xaa55aa55
-xor r3, r3, r3
-check_r3 0
-
-end
diff --git a/tests/tcg/lm32/test_xori.S b/tests/tcg/lm32/test_xori.S
deleted file mode 100644
index 2051699f12..0000000000
--- a/tests/tcg/lm32/test_xori.S
+++ /dev/null
@@ -1,35 +0,0 @@
-.include "macros.inc"
-
-start
-
-test_name XORI_1
-mvi r1, 0
-xori r3, r1, 0
-check_r3 0
-
-test_name XORI_2
-mvi r1, 0
-xori r3, r1, 1
-check_r3 1
-
-test_name XORI_3
-mvi r1, 1
-xori r3, r1, 1
-check_r3 0
-
-test_name XORI_4
-mvi r1, 1
-xori r3, r1, 0
-check_r3 1
-
-test_name XORI_5
-load r1 0xaa55aa55
-xori r3, r1, 0x5555
-check_r3 0xaa55ff00
-
-test_name XORI_6
-load r3 0xaa55aa55
-xori r3, r3, 0x5555
-check_r3 0xaa55ff00
-
-end
diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c
index eb0ec6f8eb..41c7f66e2e 100644
--- a/tests/tcg/multiarch/system/memory.c
+++ b/tests/tcg/multiarch/system/memory.c
@@ -326,6 +326,7 @@ static bool do_unsigned_test(init_ufn fn)
fn(i);
ok = do_unsigned_reads(i);
}
+ return ok;
#else
fn(0);
return do_unsigned_reads(0);
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index 0c6a4585fc..a6a4ddaeca 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -10,4 +10,17 @@ PPC64_TESTS=bcdsub
endif
bcdsub: CFLAGS += -mpower8-vector
+PPC64_TESTS += byte_reverse
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),)
+run-byte_reverse: QEMU_OPTS+=-cpu POWER10
+run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10
+else
+byte_reverse:
+ $(call skip-test, "BUILD of $@", "missing compiler support")
+run-byte_reverse:
+ $(call skip-test, "RUN of byte_reverse", "not built")
+run-plugin-byte_reverse-with-%:
+ $(call skip-test, "RUN of byte_reverse ($*)", "not built")
+endif
+
TESTS += $(PPC64_TESTS)
diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target
index 1acfcff94a..c0c14ffbad 100644
--- a/tests/tcg/ppc64le/Makefile.target
+++ b/tests/tcg/ppc64le/Makefile.target
@@ -9,4 +9,17 @@ PPC64LE_TESTS=bcdsub
endif
bcdsub: CFLAGS += -mpower8-vector
+PPC64LE_TESTS += byte_reverse
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER10),)
+run-byte_reverse: QEMU_OPTS+=-cpu POWER10
+run-plugin-byte_reverse-with-%: QEMU_OPTS+=-cpu POWER10
+else
+byte_reverse:
+ $(call skip-test, "BUILD of $@", "missing compiler support")
+run-byte_reverse:
+ $(call skip-test, "RUN of byte_reverse", "not built")
+run-plugin-byte_reverse-with-%:
+ $(call skip-test, "RUN of byte_reverse ($*)", "not built")
+endif
+
TESTS += $(PPC64LE_TESTS)
diff --git a/tests/tcg/ppc64le/byte_reverse.c b/tests/tcg/ppc64le/byte_reverse.c
new file mode 100644
index 0000000000..53b76fc2e2
--- /dev/null
+++ b/tests/tcg/ppc64le/byte_reverse.c
@@ -0,0 +1,21 @@
+#include <assert.h>
+
+int main(void)
+{
+ unsigned long var;
+
+ var = 0xFEDCBA9876543210;
+ asm("brh %0, %0" : "+r"(var));
+ assert(var == 0xDCFE98BA54761032);
+
+ var = 0xFEDCBA9876543210;
+ asm("brw %0, %0" : "+r"(var));
+ assert(var == 0x98BADCFE10325476);
+
+ var = 0xFEDCBA9876543210;
+ asm("brd %0, %0" : "+r"(var));
+ assert(var == 0x1032547698BADCFE);
+
+ return 0;
+}
+
diff --git a/tests/tcg/sparc64/Makefile.target b/tests/tcg/sparc64/Makefile.target
index 5bd7f90583..408dace783 100644
--- a/tests/tcg/sparc64/Makefile.target
+++ b/tests/tcg/sparc64/Makefile.target
@@ -1,11 +1,6 @@
# -*- Mode: makefile -*-
#
-# sparc specific tweaks and masking out broken tests
-
-# different from the other hangs:
-# tests/tcg/multiarch/linux-test.c:264: Value too large for defined data type (ret=-1, errno=92/Value too large for defined data type)
-run-linux-test: linux-test
- $(call skip-test, $<, "BROKEN")
+# sparc specific tweaks
# On Sparc64 Linux support 8k pages
EXTRA_RUNS+=run-test-mmap-8192
diff --git a/tests/tcg/tricore/Makefile.softmmu-target b/tests/tcg/tricore/Makefile.softmmu-target
new file mode 100644
index 0000000000..5007c60ce8
--- /dev/null
+++ b/tests/tcg/tricore/Makefile.softmmu-target
@@ -0,0 +1,26 @@
+TESTS_PATH = $(SRC_PATH)/tests/tcg/tricore
+
+LDFLAGS = -T$(TESTS_PATH)/link.ld
+ASFLAGS =
+
+TESTS += test_abs.tst
+TESTS += test_bmerge.tst
+TESTS += test_clz.tst
+TESTS += test_dvstep.tst
+TESTS += test_fadd.tst
+TESTS += test_fmul.tst
+TESTS += test_ftoi.tst
+TESTS += test_madd.tst
+TESTS += test_msub.tst
+TESTS += test_muls.tst
+
+QEMU_OPTS += -M tricore_testboard -nographic -kernel
+
+%.pS: $(TESTS_PATH)/%.S
+ $(HOST_CC) -E -o $@ $<
+
+%.o: %.pS
+ $(AS) $(ASFLAGS) -o $@ $<
+
+%.tst: %.o
+ $(LD) $(LDFLAGS) $< -o $@
diff --git a/tests/tcg/tricore/link.ld b/tests/tcg/tricore/link.ld
new file mode 100644
index 0000000000..364bcdc00a
--- /dev/null
+++ b/tests/tcg/tricore/link.ld
@@ -0,0 +1,60 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-tricore")
+OUTPUT_ARCH(tricore)
+ENTRY(_start)
+
+/* the internal ram description */
+MEMORY
+{
+ text_ram (rx!p): org = 0x80000000, len = 15K
+ data_ram (w!xp): org = 0xd0000000, len = 130K
+}
+/*
+ * Define the sizes of the user and system stacks.
+ */
+__USTACK_SIZE = DEFINED (__USTACK_SIZE) ? __USTACK_SIZE : 1K ;
+/*
+ * Define the start address and the size of the context save area.
+ */
+__CSA_BEGIN = 0xd0000000 ;
+__CSA_SIZE = 8k ;
+__CSA_END = __CSA_BEGIN + __CSA_SIZE ;
+
+SECTIONS
+{
+ .text :
+ {
+ *(.text)
+ . = ALIGN(8);
+ } > text_ram
+
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ } > data_ram
+
+ .data :
+ {
+ . = ALIGN(8) ;
+ *(.data)
+ *(.data.*)
+ . = ALIGN(8) ;
+ __USTACK = . + __USTACK_SIZE -768;
+
+ } > data_ram
+ /*
+ * Allocate space for BSS sections.
+ */
+ .bss :
+ {
+ BSS_BASE = . ;
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(8) ;
+ } > data_ram
+ /* Make sure CSA, stack and heap addresses are properly aligned. */
+ _. = ASSERT ((__CSA_BEGIN & 0x3f) == 0 , "illegal CSA start address") ;
+ _. = ASSERT ((__CSA_SIZE & 0x3f) == 0 , "illegal CSA size") ;
+
+}
diff --git a/tests/tcg/tricore/macros.h b/tests/tcg/tricore/macros.h
new file mode 100644
index 0000000000..0d76fc403a
--- /dev/null
+++ b/tests/tcg/tricore/macros.h
@@ -0,0 +1,129 @@
+/* Helpers */
+#define LI(reg, val) \
+ mov.u reg, lo:val; \
+ movh DREG_TEMP_LI, up:val; \
+ or reg, reg, DREG_TEMP_LI; \
+
+/* Address definitions */
+#define TESTDEV_ADDR 0xf0000000
+/* Register definitions */
+#define DREG_RS1 %d0
+#define DREG_RS2 %d1
+#define DREG_RS3 %d4
+#define DREG_CALC_RESULT %d1
+#define DREG_CALC_PSW %d2
+#define DREG_CORRECT_PSW %d3
+#define DREG_TEMP_LI %d10
+#define DREG_TEMP %d11
+#define DREG_TEST_NUM %d14
+#define DREG_CORRECT_RESULT %d15
+
+#define DREG_DEV_ADDR %a15
+
+#define EREG_RS1 %e6
+#define EREG_RS1_LO %d6
+#define EREG_RS1_HI %d7
+#define EREG_RS2 %e8
+#define EREG_RS2_LO %d8
+#define EREG_RS2_HI %d9
+#define EREG_CALC_RESULT %e8
+#define EREG_CALC_RESULT_HI %d9
+#define EREG_CALC_RESULT_LO %d8
+#define EREG_CORRECT_RESULT_LO %d0
+#define EREG_CORRECT_RESULT_HI %d1
+
+/* Test case wrappers */
+#define TEST_CASE(num, testreg, correct, code...) \
+test_ ## num: \
+ code; \
+ LI(DREG_CORRECT_RESULT, correct) \
+ mov DREG_TEST_NUM, num; \
+ jne testreg, DREG_CORRECT_RESULT, fail \
+
+#define TEST_CASE_E(num, correct_lo, correct_hi, code...) \
+test_ ## num: \
+ code; \
+ mov DREG_TEST_NUM, num; \
+ LI(EREG_CORRECT_RESULT_LO, correct_lo) \
+ jne EREG_CALC_RESULT_LO, EREG_CORRECT_RESULT_LO, fail; \
+ LI(EREG_CORRECT_RESULT_HI, correct_hi) \
+ jne EREG_CALC_RESULT_HI, EREG_CORRECT_RESULT_HI, fail;
+
+#define TEST_CASE_PSW(num, testreg, correct, correct_psw, code...) \
+test_ ## num: \
+ code; \
+ LI(DREG_CORRECT_RESULT, correct) \
+ mov DREG_TEST_NUM, num; \
+ jne testreg, DREG_CORRECT_RESULT, fail; \
+ mfcr DREG_CALC_PSW, $psw; \
+ LI(DREG_CORRECT_PSW, correct_psw) \
+ mov DREG_TEST_NUM, num; \
+ jne DREG_CALC_PSW, DREG_CORRECT_PSW, fail;
+
+/* Actual test case type
+ * e.g inst %dX, %dY -> TEST_D_D
+ * inst %dX, %dY, %dZ -> TEST_D_DD
+ * inst %eX, %dY, %dZ -> TEST_E_DD
+ */
+#define TEST_D_D(insn, num, result, rs1) \
+ TEST_CASE(num, DREG_CALC_RESULT, result, \
+ LI(DREG_RS1, rs1); \
+ insn DREG_CALC_RESULT, DREG_RS1; \
+ )
+
+#define TEST_D_D_PSW(insn, num, result, psw, rs1) \
+ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \
+ LI(DREG_RS1, rs1); \
+ rstv; \
+ insn DREG_CORRECT_RESULT, DREG_RS1; \
+ )
+
+#define TEST_D_DD_PSW(insn, num, result, psw, rs1, rs2) \
+ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \
+ LI(DREG_RS1, rs1); \
+ LI(DREG_RS2, rs2); \
+ rstv; \
+ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2; \
+ )
+
+#define TEST_D_DDD_PSW(insn, num, result, psw, rs1, rs2, rs3) \
+ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \
+ LI(DREG_RS1, rs1); \
+ LI(DREG_RS2, rs2); \
+ LI(DREG_RS3, rs3); \
+ rstv; \
+ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, DREG_RS3; \
+ )
+
+#define TEST_D_DDI_PSW(insn, num, result, psw, rs1, rs2, imm) \
+ TEST_CASE_PSW(num, DREG_CALC_RESULT, result, psw, \
+ LI(DREG_RS1, rs1); \
+ LI(DREG_RS2, rs2); \
+ rstv; \
+ insn DREG_CALC_RESULT, DREG_RS1, DREG_RS2, imm; \
+ )
+
+#define TEST_E_ED(insn, num, res_hi, res_lo, rs1_hi, rs1_lo, rs2) \
+ TEST_CASE_E(num, res_lo, res_hi, \
+ LI(EREG_RS1_LO, rs1_lo); \
+ LI(EREG_RS1_HI, rs1_hi); \
+ LI(DREG_RS2, rs2); \
+ insn EREG_CALC_RESULT, EREG_RS1, DREG_RS2; \
+ )
+
+/* Pass/Fail handling part */
+#define TEST_PASSFAIL \
+ j pass; \
+fail: \
+ LI(DREG_TEMP, TESTDEV_ADDR) \
+ mov.a DREG_DEV_ADDR, DREG_TEMP; \
+ st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\
+ debug; \
+ j fail; \
+pass: \
+ LI(DREG_TEMP, TESTDEV_ADDR) \
+ mov.a DREG_DEV_ADDR, DREG_TEMP; \
+ mov DREG_TEST_NUM, 0; \
+ st.w [DREG_DEV_ADDR], DREG_TEST_NUM;\
+ debug; \
+ j pass;
diff --git a/tests/tcg/tricore/test_abs.S b/tests/tcg/tricore/test_abs.S
new file mode 100644
index 0000000000..e42240159a
--- /dev/null
+++ b/tests/tcg/tricore/test_abs.S
@@ -0,0 +1,7 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_D(abs, 1, 0, 0)
+
+ TEST_PASSFAIL
diff --git a/tests/tcg/tricore/test_bmerge.S b/tests/tcg/tricore/test_bmerge.S
new file mode 100644
index 0000000000..8a0fa6d3f6
--- /dev/null
+++ b/tests/tcg/tricore/test_bmerge.S
@@ -0,0 +1,8 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DD_PSW(bmerge, 1, 0x555557f7, 0x00000b80, 0x0000001d, 0x0000ffff)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_clz.S b/tests/tcg/tricore/test_clz.S
new file mode 100644
index 0000000000..e03835f123
--- /dev/null
+++ b/tests/tcg/tricore/test_clz.S
@@ -0,0 +1,9 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_D(cls.h, 1, 0x0, 0x6db17976)
+ TEST_D_D(cls.h, 2, 0x000f000f, 0x0)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_dvstep.S b/tests/tcg/tricore/test_dvstep.S
new file mode 100644
index 0000000000..858dbc62dd
--- /dev/null
+++ b/tests/tcg/tricore/test_dvstep.S
@@ -0,0 +1,15 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ # Result RS1 RS2
+ TEST_E_ED(dvstep, 1, 0x000001ff, 0xfffe5cff, 0x00000001, 0xfffffe5c, 0x0)
+ TEST_E_ED(dvstep, 2, 0x00000000, 0x000000ff, 0x00000000, 0x00000000, 0x0)
+ TEST_E_ED(dvstep, 3, 0x0000f000, 0x000000fd, 0x010000f0, 0x00000000, 0x0)
+ TEST_E_ED(dvstep, 4, 0xfffff000, 0x00000000, 0x7ffffff0, 0x00000000, 0x0)
+ TEST_E_ED(dvstep.u, 5, 0xffffff00, 0x100008ff, 0xffffffff, 0x00100008, 0x0)
+ TEST_E_ED(dvstep.u, 6, 0x00000100, 0x00000000, 0x08000001, 0x00000000, \
+ 0xffffff2d)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_fadd.S b/tests/tcg/tricore/test_fadd.S
new file mode 100644
index 0000000000..1a65054803
--- /dev/null
+++ b/tests/tcg/tricore/test_fadd.S
@@ -0,0 +1,16 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DD_PSW(add.f, 1, 0x7fc00000, 0x00000b80, 0xffffff85, 0x00001234)
+ TEST_D_DD_PSW(add.f, 2, 0xf9c00000, 0x00000b80, 0xf9400000, 0xf9400000)
+ TEST_D_DD_PSW(add.f, 3, 0x8bb858ca, 0x00000b80, 0x8b3858ca, 0x8b3858ca)
+ TEST_D_DD_PSW(add.f, 4, 0x00000000, 0x00000b80, 0x000000ff, 0x00000000)
+ TEST_D_DD_PSW(add.f, 5, 0x7fc00000, 0x00000b80, 0xfffffe52, 0x0a4cf70c)
+ TEST_D_DD_PSW(add.f, 6, 0x9e6d5076, 0x84000b80, 0x9ded50ec, 0x9ded4fff)
+ TEST_D_DD_PSW(add.f, 7, 0x00000000, 0x04000b80, 0x0000e8bd, 0x00000000)
+ TEST_D_DD_PSW(add.f, 8, 0x7fc00000, 0xc4000b80, 0xffad546e, 0xffad546e)
+ TEST_D_DD_PSW(add.f, 9, 0x7fc00000, 0x04000b80, 0xfffe0000, 0x08130000)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_fmul.S b/tests/tcg/tricore/test_fmul.S
new file mode 100644
index 0000000000..fb1f634b2d
--- /dev/null
+++ b/tests/tcg/tricore/test_fmul.S
@@ -0,0 +1,8 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DD_PSW(mul.f, 1, 0x974f4f0a, 0x84000b80, 0x1a0b1980, 0xbcbec42d)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_ftoi.S b/tests/tcg/tricore/test_ftoi.S
new file mode 100644
index 0000000000..fb4af6b5aa
--- /dev/null
+++ b/tests/tcg/tricore/test_ftoi.S
@@ -0,0 +1,10 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_D_PSW(ftoi, 1, 0x0, 0x84000b80, 0x05f6e605)
+ TEST_D_D_PSW(ftoi, 2, 0x0, 0x04000b80, 0x00012200)
+ TEST_D_D_PSW(ftoi, 3, 0x0, 0xc4000b80, 0xffffffff)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_madd.S b/tests/tcg/tricore/test_madd.S
new file mode 100644
index 0000000000..5d839772bb
--- /dev/null
+++ b/tests/tcg/tricore/test_madd.S
@@ -0,0 +1,11 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DDI_PSW(madd, 1, 0x0000fffd, 0x60000b80, 0x0000ffff, 0x7fffffff,2)
+ TEST_D_DDI_PSW(madd, 2, 0xffff7fff, 0x60000b80, 0xffff8001, 0x7fffffff,2)
+ TEST_D_DDD_PSW(madds.u, 3, 0xffffffff, 0x60000b80, 0x00000000, 0x80000000, \
+ 0x80000000)
+
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_msub.S b/tests/tcg/tricore/test_msub.S
new file mode 100644
index 0000000000..6dee87d99c
--- /dev/null
+++ b/tests/tcg/tricore/test_msub.S
@@ -0,0 +1,9 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DDI_PSW(msub, 1, 0xd2fbe5e0, 0x00000b80,0x64003300, 0xff5420d4, -216)
+ TEST_D_DDI_PSW(msub, 2, 0xfffffc10, 0x00000b80,0xfffffe68, 0xfffffffd, -200)
+ TEST_D_DDD_PSW(msubs.u, 3, 0x0, 0x60000b80, 0x1, 0xffffffff, 0xffffffdb)
+ TEST_PASSFAIL
+
diff --git a/tests/tcg/tricore/test_muls.S b/tests/tcg/tricore/test_muls.S
new file mode 100644
index 0000000000..ca517556bc
--- /dev/null
+++ b/tests/tcg/tricore/test_muls.S
@@ -0,0 +1,9 @@
+#include "macros.h"
+.text
+.global _start
+_start:
+ TEST_D_DD_PSW(muls.u, 1, 0xffffffff, 0x78000b80, 0x80000001, 0xffffffff)
+ TEST_D_DD_PSW(muls.u, 2, 0xffffffff, 0x60000b80, 0xfffffffe, 0xffffffff)
+
+ TEST_PASSFAIL
+
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
index fc1c45a2eb..0158e4637a 100644
--- a/tests/unit/test-write-threshold.c
+++ b/tests/unit/test-write-threshold.c
@@ -7,117 +7,41 @@
*/
#include "qemu/osdep.h"
-#include "qapi/error.h"
#include "block/block_int.h"
#include "block/write-threshold.h"
-static void test_threshold_not_set_on_init(void)
-{
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- g_assert(!bdrv_write_threshold_is_set(&bs));
-
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, 0);
-}
-
-static void test_threshold_set_get(void)
-{
- uint64_t threshold = 4 * 1024 * 1024;
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- bdrv_write_threshold_set(&bs, threshold);
-
- g_assert(bdrv_write_threshold_is_set(&bs));
-
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, threshold);
-}
-
-static void test_threshold_multi_set_get(void)
-{
- uint64_t threshold1 = 4 * 1024 * 1024;
- uint64_t threshold2 = 15 * 1024 * 1024;
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- bdrv_write_threshold_set(&bs, threshold1);
- bdrv_write_threshold_set(&bs, threshold2);
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, threshold2);
-}
-
static void test_threshold_not_trigger(void)
{
- uint64_t amount = 0;
uint64_t threshold = 4 * 1024 * 1024;
BlockDriverState bs;
- BdrvTrackedRequest req;
memset(&bs, 0, sizeof(bs));
- memset(&req, 0, sizeof(req));
- req.offset = 1024;
- req.bytes = 1024;
-
- bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold);
- amount = bdrv_write_threshold_exceeded(&bs, &req);
- g_assert_cmpuint(amount, ==, 0);
+ bdrv_write_threshold_check_write(&bs, 1024, 1024);
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, threshold);
}
static void test_threshold_trigger(void)
{
- uint64_t amount = 0;
uint64_t threshold = 4 * 1024 * 1024;
BlockDriverState bs;
- BdrvTrackedRequest req;
memset(&bs, 0, sizeof(bs));
- memset(&req, 0, sizeof(req));
- req.offset = (4 * 1024 * 1024) - 1024;
- req.bytes = 2 * 1024;
-
- bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold);
- amount = bdrv_write_threshold_exceeded(&bs, &req);
- g_assert_cmpuint(amount, >=, 1024);
+ bdrv_write_threshold_check_write(&bs, threshold - 1024, 2 * 1024);
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0);
}
-typedef struct TestStruct {
- const char *name;
- void (*func)(void);
-} TestStruct;
-
int main(int argc, char **argv)
{
- size_t i;
- TestStruct tests[] = {
- { "/write-threshold/not-set-on-init",
- test_threshold_not_set_on_init },
- { "/write-threshold/set-get",
- test_threshold_set_get },
- { "/write-threshold/multi-set-get",
- test_threshold_multi_set_get },
- { "/write-threshold/not-trigger",
- test_threshold_not_trigger },
- { "/write-threshold/trigger",
- test_threshold_trigger },
- { NULL, NULL }
- };
-
g_test_init(&argc, &argv, NULL);
- for (i = 0; tests[i].name != NULL; i++) {
- g_test_add_func(tests[i].name, tests[i].func);
- }
+ g_test_add_func("/write-threshold/not-trigger", test_threshold_not_trigger);
+ g_test_add_func("/write-threshold/trigger", test_threshold_trigger);
+
return g_test_run();
}
diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
index 1170f375a5..9efdbd8ffd 100644
--- a/tools/virtiofsd/fuse_virtio.c
+++ b/tools/virtiofsd/fuse_virtio.c
@@ -1024,9 +1024,9 @@ static int fv_create_listen_socket(struct fuse_session *se)
if (se->vu_socket_group) {
struct group *g = getgrnam(se->vu_socket_group);
if (g) {
- if (!chown(se->vu_socket_path, -1, g->gr_gid)) {
+ if (chown(se->vu_socket_path, -1, g->gr_gid) == -1) {
fuse_log(FUSE_LOG_WARNING,
- "vhost socket failed to set group to %s (%d)\n",
+ "vhost socket failed to set group to %s (%d): %m\n",
se->vu_socket_group, g->gr_gid);
}
}
diff --git a/util/compatfd.c b/util/compatfd.c
index 174f394533..a8ec525c6c 100644
--- a/util/compatfd.c
+++ b/util/compatfd.c
@@ -72,14 +72,10 @@ static int qemu_signalfd_compat(const sigset_t *mask)
QemuThread thread;
int fds[2];
- info = malloc(sizeof(*info));
- if (info == NULL) {
- errno = ENOMEM;
- return -1;
- }
+ info = g_malloc(sizeof(*info));
if (pipe(fds) == -1) {
- free(info);
+ g_free(info);
return -1;
}
diff --git a/util/cutils.c b/util/cutils.c
index ee908486da..c9b91e7535 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -1055,5 +1055,5 @@ char *get_relocated_path(const char *dir)
assert(G_IS_DIR_SEPARATOR(dir[-1]));
g_string_append(result, dir - 1);
}
- return result->str;
+ return g_string_free(result, false);
}
diff --git a/util/main-loop.c b/util/main-loop.c
index 5188ff6540..d9c55df6f5 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -591,64 +591,3 @@ void event_notifier_set_handler(EventNotifier *e,
aio_set_event_notifier(iohandler_ctx, e, false,
handler, NULL);
}
-
-/* reaping of zombies. right now we're not passing the status to
- anyone, but it would be possible to add a callback. */
-#ifndef _WIN32
-typedef struct ChildProcessRecord {
- int pid;
- QLIST_ENTRY(ChildProcessRecord) next;
-} ChildProcessRecord;
-
-static QLIST_HEAD(, ChildProcessRecord) child_watches =
- QLIST_HEAD_INITIALIZER(child_watches);
-
-static QEMUBH *sigchld_bh;
-
-static void sigchld_handler(int signal)
-{
- qemu_bh_schedule(sigchld_bh);
-}
-
-static void sigchld_bh_handler(void *opaque)
-{
- ChildProcessRecord *rec, *next;
-
- QLIST_FOREACH_SAFE(rec, &child_watches, next, next) {
- if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) {
- QLIST_REMOVE(rec, next);
- g_free(rec);
- }
- }
-}
-
-static void qemu_init_child_watch(void)
-{
- struct sigaction act;
- sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL);
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- sigaction(SIGCHLD, &act, NULL);
-}
-
-int qemu_add_child_watch(pid_t pid)
-{
- ChildProcessRecord *rec;
-
- if (!sigchld_bh) {
- qemu_init_child_watch();
- }
-
- QLIST_FOREACH(rec, &child_watches, next) {
- if (rec->pid == pid) {
- return 1;
- }
- }
- rec = g_malloc0(sizeof(ChildProcessRecord));
- rec->pid = pid;
- QLIST_INSERT_HEAD(&child_watches, rec, next);
- return 0;
-}
-#endif
diff --git a/util/module.c b/util/module.c
index 7661d0f623..eee8ff2de1 100644
--- a/util/module.c
+++ b/util/module.c
@@ -182,6 +182,10 @@ static const struct {
{ "ui-spice-app", "ui-spice-core" },
{ "ui-spice-app", "chardev-spice" },
+ { "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" },
+ { "hw-display-virtio-gpu-pci-gl", "hw-display-virtio-gpu-pci" },
+ { "hw-display-virtio-vga-gl", "hw-display-virtio-vga" },
+
#ifdef CONFIG_OPENGL
{ "ui-egl-headless", "ui-opengl" },
{ "ui-gtk", "ui-opengl" },
@@ -301,13 +305,16 @@ static struct {
{ "qxl-vga", "hw-", "display-qxl" },
{ "qxl", "hw-", "display-qxl" },
{ "virtio-gpu-device", "hw-", "display-virtio-gpu" },
+ { "virtio-gpu-gl-device", "hw-", "display-virtio-gpu-gl" },
{ "vhost-user-gpu", "hw-", "display-virtio-gpu" },
{ "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" },
{ "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" },
+ { "virtio-gpu-gl-pci", "hw-", "display-virtio-gpu-pci-gl" },
{ "vhost-user-gpu-pci", "hw-", "display-virtio-gpu-pci" },
{ "virtio-gpu-ccw", "hw-", "s390x-virtio-gpu-ccw" },
{ "virtio-vga-base", "hw-", "display-virtio-vga" },
{ "virtio-vga", "hw-", "display-virtio-vga" },
+ { "virtio-vga-gl", "hw-", "display-virtio-vga-gl" },
{ "vhost-user-vga", "hw-", "display-virtio-vga" },
{ "chardev-braille", "chardev-", "baum" },
{ "chardev-spicevmc", "chardev-", "spice" },
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 9678d5b682..4944015a25 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1056,7 +1056,8 @@ bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
while (entry != NULL) {
next = qdict_next(qdict, entry);
- if (find_desc_by_name(opts->list->desc, entry->key)) {
+ if (opts_accepts_any(opts->list) ||
+ find_desc_by_name(opts->list->desc, entry->key)) {
if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
return false;
}
diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c
index 97dfa3fd57..911115b86e 100644
--- a/util/vfio-helpers.c
+++ b/util/vfio-helpers.c
@@ -459,51 +459,38 @@ fail_container:
return ret;
}
-static void qemu_vfio_ram_block_added(RAMBlockNotifier *n,
- void *host, size_t size)
+static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, void *host,
+ size_t size, size_t max_size)
{
QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier);
- trace_qemu_vfio_ram_block_added(s, host, size);
- qemu_vfio_dma_map(s, host, size, false, NULL);
+ int ret;
+
+ trace_qemu_vfio_ram_block_added(s, host, max_size);
+ ret = qemu_vfio_dma_map(s, host, max_size, false, NULL);
+ if (ret) {
+ error_report("qemu_vfio_dma_map(%p, %zu) failed: %s", host, max_size,
+ strerror(-ret));
+ }
}
-static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n,
- void *host, size_t size)
+static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, void *host,
+ size_t size, size_t max_size)
{
QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier);
if (host) {
- trace_qemu_vfio_ram_block_removed(s, host, size);
+ trace_qemu_vfio_ram_block_removed(s, host, max_size);
qemu_vfio_dma_unmap(s, host);
}
}
-static int qemu_vfio_init_ramblock(RAMBlock *rb, void *opaque)
-{
- void *host_addr = qemu_ram_get_host_addr(rb);
- ram_addr_t length = qemu_ram_get_used_length(rb);
- int ret;
- QEMUVFIOState *s = opaque;
-
- if (!host_addr) {
- return 0;
- }
- ret = qemu_vfio_dma_map(s, host_addr, length, false, NULL);
- if (ret) {
- fprintf(stderr, "qemu_vfio_init_ramblock: failed %p %" PRId64 "\n",
- host_addr, (uint64_t)length);
- }
- return 0;
-}
-
static void qemu_vfio_open_common(QEMUVFIOState *s)
{
qemu_mutex_init(&s->lock);
s->ram_notifier.ram_block_added = qemu_vfio_ram_block_added;
s->ram_notifier.ram_block_removed = qemu_vfio_ram_block_removed;
- ram_block_notifier_add(&s->ram_notifier);
s->low_water_mark = QEMU_VFIO_IOVA_MIN;
s->high_water_mark = QEMU_VFIO_IOVA_MAX;
- qemu_ram_foreach_block(qemu_vfio_init_ramblock, s);
+ ram_block_notifier_add(&s->ram_notifier);
}
/**